Summary: Talk page for PowerTools.
Maintainer: HansB
Users: +7 (View / Edit)

This space is for User-contributed commentary and notes. Please include your name and a date along with your comment.

PHP 8 - Error log entry

PHP Deprecated:  Required parameter $args follows optional parameter $trailname in /var/www/lighttpd/projects/cookbook/powertools.php on line 258

The optional argument needs to be moved to the end of the argument list. I moved the optional argument to the end of the argument list. $argp was the last argument before the modification.

$MarkupExpr['rndpage'] = 'MXRandomPageLink($pagename, $args[0], $argp, $args[1])';
function MXRandomPageLink($pagename, $label, $args, $trailname='') {

DannyB January 6, 2022, at 11:25 AM

Uploaded powertools_2021-11-12.phpΔ, which incorporates the suggested $PowerToolsNewTicketSuffix feature described below, as well as ChuckG’s 2017-12-21 fix. —Said Achmiz November 13, 2021, at 03:12 AM


I wanted the suffix for new tickets to be something other than 001 (perhaps 0001, etc.), so this is what I did:

1. Add this just before the MakeNewTicket function:


2. Add at the very start of MakeNewTicket this line:

 global $PowerToolsNewTicketSuffix;

3. Change the next-to-last line of the MakeNewTicket function like so:

 else $target = $grp.".".$today.$PowerToolsNewTicketSuffix;

Then $PowerToolsNewTicketSuffix can be set in config.php, e.g.:

 $PowerToolsNewTicketSuffix = '00001';

Said Achmiz December 04, 2017, at 01:36 PM

You would also need to change code line 346 to reflect the number of digits:

   $issue = max(@$issue,substr($p,-11));

for a five digit suffix to the day number change to

   $issue = max(@$issue,substr($p,-13));

i.e. the page names consists now of numbers with 13 digits (8 for the day-number plus 5 for the suffix). Because of such complications I will not change the recipe to incorporate a 'suffix' global variable. - HansB December 04, 2017, at 05:53 PM

Indeed, there are additional additional modifications, but they are fairly straightforward—here is the full modified function:

# add markup expression {(newticket Group)}
# creates auto increasing pagename of format  
# Group.20061220001 (date and 3 digit number)
SDV($PowerToolsNewTicketSuffix, '001');
$MarkupExpr['newticket'] = 'MakeNewTicket($pagename, $args[0])';
function MakeNewTicket($pagename, $grp) {
	global $PowerToolsNewTicketSuffix;
	$ticket_id_length = 8 + strlen($PowerToolsNewTicketSuffix);
	if (!$grp) $grp = PageVar($pagename, '$Group');
	foreach(ListPages("/^$grp\\.\\d{{$ticket_id_length}}\$/") as $p) 
		$issue = max(@$issue,substr($p,-1 * $ticket_id_length)); 
	$issueday = substr($issue,0,8);
	$today = strftime("%Y%m%d", time());
	if($issueday == $today) {
	   $nextissue = $issue + 1;
	   $target = $grp.".".$nextissue;
	else $target = $grp.".".$today.$PowerToolsNewTicketSuffix;
	return $target;    

So, we calculate the number of digits based on the length of the suffix, as you can see.

I have also modified the regex that filters page names a bit, to compensate for a bug I stumbled on, that breaks the incrementing if there exist pages with a name like 20061220001-Talk (if e.g. you have implemented Talk pages, as I have done); the modification eliminates that bug.

I have tested this code and it works as advertised. :)

Said Achmiz December 04, 2017, at 07:53 PM

That function does look good, thanks! I would put the line

  SDV($PowerToolsNewTicketSuffix, '001');

inside the function though, there is no need to define the suffix if the functionis not called. One other thing may be good too, which is to make sure any $PowerToolsNewTicketSuffix set is an integer, not just any string. - HansB December 05, 2017, at 03:18 AM

Ah, good points! In that case perhaps like this:

$MarkupExpr['newticket'] = 'MakeNewTicket($pagename, $args[0])';
function MakeNewTicket($pagename, $grp) {
	global $PowerToolsNewTicketSuffix;
	SDV($PowerToolsNewTicketSuffix, '001');
	$PowerToolsNewTicketSuffix = is_numeric($PowerToolsNewTicketSuffix) ? $PowerToolsNewTicketSuffix : '001';

	$ticket_id_length = 8 + strlen($PowerToolsNewTicketSuffix);

and the rest as before? —Said Achmiz December 06, 2017, at 10:37 AM

Although the docs for pagelist say Any PageList directive parameters are allowed, quotation marks surrounding included and excluded text are not working for me. This would allow the searching for words with spaces in them, or arbitrary sections of text containing punctuation.

For example, I can use standard pmwiki pagelist markup so:

(:pagelist "TODO:":) or (:pagelist TODO::) and obtain results


{(pagelist TODO:)} or {(pagelist "TODO:")} or {(pagelist 'TODO:')} or even {(pagelist "'TODO:'")} (single-quotes-in-double-quotes, as suggested below) are return no results.

Is there a parameter name or markup trick that I am missing?

I was hoping to pipe the output to TextExtract, but that only takes input from {(pagelist)} and not (:pagelist:), it seems.

I am using (:pagelist "TODO:" fmt=extract unit=line phead=link order=-time:) right now, which provides roughly what I was looking for, but I'm curious as to why I was failing with the {(pagelist)} markup.

MichaelPaulukonis July 08, 2014, at 10:55 AM

Please leave latest comment/request at the top

pagelist doesn't find records when PTV value used in selection has a space

AllanGN 2012-06-07: Using a PTV as part of the pagelist selection, it seems to fail when the PTV value has a space.

Some background: I'm using Pmwiki to manage my "todos" using pages I'm calling Notes, and I assign PTVs to each one including "notestatus" (which has values like "Open", "Completed", "In progress") and "notehoursleft" (hours of work left for a particular Note). I'm trying to use PowerTools' sumdata and pagelist to selectively add up "notehoursleft".

Anyway, here are some of my test findings, below.

(p.s. Thanks for all this. I've just recently started using Fox (I love FoxEdit!) and now trying these PowerTools. Fantastic stuff.)

These work:

  • Hard-coded "Open":

{(pagelist group=Notes name=Note-* $:notestatus="Open")}

  • Hard-coded: "Open,Cancelled":

{(pagelist group=Notes name=Note-* $:notestatus="Open,Cancelled" )}

  • Using a temporary PTV:


testnotestatus = {$:testnotestatus}

{(pagelist group=Notes name=Note-* $:notestatus="{$:testnotestatus}" )}

These fail:

  • Hard-coded: "In progress". (I think it doesn't work because there's a space?) Update: Verified. I took out spaces and now my stuff works.

{(pagelist group=Notes name=Note-* $:notestatus="In progress" )}

  • Using a temporary PTV, one of the values has a space:

(:testnotestatus2:Open,In progress:)

testnotestatus2 = {$:testnotestatus2}

{(pagelist group=Notes name=Note-* $:notestatus="{$:testnotestatus2}" )}


These work:

    Hard-coded "Open": 


    Hard-coded: "Open,Cancelled": 


    Using a temporary PTV: 

testnotestatus = Open,Cancelled


These fail:

    Hard-coded: "In progress". (I think it doesn't work because there's a space?)
    Using a temporary PTV, one of the values has a space: 

testnotestatus2 = Open,In progress 

Thanks, confirmed as a bug, and I don't know a solution at present. If you use the pagelist markup expression solo, i.e. similar to a directive, and not nested in other markup expressions or directives, you could avoid the problem by using the (:pagelist ... :) directive, with your parameters, plus the additional parameter fmt=csv, which you got defined by including powertools.php. I.e. like (:pagelist group=Notes name=Note-* $:notestatus="In progress" fmt=csv:) HansB June 08, 2012, at 11:27 AM

PS:Just discovered you can use values with spaces by adding another pair of quotes (single quotes in double quotes), like {(pagelist group=Notes name=Note-* $:notestatus="'In progress'" )}

I went with your "single quotes in double quotes" tip; that did the trick. I used FoxTextReplace to change back my note status types to having spaces in the middle. All working! Thanks! AllanGN, 2012-06-12 (p.s. FoxTextReplace = wow)

(serial) issue when appending digits

DannyB 2012-02-23: I use the 2 digit year number as a prefix for the serial command. At the beginning of every year when the prefix changes the serial command does not produce the correct "next" number because the code looks for digits. I modified the code as follows and the role-over now works because my year digits don't get "eaten up" by the regular expression. I also tried a second approach using substr (the other commented out line) to just skip the leading stuff producing a variable rather than an array and it worked too. If you feel that this general approach fixes the problem without breaking something else, could you produce an update for the serial and serialname commands so I don't have to worry about patching the code?

  foreach(ListPages("/^$grp.$name\\d/") as $p) {
      preg_match("/^$grp.$name(\\d+)$/",$p, $m);
      #preg_match("/.*[^\\d](\\d+)$/",$p, $m);
      #$m = substr($p,strlen($grp)+1+strlen($name));

Thanks for your consideration.

(trail) question

Is it possible for the "label" to return the title or name of the page the prev/next link is going to?
Sovvie December 14, 2011, at 08:12 AM


I'm assuming that installation of PowerTools is the same as for other recipes: "place powertools.php in your cookbook folder and add include_once('cookbook/powertools.php'); to your local/config.php" although this instruction is not included on the recipe description page. R D Jones August 25, 2011, at 08:12 AM

(serialname) issue

DannyB 2011-03-08: I just want to create a serial pagename starting with the current 2 digit year on the front. Why won't this work?

(:Year: {(ftime fmt=%y)}:)
[[{(serialname Projects "{$:Year}")}?action=edit|New Project]]

It gives me the pagename "SerialnameProjects11". Does it just not process the "serialname" function? I'm ready to write my own "serialyear" function, but really want this to work.

HansB: Instead of using a markup expression as value for a page text variable, and using the PTV inside a markup expression, use the time markup expression directly inside the serialname expression:
[[{(serialname Projects (ftime fmt=%y) )}?action=edit|New Project]]

Mark Bacas - 20100301 - I'm trying to make use of "newticket" for creating new forms. I would like to be brought to the "Form" and not the "Edit" page where I have to click "Save" to get to the form. Is there something special I have to do to skip the "Edit" page? I believe all of my form stuff is setup properly (but maybe I'm missing something there).

HansB: sounds like a form, not a 'newticket' issue. I would need to see how your form is set up. Can this be discussed on PmWiki's user mail list, or on a Talk page of the form processing recipe you use?

(pagelist) issue and proposed fix

SteP 2010-12-04: I noticed some cases where (pagelist) produces different results than the regular (:pagelist:) markup. I couldn't get some nested markup expressions to work correctly inside (pagelist). Then I found a fix, by replacing one line in powertools.php, from:

   $MarkupExpr['pagelist'] = 'MxPageList($pagename, $params)';


   $MarkupExpr['pagelist'] = 'MxPageList($pagename, preg_replace($rpat, $rrep, $params))';

As scripts/markupexpr.php explains, when $params is used ParseArgs() returns possibly escaped values, which can be unescaped before passing them to FmtPageList(). This fix works for me. If more people can test it and find it OK, it could be rolled into the next revision.

I expected the following 2 pagelists to be identical except for the different default fmt=X:

(:pagelist group=Test "[[#answer-1-2]]":)

{(pagelist group=Test "[[#answer-1-2]]")}

No results found.

(pagelist group=Test )

Instead it appears that powertools's pagelist doesn't find any pages matching that pattern while the (:pagelist...:) does find the test pages I created... —Peter Bowers August 14, 2010, at 03:31 AM

To use PowerTools' wordcount in pagelist as order param, use this code (from Antony) :


function CountWordCompare($x, $y) {

    # get word count of the page
    $xval = WordCount( $x );
    $yval = WordCount( $y );

    # compare integer values
    if($xval > $yval) $c = 1;
    elseif($xval < $yval) $c = -1;
    else $c = 0;
    return $c;
$PageListSortCmp['countword'] = 'CountWordCompare($x, $y)';

and in your wikipage use:
(:pagelist group=MyGroup order=countword:)
or (:pagelist group=MyGroup order=-countword:)

Talk page for the PowerTools recipe (users).