PmWiki»Custom Markup

Custom Markup

administrators (intermediate)

Introduction

PmWiki's markup translation engine is handled by a set of rules; each rule searches for a specific pattern in the markup text and replaces it with some replacement text. Internally, this is accomplished by using PHP's "preg_replace" function.

Rules are added to the translation engine via PmWiki's Markup() function, which looks like

Markup($name, $when, $pattern, $replace);

where $name is a unique name (a string) given to the rule, $when says when the rule should be applied relative to other rules, $pattern is the pattern to be searched for in the markup text, and $replace is what the pattern should be replaced with.

For example, here's the code that creates the rule for ''emphasized text'' (in scripts/stdmarkup.php):

Markup("em", "inline", "/''(.*?)''/", "<em>$1</em>");

Basically this statement says to create a rule called "em" to be performed with the other "inline" markups, and the rule replaces any text inside two pairs of single quotes with the same text ($1) surrounded by <em> and </em>.

The first two parameters to Markup() are used to specify the sequence in which rules should be applied. The first parameter provides a name for a rule -- "em" in the example above. We could've chosen other names such as "''", or even "twosinglequotes". In general PmWiki uses the markup itself to name the rule (i.e., PmWiki uses "''" instead of "em"), but to keep this example easier to read later on we'll use a mnemonic name for now.

The second parameter says that this rule is to be done along with the other "inline" markups. PmWiki divides the translation process into a number of phases:

_begin      start of translation
fulltext    translations to be performed on the full text            
split       conversion of the full markup text into lines to be processed
directives  directive processing
inline      inline markups
links       conversion of [[links]], url-links, and WikiWords     
block       block markups
style       style handling       
_end        end of translation

Thus, specifying "inline" for the second parameter says that this rule should be applied when the other "inline" rules are being performed. If we want a rule to be performed with the directives -- i.e., before inline rules are processed, we would specify "directives" for the second parameter.

The third parameter is a Perl-compatible regular expression. Basically, it is a slash, a regular expression, another slash, and (optionally) a set of options ("modifiers").

The example uses the pattern string "/''(.*?)''/", which uses ''(.*)'' as the regular expression and no options. (The regular expression says "find two single quotes in succession, then as few arbitrary characters as are needed to make the match find something, then two additional single quotes in succession"; the parentheses "capture" a part of the wikitext for later use.)

The fourth parameter is the replacement text that should be inserted instead of the marked-up wikitext. You can use $1, $2, etc. to insert the text from the first, second etc. parenthesised part of the regular expression.

In the example, we have "<em>$1</em>", which is an <em>, the text matched by the first parentheses (i.e. by the .*? section of the pattern), and </em>.

Examples

Here's a rule for @@monospaced@@ text:

Markup("@@", "inline", "/@@(.*?)@@/", "<code>$1</code>");

and for a [:comment ...:] directive that is simply removed from the output:

Markup("comment", "directives", "/\\(:comment .*?:\\)/", '');

Okay, now how about the rule for '''strong emphasis'''? We have to be a bit careful here, because although this translation should be performed along with other inline markup, we also have to make sure that the rule for ''' is handled before the rule for '', because ''' also contains ''. The second parameter to Markup() can be used to specify the new rule's relationship to any other rule:

Markup("strong", "<em", "/'''(.*?)'''/", "<strong>$1</strong>");

This creates a rule called "strong", and the second parameter "<em" says to be sure that this rule is processed before the "em" rule we defined above. If we wanted to do something after the "em" rule, we would use ">em" instead. Thus, it's possible to add rules at any point in PmWiki's markup translation process in an extensible manner. (In fact, the "inline", "block", "directives", etc., phases above are just placeholder rules used to provide an overall sequence for other rules. Thus one can use "<inline" to specify rules that should be handled before any other inline rules.)

If you want to disable available markup just call e.g.:

Markup("strong", "<em");

The lack of a pattern & replacement parameters indicates that you simply wish to disable the markup.

PmWiki's default markup rules are defined in the scripts/stdmarkup.php file. To see the entire translation table as the program is running, the scripts/diag.php module adds "?action=ruleset", which displays the set of defined markup rules in the sequence in which they will be processed. You can see it at CustomMarkup?action=ruleset.

More examples

Call a user function which returns some content

An 'e' option on the $pattern parameter will make PmWiki interpret the $replace parameter not as a replacement text, but as a PHP expression that returns the replacement text.

The markup (:meeting:) uses this by calling a hypothetical global function meeting() (say, defined in config.php), which is supposed to return the date of the next BLUG Meeting as a string:

Markup('meeting', 'directives', '/\\(:meeting:\\)/e', 'meeting()');

Note also, that the 'e' option is a standard preg_replace() option - and it still allows for 'references substitution' (that is, the parentheses in the $pattern are caught and inserted where $1, $2... etc. are). That might help you also in solving the excercise left below ;)

Simple macro replacement:

Markup('bigP', 'fulltext', '/\{bigP\}/',
  '%font-size="40px"% P' .
  '%block font-size="15px" border="0px" ' .
  'padding="4px 14px 7px 14px" bgcolor=#FFB% ');

This uses the fulltext phase to simply replace the {bigP} sequence with a bunch of random markup, so that

 {bigP}ie Jesu Domine, dona eis requiem (''whack'').

produces this effect:

P ie Jesu Domine, dona eis requiem (whack).

Adding an argument (as in {big P}, here) to a macro is left as an exercise for the reader.

Add Google Search to your wiki

German Example, Same Window

Put this text at the bottom of your config.php file

Markup('googlesearch', 'directives', '/\\(:googlesearch:\\)/e',"Keep(\"
<FORM method=GET action='http://www.google.de/search'>
<TABLE><tr><td>
<A HREF='http://www.google.de'>
<IMG SRC='http://www.google.de/logos/Logo_40wht.gif' border='0'
ALT='Google' align='absmiddle'></A>
<INPUT TYPE=text name=q size=20 maxlength=255 value=''>
<INPUT TYPE=hidden name=hl value=de>
<INPUT type=submit name=btnG VALUE='Google Search'>
</td></tr></TABLE>
</FORM>
\")");

Put (:googlesearch:) anywhere on your Page. --newmy

Add Google Safe Search in a New Window to your wiki

English Example, Safe Search in a New Window

Put this text at the bottom of your config.php file

Markup('googlesearch', 'directives', '/\\(:googlesearch:\\)/e',"Keep(\"
<FORM method=GET action='http://www.google.com/search' target='_blank'>
<TABLE><tr><td>
Google Safe Search
<A HREF='http://www.google.com/search?safe=vss'></A>
<INPUT TYPE=text name=q size=42 maxlength=255 value=''>
<INPUT type=hidden name=safe value=strict>
<INPUT type=submit name=sa value='Google Search'>
</td></tr></TABLE>
</FORM>
\")");

Now you can put (:googlesearch:) anywhere on your Page. --Jeff, Corpus Christi, Texas

Add Local Weather to your site

Put this text at the bottom of your config.php file

Markup('localweather', 'directives', '/\\(:localweather:\\)/e',"Keep(\"
<script src='http://voap.weather.com/weather/oap/78410?template=GENXV&par=null&unit=0&key=021c5b063db71b7fdd9a11f5ec88c033'></script>
\")");

Now you can put (:localweather:) anywhere on your Page. --Jeff, Corpus Christi, Texas

Note: You will need to go to http://www.weather.com to get the script line to replace the script line above.

Just place your script between:
Markup('localweather', 'directives', '/\\(:localweather:\\)/e',"Keep(\"

and

\")");

<< Custom InterMap | DocumentationIndex | Custom WikiStyles >>