Introduction
Most weblog software shows in their respective sidebar/navbar a list of the recent posts. I wanted to have the same feature in PmWiki as I intend to us this platform to speak out. I had the gutt feeling that there was something in PmWiki that would let me do that but wasn't sure how (I knew it would be pagelist). So I decided to create a custom markup to handle this task. Tutorial in the form of story telling.
mostRecentUpdates
PmWiki keeps track of site wide updates in the document Site.AllRecentChanges and of group specific updates (only the documents belonging to a given group) in the document GroupName.RecentChanges.
The first things we have to do is to look into those documents (for the purpose of this story we'll only consider the site wide case).
file format
PmWiki is a flat file based wiki engine (could change or offer alternatives in the future but ... that's the way it is today 20060211). The Site.AllRecentChanges documents looks like this (all documents do by the way):
agent=Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1
host=84.101.247.196
name=Site.AllRecentChanges
rev=133
text=* [[Tutorial.MostRecentUpdates]] . . . February 11, 2006, at 10:45 PM by [[~EuGeNe]]: %0a* [[Site.SideBar]] . . . February 11, 2006, at 10:08 PM by ?: %0a* [[Main.HomePage]] . . . February 11, 2006, at 09:38 PM by ?: %0a* [[Tutorial.PumpItUp]] . . . February 09, 2006, at 09:49 PM by ?: %0a* [[Articles.MyArtix]] . . . February 08, 2006, at 09:15 PM by ?: %0a* [[Setup.PmWiki]] . . . February 06, 2006, at 12:24 PM by ?: %0a* [[Setup.Python]] . . . February 05, 2006, at 10:39 PM by ?: %0a* [[Setup.Server]] . . . February 05, 2006, at 09:27 PM by ?: %0a* [[Site.EditForm]] . . . February 05, 2006, at 09:01 PM by ?: %0a* [[Main.FormationMassage]] . . . February 02, 2006, at 07:13 PM by ?: %0a
time=113969433
Each line begins with a tag describing the information it contains. The one we care about is text=, it contains the history of all the changes made to a PmWiki based site.
If you are a tiny bit familiar with the platform (would you be reading that if you were not) you know that all the documents are listed in reverse chronological order and that the double brackets are links .
Function
What we have to do is parse the text= line and extract all the information between double brackets to recover the list of all the pages that have been created or modified. Regular expressions come very handy.
As was mentioned above we want to be able to show only group specific changes as well as site wide changes. It also seems relevant to limit the number of entry displayed.
The function mostRecentUpdates takes two arguments, a group name (default to Site) and a number of documents to show (count default to 5).
global $WorkDir;
if ($Group!="Site"){
$Page="RecentChanges";
} else {
$Page="AllRecentChanges";
}
$path="$WorkDir/$Group.$Page";
$file=file($path,"r");
foreach($file as $line) {
$pos=strpos($line,"text=");
if ($pos===false or $pos>0) {
continue;
}
$text=$line;
}
preg_match_all("/\* \[\[([^\]]*)\]\]/",$text,$pages);
$i=0;
$return="";
foreach($pages[1] as $page){
$return.= "[[$page]]<br/>";
$i++;
if ($i>=$count) break;
}
return $return;
}
$WorkDir is a PmWiki variable wich containes the path to the directory where the documents are saved.
Site wide changes are stored in AllRecentChanges while group specific changes are stored in a page called RecentChanges.
Given these info we know which file to look into. In the file we search for the line starting with text=, and extract all the information between double brackets (modified pages) preceded by a * (otherwise by links to the profile of the author show in the list).
We then generate a string to be displayed that contains only the first count entries.
Markup
PmWiki makes it easy (when you know regexp) to define new markups (cf. CustomMarkup).
We create a markup called mru. Explaining the regexp game is beyond the scope of this story/tutorial (and my skills).
'mru',
'directives',
'/\\(:mru(\\s+.*?)?:\\)/ei',
"mru('$1')"
);
I wanted to have something a tiny bit flexible so I want the arguments to the mru markup to be group=GroupName count=count. For some reason in order to do that the single quotes around the $1 are important (I don't know why) in the callback function. The callback function mru() will parse the arguments and call the mighty mostRecentUpdates function.
ParsArgs
PmWiki has a function to parse markup arguments, it is called ParsArgs. It does a lot more than what we use it for: parsing a string of key=value into an array. You'll not that we do not do any validity test ... misused it will fail miserabily and more than likely silently.
$args=ParseArgs($args);
$group=$args['group'];
$count=$args['count'];
return mostRecentUpdates($group,$count);
}
The code
Put together MRU.php looks like that:
Markup(
'mru',
'directives',
'/\\(:mru(\\s+.*?)?:\\)/ei',
"mru('$1')"
);
function mru($args){
$args=ParseArgs($args);
$group=$args['group'];
$count=$args['count'];
return mostRecentUpdates($group,$count);
}
function mostRecentUpdates($Group="Site",$count=5) {
global $WorkDir;
if ($Group!="Site"){
$Page="RecentChanges";
} else {
$Page="AllRecentChanges";
}
$path="$WorkDir/$Group.$Page";
$file=file($path,"r");
foreach($file as $line) {
$pos=strpos($line,"text=");
if ($pos===false or $pos>0) {
continue;
}
$text=$line;
}
preg_match_all("/\[\[([^\]]*)\]\]/",$text,$pages);
$i=0;
$return="";
foreach($pages[0] as $page){
$return.= $page."<br/>";
$i++;
if ($i>=$count) break;
}
return $return;
}
?>
Using MRU.php
- Save MRU.php in your cookbook/ folder.
- In you local/config.php add include_once('cookbook/MRU.php');
Done! In any document type (:mru group=Site count=5:) and let the magic happen.
The pagelist alternative.
PmWiki comes with a lot of useful features and avoid most of the useless bells and whistles. I don't do pagelist justice by calling it the alternative. MRU clearly ease a low key low tech way of doing what PmWiki does in one line:
... BUT ... MRU uses the group argument differently and looks different as you can see bellow:
MRU
(:mru group=Site count=5:)
pagelist
Personaly I like the MRU output better for my sidebar ;) --Eugene
The pagelist solution
With version 2.1 of PmWiki pagelist has become very powerful (not that it was not before but ... more powerful). It is now possible to specify in which format pagelist should display the list of pages etc. etc. check it out on PageListExplained.
So I have created the #MRU format in Site.PageListTemplates and ...
Which basically states:
- no page in the Site group
- 5 pages only
- order by updated time (decreasing)
- list only normal pages i.e. not RecentChanges etc.
- use the #MRU format
PmWiki rules!


