Mastering MediaWiki Parser Functions for Dynamic Content
Why parser functions matter for a lively wiki
Why parser functions matter for a lively wiki
When you first stare at a MediaWiki page that seems to “think” for itself –‑ a table that fills up with the current date, a navigation box that adapts to the page title, or a warning that only appears for logged‑in users –‑ you’ve probably witnessed parser functions in action. They are the invisible glue that lets wikitext behave more like a tiny programming language, all without leaving the comfort of the editor.
In my own tinkering with a community wiki, I often found myself wishing “this should change automatically”. The answer? A parser function, most often supplied by the ParserFunctions extension, but sometimes a custom hook written in PHP.
Getting the syntax right – a quick refresher
The basic shape of a parser function is:
{{#functionname: param1 | param2 | param3}}Notice the # before the function name; it tells MediaWiki to treat this as a hook rather than a normal template. You can also supply named parameters, like name=Value, which makes the call more readable.
Here’s an example that greets a user with a time‑dependent message:
{{#ifexpr: {{#time:Y}} >= 12 |
Good afternoon, {{FULLPAGENAME}}!
| Good morning, {{FULLPAGENAME}}! }}That little snippet shows three concepts at once: #ifexpr for conditional logic, #time for pulling the current hour, and FULLPAGENAME as a magic word.
Common built‑in functions you’ll reach for daily
- #if – simple true/false branching.
- #ifexist – checks if a page exists.
- #ifexpr – evaluates mathematical or Boolean expressions.
- #switch – a compact multi‑branch selector.
- #time – returns the current time in a format you dictate.
- #titleparts – splits the page title into components.
- #arraymap – applies a template to each element of an array.
These functions are part of the ParserFunctions extension, which ships with almost every modern MediaWiki installation.
Named parameters and defaults – making templates robust
Without named parameters, you end up juggling a list of positional arguments that can be easy to mis‑place. The syntax for a named argument looks like:
{{#ifexist: {{{page|Main Page}}} | {{#ifexist:{{{page|Main Page}}}|Yes|No}} }}Notice the {{{page|Main Page}}} pattern: it declares a variable page that falls back to “Main Page” if the caller didn’t supply a value. The double curly braces are a little quirky, but that’s just how wikitext works.
What I love about defaults is that they keep a template from blowing up when a new editor forgets an argument. A tiny redundancy, but it saves a lot of head‑scratching later.
Embedding parser functions inside templates
Templates and parser functions are often used together, and that’s where you start seeing truly dynamic content. Take a typical “infobox” template that pulls the article’s title and automatically adds a link to the talk page:
{{Infobox
|title = {{FULLPAGENAME}}
|talk = {{#ifexist: Talk:{{FULLPAGENAME}} | [[Talk:{{FULLPAGENAME}}|Talk]] | No talk page yet }}
}}Here the #ifexist function checks for a talk page before trying to render a link. If the page is missing, the template quietly falls back to “No talk page yet”. That behavior feels “smart” to the reader and spares admins from manually updating dozens of pages.
One thing to watch for: if your template calls a parser function that itself calls the same template, MediaWiki can hit its recursion limit. A quick check of $wgMaxRecursiveTemplateDepth in LocalSettings.php can prevent nasty errors.
Performance considerations – don’t let the functions slow you down
Parser functions are cheap when they just return a string, but they can become “expensive” if they perform heavy work, such as database queries or extensive looping. MediaWiki marks a function as expensive by passing the SFH_EXPENSIVE flag to Parser::setFunctionHook. When you do that, the parser will try to cache the result more aggressively.
Here’s a stripped‑down example of a custom PHP hook that marks itself as expensive:
// In an extension’s entry point
$wgHooks['ParserFirstCallInit'][] = function ( Parser $parser ) {
$parser->setFunctionHook( 'myexpensive', 'myExpensiveFunction', SFH_OBJECT_ARGS | SFH_EXPENSIVE );
return true;
};
function myExpensiveFunction( $parser, $frame, $args ) {
// Pretend we’re doing a costly DB query here
$result = Database::singleton()->fetchRow(...);
return $result;
}
Marking it as expensive tells MediaWiki: “Hey, cache this output if you can”. Otherwise you might end up re‑running the query on every page view, which could really bog down a busy site.
Writing your own parser functions – the basics
If the built‑ins don’t cover a particular need, you can extend the parser with a custom hook. The general pattern is:
- Register a hook on
ParserFirstCallInit. - Call
Parser::setFunctionHookwith your function name and callback. - Write the callback to accept either plain arguments (
$parser,$arg1,$arg2) or the object‑style signature ($parser,$frame,$args).
The object‑style version gives you a PPFrame object, which can expand nested wikitext on demand. That’s handy for #ifexpr-style conditionals where you only want to evaluate the “true” branch.
For example, a simple “random quote” function could look like this:
$wgHooks['ParserFirstCallInit'][] = function ( Parser $parser ) {
$parser->setFunctionHook( 'randomquote', 'wfRandomQuote' );
return true;
};
function wfRandomQuote( $parser, $frame, $args ) {
$quotes = [
"Keep it simple.",
"Code is poetry.",
"Never trust a bug with a smile."
];
$choice = $quotes[array_rand( $quotes )];
// Return raw wikitext, no further parsing needed
return $choice;
}
Drop that into an extension.json or a small RandomQuote.php file, and you can call {{#randomquote}} anywhere on the wiki. The output changes every time the page is rendered – perfect for a splash page or a “quote of the day”.
Debugging tips – when the output isn’t what you expect
Parser functions can be cryptic, especially when they involve nested templates. Here are a few tricks I’ve learned:
- Use
#showor#arraymapfor step‑by‑step output. Wrapping a suspect call in{{#show: {{#ifexist: ... }}can reveal which branch is taken. - Check the cache status. Adding
debug=1to the URL (e.g.,?debug=1) shows whether a function’s result was cached or recomputed. - Watch for “unexpanded” arguments. When you see raw wikitext like
[[Page]]appearing literally, it probably means you forgot to use$frame->expandin a custom hook. - Mind the order of evaluation. Parser functions are evaluated left‑to‑right, but some built‑ins (like
#if) short‑circuit. That’s why#ifexpris handy – it only expands the true side.
If you hit a wall, the help page on MediaWiki.org has a surprisingly thorough list of every core function with examples. It’s a great reference when you’re feeling stuck.
Real‑world patterns that showcase the power of parser functions
Below are a few scenarios where I’ve seen parser functions make a wiki feel dynamic without any JavaScript:
- Automatic category assignment. A template can add a page to a category only if a certain parameter is set:
{{#if: {{{type|}}} | [[Category:{{{type}}}]] }}. - Context‑aware navigation. Using
#titlepartsyou can highlight the current section in a sidebar:{{#titleparts:{{PAGENAME}}|1}} = "Current". - Version badges. Pull the latest release number from a page that stores a JSON blob, then display it with
#invoke:SomeModule|getVersionwrapped inside an#ifexistcheck. - Localized greetings. Combine
#exprwith theLANGmagic word to greet users in their interface language.
All of those use cases are achievable with just a handful of lines of wikitext, which keeps the site lightweight and easier to maintain.
A word on maintainability
It’s tempting to cram every conditional you can think of into a single template. In practice, that quickly becomes a “spaghetti” mess. I recommend breaking complex logic into smaller building blocks –‑ one template per logical unit –‑ and then assemble them with parser functions. It mirrors the way programmers write functions in any language, and it yields pages that are easier to read (for humans) and easier to parse (for MediaWiki).
Wrapping up: where to go from here?
Parser functions are the secret sauce that turns a static wiki into a living, breathing knowledge base. They let you:
- Make content adapt to the time of day, the page title, or the user’s language.
- Write reusable, parameter‑driven templates that stay tidy even as the site grows.
- Extend the parser with custom PHP hooks for truly bespoke behaviour.
- Keep performance in check by flagging expensive functions and leveraging caching.
If you’ve been hand‑crafting tables or manually updating categories, consider flipping the switch to parser functions. It might feel a little odd at first –‑ the syntax is quirky, the documentation is dense –‑ but once you get the hang of #ifexpr and its cousins, you’ll wonder how you ever managed without them.
Perhaps the best way to cement the concepts is to open a sandbox page, paste a few examples, and watch the output shift in real time. The more you play, the more the patterns stick, and the richer your wiki becomes.