Developers

Technical notes on the UpdatePage() function. It is updated as of 2.2.0 Beta65.

UpdatePage($editPageName, $old (page object), $new (page object));

UpdatePage() is a code hook allowing cookbook recipes to mimic the behavior of editing wiki pages via the browser. It accepts a page object (array) of page data then performs all the usual PmWiki housekeeping tasks that would be performed on text submitted by the edit form in a browser window i.e. it preserves history/diff information, updates page revision numbers, updates RecentChanges pages, sends email notifications, etc.

  • "Page object" refers to an array pulled from RetrieveAuthPage($somePageNameYouAreEditing, $level, $authprompt=true, $since=0); (preferred), or ReadPage($pagename); (disregards page security). Note that $new['text'] should contain all page data for the new version of the page. See PageFileFormat for more information on the type of information you may be able to access in the array.
  • If a page doesn't exist, UpdatePage() will attempt to create it.
  • If you retrieved $old using RetrieveAuthPage($editPageName,$auth,$prompt,READPAGE_CURRENT) and set $new=$old, then UpdatePage or WritePage will also erase all historical data (because READPAGE_CURRENT only reads and returns the current version of the page without any history; the same happens with ReadPage($pagename, READPAGE_CURRENT)).

Caution

If used incorrectly, UpdatePage() can not only blank pages, but can wipe entire histories of pages - PmWiki cannot recover an old version if you accidentally drop the page history when you read or save a page.

Calling UpdatePage()

UpdatePage() cannot be called directly from config.php or an include()d recipe because there are necessary initializations which occur later in pmwiki.php. To use UpdatePage(), do it within a custom markup, a custom markup expression, or a custom action.

UpdatePage() does very little itself other than traverse $EditFunctions and call each function contained there. ($EditFunctions can be overridden by the 4th argument $fnlist, but this is fairly rare).

The global $IsPagePosted is set to FALSE at the start of UpdatePage() and then returned at the end of this function. Any of the intervening functions can set it to TRUE (indicating successful posting/saving) but normally this is the job of the function PostPage().

Here is the definition of $EditFunctions from pmwiki.php:

$EditFunctions = array('EditTemplate', 'RestorePage', 'ReplaceOnSave',
  'SaveAttributes', 'PostPage', 'PostRecentChanges', 'AutoCreateTargets',
  'PreviewPage');

Recipes can change how edits work

Cookbook Authors can add their own functions to $EditFunctions as needed.

As an example, suppose you need to know the $pagename of the page being edited for some reason (Maybe you've added to $ROSPatterns):

  global $EditFunctions; # if inside a function
  array_unshift($EditFunctions, "GetEditPagename");
  // ...
  function GetEditPagename($pagename, $p, $n) {
    global $EditPagename;
    $EditPagename=$pagename;
  }

Or if you need to do processing after a page has been saved:

  $EditFunctions[]= "MyPostEditProcessing"; // Add to end of $EditFunctions
  function MyPostEditProcessing($pagename, $p, $n) {
    // mirror page to another site, send an email, update page lists somewhere, etc
    // Might check global $IsPagePosted
  }

Default $EditFunctions

EditTemplate

This function allows pre-populating new pages with the contents of a template page. If the $new['text'] contains anything then this function does nothing.

The pagename of the template can be passed in the $_REQUEST['template'].

Otherwise the $EditTemplatesFmt array is traversed and each page read until obtaining some text which then becomes the text of the $new['text'].

RestorePage

On a normal save of a page this function does nothing.

The value for $Restore can be passed by argument to the function, but it will not in the context of UpdatePage(). The value will be obtained instead from $_REQUEST['restore']. If this value is not set then this function will do nothing. If this value is set to a timestamp then the page history will be traversed and the various diff's in page history will be reverse applied until the requested timestamp.

ReplaceOnSave

There are 2 arrays: $ROEPatterns and $ROSPatterns. In each array the key to the hash is the search-pattern and the value to the hash is the replace-pattern. $ROEPatterns is replaced on each edit, $ROSPatterns only if $EnablePost is set.

SaveAttributes

Several different attributes are calculated to become one of the keys of the $new[] page array. (Each of these will then become their own line in the pagefile.) Targets are calculated as a space-separated list of pages which are linked to from this page. Properties held in the global $SaveProperties are copied from the $page[] (old page) array.

  • Note: SaveAttributes runs MarkupToHTML() on the page text. This sets page variables, but may have side effects (if you are keeping a count of your markup, writing to files every time a page is viewed, etc).

PostPage

$IsPagePosted is set to false.

If $EnablePost is true then these steps occur:

  • Attributes such as 'charset' ($Charset), 'author' ($Author), 'author:<timestamp>' ($Author), and 'host:<timestamp>' ($_SERVER['REMOTE_ADDR']) are set.
  • A diff is done between the previous text and the current text and the result stored as a '<timestamp>' key.
  • If the text matches the global $DeleteKeyPattern then the page is deleted.
  • WritePage() is called
  • $IsPagePosted is set to true.

PostRecentChanges

If $IsPagePosted is NOT true then do nothing.

The global array $RecentChangesFmt[] is traversed with the KEY to the hashed array being the pagename where the changes should be written to and the VALUE of the hashed array being the text to be written to the end of that page.

If the number of lines in the recentchanges page exceeds the global $RCLinesMax then the page is chopped appropriately.

The recentchanges page is written via WritePage().

AutoCreateTargets

If link targets within the page match some global and they do not exist then they will be automatically created. See also AutoCreatePages.

PreviewPage

This function does nothing if you're not doing a preview.

Other $EditFunctions

There are other $EditFunctions that come with PmWiki but that are not part of the basic functionality:

author.php

array_unshift($EditFunctions,'RequireAuthor'); // Makes sure an author is specified before allowing page to be edited

blocklist.php

array_unshift($EditFunctions, 'CheckBlocklist');

draft.php

array_unshift($EditFunctions, 'EditDraft'); // Check if saving to the draft file and if so, change names and Redirect to the draft page to continue edit.

  • Note: This may change $pagename unexpectedly

notify.php

$EditFunctions[] = 'PostNotify'; // Add 'PostNotify' to send an email after edit successfully done

pagelist.php

$EditFunctions[] = 'PostPageIndex'; // handle (:pagelist:) functionality after a page is updated

simuledit.php

array_unshift($EditFunctions,'MergeSimulEdits'); // If more than one edit happened since page load, merge the changes before saving

transition.php

Handles transitions between PmWiki versions. Used for GUI Edit buttons.

urlapprove.php

array_splice($EditFunctions, array_search('PostPage', $EditFunctions), 0, 'BlockUnapprovedPosts');

Puts the BlockUnapprovedPosts() function right before PostPage()


Notes

Can I call UpdatePage() directly from config.php?

No. As stated on the PmWiki/Functions: UpdatePage() cannot be called directly from config.php because there are necessary initializations which occur later in pmwiki.php. It is not enough to just load stdconfig.php. If you want to use UpdatePage() you will need to do it within a custom markup, a custom markup expression?, or a custom action.


Category: PmWiki Internals PmWiki Developer

This page may have a more recent version on pmwiki.org: PmWiki:UpdatePage, and a talk page: PmWiki:UpdatePage-Talk.