MarkupDirectiveFunctions

Summary: Simply configured custom directives
Version: pmwiki-2.3.32
Prerequisites: PmWiki 2.3.11 (PmWiki 2.3.21 for multi-line directives)
Status: Experimental
Maintainer: Petko
License: GPLv2+
Categories: MarkupWriting
Users: +1 (view / edit)

A simple way to configure custom markup directives.

Description

This page documents the use of a new helper function (as of PmWiki 2.3.11) that makes it easy to add custom markup directives in the format:

!! Simple directive
(:mydirective arg1=val1 arg2="val 2":)

!! Multiline directive with start, content, end
(:otherdirective arg1=val1 arg2="val 2":)
Content
(:otherdirectiveend:)

New PmWiki core helper functions will:

  • register the Markup() calls with the regular expressions for your directive
  • receive the matching texts from the wiki pages
  • extract the $pagename variable
  • parse the directive arguments, if any, and cast numeric values to floating point numbers,
  • call your function with the arguments $pagename, $directive, $args, $content (if any).

All the above is regularly done by authors of many individual recipes; the new helper functions should simplify this chore.

This format may also be more future-proof than direct Markup() calls, as it should be simpler for the PmWiki core to automatically adapt these to changes in future PHP versions.

On the other hand, these directives are processed quite early in the markup sequence, normally just after conditionals. If your function needs to be called at a specific point of the processing, or relative to other markup rules, you may need to use the standard Markup() calls.

Usage

In your recipe, instead of Markup() calls, just define your directive keyword, and the function that receives the parsed content:

$MarkupDirectiveFunctions['mydirective'] = 'FmtMyDirective';
$MarkupDirectiveFunctions['otherdirective'] = 'FmtMyDirective';
function FmtMyDirective($pagename, $directive, $args, $content = '') {
  // do your magic
  return  $out;
}

When markup directives are processed, your function will be called for every matching directive with the arguments:

  1. $pagename: the full name of the currently processed page.
  2. $directive: the directive keyword, as in "mydirective" (you may have different directives calling the same function).
  3. $args: an array with the parsed arguments within the start directive (see documentation for ParseArgs).
    • in the above example, $args['arg1'] will be 'val1', and $args['arg2'] will be 'val 2'.
  4. $content: the text between the start and end directives (in the case of a complex directive). Note that $content will be:
    • "" (empty string) with the single line directive,
    • in a multiline directive it will keep any leading and trailing line breaks and spaces; you can use trim($content) to remove these if needed.

Return values

If your function returns wiki code such as (:notitle:) or {*$FullName} that needs to be re-processed by the markup engine, use PRR():

  return PRR($out);

On your wiki, in Page?action=ruleset, the markup that should be wrapped in PRR() are the rules between "_begin" at the top and "anydir1" in the first column. If you output simple tables, wikistyles, and other inline markup you may not need to wrap it with PRR(). YMMV.

If your function returns HTML that should not be processed further, call Keep():

  return Keep($out);

If your HTML is a block-level element like a <div>, to prevent it from becoming wrapped in <p> tags which would be invalid HTML, call KeepBlock():

  return KeepBlock($out);
  ### before 2.3.19, please use this instead:
  # return '<:block>'. Keep($out);

User interaction

Say your markup needs to do something or display different information based on user interaction. Your markup can include for example pagination links or forms for users to input their choices. Your function can then check $_GET, $_POST, or $_REQUEST values.

Here is an example directive that shows the time in a selected timezone:

$MarkupDirectiveFunctions['timeinzone'] = 'FmtTimeInZone';
function FmtTimeInZone($pagename, $directive, $args) {
  global $InputValues;

  # Available choices, possible data
  $Zones = array('America/Chicago', 'Asia/Tokyo', 'Europe/Ljubljana', 'Pacific/Auckland', 'GMT');

  if (isset($_POST['tz']) && in_array($_POST['tz'], $Zones)) {
    # User has posted the form, and the value is acceptable
    $zone = $_POST['tz'];
  }
  elseif (isset($args['tz']) && in_array($args['tz'], $Zones)) {
    # The directive in the page has a tz= argument, and the value is acceptable
    $zone = $args['tz'];
  }
  else {
    # Use default value
    $zone = 'GMT';
  }

  # Selected value of the dropdown
  $InputValues['tz'] = $zone;

  # Output content based on the default or selected choices
  $time = "Time is {(ftime fmt=%R tz=$zone)} in $zone.";

  # Add a form to select a choice
  $form = "(:input form action={*\$PageUrl} method=post:)
Select timezone:
(:input select tz GMT:)
(:input select tz America/Chicago:)
(:input select tz Asia/Tokyo:)
(:input select tz Europe/Ljubljana:)
(:input select tz Pacific/Auckland:)
(:input submit value=Go:)
(:input end:)";
  # Alternatively, the form can be in Site.LocalTemplates
  # and can be included like this:
  $form = '(:include Site.LocalTemplates#timeinzoneform:)';

  # Output markup, PRR() to be reprocessed
  return PRR("$time\n\n$form");
}

And here is the above directive enabled:

(:timeinzone tz=America/Chicago:)

Time is 05:03 in America/Chicago.

Select timezone:

Notes

Search the documentation about the PmWiki helper functions ParseArgs(), PRR() and Keep().

  • The custom directive 'keyword' can only have letters, digits, minus and underscore characters, and unlike some other markup is case sensitive.
  • The end directive (if any) has simply an added "end", like XYZ...XYZend.
  • Do not use the same directive name for both simple (single line) and complex (multiline) directives.

Change log / Release notes

  • 2023-03-06 Bug-fix for multi-line directives (PmWiki 2.3.21).
  • 2022-08-28 Helper function and added to Subversion for PmWiki 2.3.11. See PmWiki.ChangeLog for changes.

See also

Cookbook /
Functions  Brief description of some of PmWiki's internal functions available to cookbook recipe authors and custom markup developers
ParseArgs  Description of ParseArgs function for parsing argument lists (Stable)
PmWiki /
CustomMarkup  Using the Markup() function for custom wiki syntax; migration to PHP 5.5
FunctionList  A simple list of the functions provided by PmWiki
Functions  How some of the functions in pmwiki.php work
Test /
ParseArgs  

Contributors

Written and maintained by Petko.

Comments

See discussion at MarkupDirectiveFunctions-Talk

User notes +1: If you use, used or reviewed this recipe, you can add your name. These statistics appear in the Cookbook listings and will help newcomers browsing through the wiki.