Mastering MediaWiki's Parser Functions: A Developer's Guide

Why parser functions matter

Jump‑in: why parser functions matter

Imagine you’re tweaking a wiki that lives on the edge of a bustling community—people drop in, edit, and expect instant, tidy results. You could hand‑craft every template, but that’s like painting each brick individually. Parser functions are the mortar: they let you compute, branch, and format on the fly, without spawning a gazillion templates.

Got a “last‑updated” stamp that should respect the viewer’s timezone? Need to pull the page title, split it, and feed parts into a navigation box? All that, and more, lives the curly braces that MediaWiki has been whispering about since version 1.7.

Getting the extension on board

  • Check LocalSettings.php. If you haven’t already, add wfLoadExtension( 'ParserFunctions' );.
  • Run php maintenance/update.php (or hit Special:Version in your browser to confirm it’s loaded).
  • Optional: tweak $wgPFEnableStringFunctions if you want the #replace and #explode goodies.

Don’t forget to clear the cache after a fresh install—otherwise the wiki will act like it never saw those functions, and you’ll be scratching your head wondering why “{{#if}}” just prints literally.

Basic building blocks

At its core, a parser function looks like {{#func:param1|param2|…}}. The “#” signals “this is a function, not a variable”. The most common starters are:


{{#if:{{{show|}}}|Yes|No}}
{{#ifexist:Help:Parser_functions|Exists|Missing}}
{{#ifeq:{{{lang|en}}}|fr|Bonjour|Hello}}

Notice the triple braces {{{…}}}—they’re placeholders for template parameters. If you’re new to them, think of them as “fill‑in‑the‑blank” slots that the caller decides the content of.

Branching without a compass

Ever tried to write a single template that works for both “draft” and “published” pages? The #if family saves you a boatload of duplication.


{{#if:{{{draft|}}}
 | {{#subpagelist:namespace=Talk|title={{FULLPAGENAME}}}}
 | {{#subpagelist:namespace=0|title={{FULLPAGENAME}}}}
}}

Here the function checks whether draft is set. If it is, we list talk‑subpages; otherwise we list article subpages. The syntax can feel a bit cramped, but once you get the rhythm, it’s as smooth as a well‑oiled bike chain.

String gymnastics

String manipulation used to be a pain point before the StringFunctions module (enabled via $wgPFEnableStringFunctions = true;). Now you can split, replace, and trim without a single Scribunto module.


{{#replace:{{{title|}}}|_|\ }}

That tiny line swaps underscores for spaces—handy when you’re pulling a page title into a human‑readable heading.

Or, to grab the last segment of a slash‑separated path:


{{#explode:{{FULLPAGENAME}}|/|{{#vardefine:parts|{{#explode:{{FULLPAGENAME}}|/}}}}}}
{{#vardefine:last|{{#arrlast:{{#var:parts}}}}}}
{{#var:last}}

Sure, it looks like a cryptic recipe, but once you’ve baked it a couple of times you’ll appreciate the power—no need to dive into Lua for simple splits.

Arithmetic and date tricks

When you need to calculate ages or add days to a deadline, #expr is your go‑to. It supports basic math, bitwise ops, and even mod (the remainder operator).


{{#expr: ( {{#time:Y}} - {{#time:Y|{{{birthdate|}}}}} ) }}

That one‑liner spits out the age based on a birthdate param formatted as YYYY-MM-DD. If you’re feeling fancy, combine it with #time to format future dates:


{{#time:{{#expr:{{#time:Y}}+1}}-{{#time:m}}-{{#time:d}}}}

Result: the same month‑day next year. Handy for “renewal” notices that never get stale.

URL‑and‑title decoding

MediaWiki stores page titles in a URL‑encoded form when you fetch them via #urlencode or #urlunencode. This is useful when you want to embed a link inside a parameter that itself is part of a URL.


{{#urlencode:{{FULLPAGENAME}}}}

Couple that with #titleparts to dissect a title into namespace, main title, and fragment. Great for generating breadcrumbs without a custom extension.


{{#titleparts:{{FULLPAGENAME}}|1}} – namespace
{{#titleparts:{{FULLPAGENAME}}|2}} – base title
{{#titleparts:{{FULLPAGENAME}}|3}} – section (if any)

Performance: keep it lean

Parser functions are evaluated on every page view, which means a heavy‑handed #ifexist in a top‑level template can add noticeable latency. A few tricks help keep the wiki snappy:

  • Cache results. Use {{#vardefine}} to store intermediate values; this avoids recomputing the same expression multiple times in the same render.
  • Prefer static data. When you need a list of categories, consider using #show from the ParserFunctions extension rather than pulling the whole list via an API call inside a template.
  • Limit recursion. Deeply nested templates that each call parser functions can blow the parser stack. MediaWiki caps recursion at 100 levels, but hitting that limit will throw a “too many levels of recursion” error.

Security hygiene

Because parser functions can be used to fetch page content (#ifexist, #titleparts, etc.), a mischievous user could try to expose private pages or overload the parser with massive loops. Here’s what to watch:

  • Disable #ifexist on wikis that host confidential material. Set $wgPFAllowDisplayTitle = false; if you don’t need dynamic titles.
  • Turn on $wgEnableJavaScriptTest—it won’t stop parser misuse, but it will flag templates that call too many functions.
  • Audit templates regularly. A simple “{{#expr:{{#var:x}}*{{#var:x}}}}” can be turned into a denial‑of‑service if x is user‑controlled and astronomically large.

In short, treat parser functions like any other code: keep an eye on input, validate where possible, and don’t hand out super‑powers to just anyone.

Real‑world showcase: a dynamic “Featured article” banner

Suppose your wiki wants to highlight the article of the week, pulling the title from a page Template:Featured. A compact solution lives entirely in wikitext:


{{#vardefine:fa|{{#ifexist:Template:Featured|{{#subpagelist:namespace=Template|title=Featured|limit=1}}|None}}}}
{{#if:{{#var:fa}}|
  {{#ifexist:{{#var:fa}}|
    {{#titleparts:{{#var:fa}}|2}} 
    {{#ifexist:{{#var:fa}}/Banner|
      [[File:{{#var:fa}}/Banner|thumb|center]]
    }}
  | No featured article today.}}
| No featured article today.}}

What’s happening?

  1. We grab the first subpage of Template:Featured (that’s the article name).
  2. If it exists, we extract its base title and optionally pull an image named ArticleName/Banner.
  3. If anything’s missing, a friendly fallback shows up.

All of that without a single line of PHP or Lua. The page automatically updates when editors edit Template:Featured or upload a new banner image.

Debugging tips – when things go sideways

Parser functions don’t throw stack traces; they just output the raw call if something’s off. To diagnose, wrap your suspect call in #iferror (available via the ParserFunctions extension) and ship a helpful message.


{{#iferror:{{#:{{{num|}}}+1}}|Oops, {{#var:num}} isn’t a number!|Result: {{#expr:{{{num|}}}+1}}}}

Now a typo like “abc” won’t break the whole page; you’ll see a gentle “Oops…” cue instead. Another handy tool is Special:ExpandTemplates—paste your wikitext there and watch the engine resolve every function step by step.

Beyond the basics: mixing with Scribunto

When you outgrow pure parser functions, Lua modules (#invoke) can take the baton. The trick is to keep the heavy lifting in Lua while letting parser functions handle the simple conditionals and formatting.


{{#invoke:Stats|display|page={{FULLPAGENAME}}}}
{{#ifexist:{{#invoke:Stats|hasData|page={{FULLPAGENAME}}}}|…|No data}}

Here Stats returns a boolean flag (via #return) that the surrounding parser function checks. This pattern reduces the number of template calls, speeds up rendering, and keeps the wikitext readable.

Final thoughts – a toolbox, not a crutch

Parser functions are like a Swiss‑army knife: you can carve out a quick solution, but you shouldn’t rely on it for every job. When the logic starts to feel like a maze of pipes, consider a dedicated extension or a Lua module. Still, for the everyday “show this if that”, “format this date”, or “split that title”, they’re unbeatable.

If you’re still on the fence, try sprinkling a few #if checks into an existing template you already maintain. Watch the page load a tad faster (thanks to reduced template churn) and enjoy the satisfaction of seeing a single wikitext line replace a whole cascade of sub‑templates. That’s the sweet spot where Mastery meets practicality.

Subscribe to MediaWiki Tips and Tricks

Don’t miss out on the latest articles. Sign up now to get access to the library of members-only articles.
jamie@example.com
Subscribe