Mastering ParserFunctions in MediaWiki: Logical and String Functions for Dynamic Content
ParserFunctions Unleashed: From Simple Logic to String Sorcery
Ever stared at a wiki page that felt as static as a marble statue? Then you probably missed the hidden gears of ParserFunctions humming underneath. Imagine you could ask, “Show this text only if the user is logged in,” or “Trim a title down to thirty characters.” That’s what we’re diving into today – a hands‑on romp through logical and string functions that turn bland wikitext into a living, breathing interface.
Why bother?
First off, you don’t need a PhD in computer science to add conditional flair. The core parser already understands a handful of “if‑this‑then‑that” tricks, but the extension expands the toolbox to a point where you can rewrite page titles on the fly, build navigation menus, or even craft tiny calculators without touching a single line of PHP.
And no, I’m not just blowing smoke. The ParserFunctions extension ships with MediaWiki 1.18+ – so if your wiki runs on a modern version, the code is already there, just waiting to be turned on.
Getting the engine humming
// In LocalSettings.php
wfLoadExtension( 'ParserFunctions' );
// Enable string functions (optional but handy)
$wgPFEnableStringFunctions = true;
// Keep an eye on the max string length; 1000 is the default.
$wgPFStringLengthLimit = 1500;
That’s it. One line to load, another to flip the switch, and you’re ready to start sprinkling magic across your wiki.
Logical functions – the Swiss‑army knives
Let’s start with the classics. These are the “if‑you‑look‑closer‑you’ll‑see‑the‑logic” functions that every seasoned wiki‑editor knows by heart.
#if– the most basic conditional.#ifeq/#ifneq– compare two values.#ifexist– does a page exist?#switch– a tidy alternative to nested#ifs.#expr– evaluate a mathematical expression.
Example: show a warning only for anonymous users.
{{#if: {{{{{USERID}}}}|
|
'''Warning:''' You are browsing anonymously. Some features may be hidden.
}}
Notice the triple braces – they pull the USERID variable from {{#ifexist:User:{{{USERNAME}}}}} behind the scenes. If you’re not a fan of that nesting, you can always break it out into a template.
Now, a quick #switch demo: a tiny language selector.
{{#switch: {{#var:lang}}
|en=Welcome!
|fr=Bienvenue!
|es=¡Bienvenido!
|{{#default}}=Hello, world!
}}
Here #var fetches a custom variable that you could set elsewhere with #vardefine. The #default clause catches any unexpected language code – a nice safety net.
String functions – turning text into play‑dough
When $wgPFEnableStringFunctions is true, a whole new world opens up. Think of it as a mini‑programming language for strings. Below are the most useful ones, illustrated with real‑world scenarios.
#len– length of a string.#sub– substring extraction.#replace– find‑and‑replace.#lc/#uc– lower‑case / upper‑case conversion.#urlencode– make a string safe for URLs.#explodeand#join– split and re‑join lists.#padleft/#padright– add padding characters.
Take the common need to truncate a long title to a manageable length:
{{#if: {{#len: {{PAGENAME}} }} > 30
|{{#sub: {{PAGENAME}} |0|30}}…
|{{PAGENAME}}
}}
That snippet checks the title length; if it exceeds thirty characters, it slices the first thirty and tacks an ellipsis on the end. The #sub function’s third argument (the length) makes this a breeze.
What about cleaning up a user‑entered URL parameter? Suppose you accept a page query string and want to guarantee it’s safe:
{{#urlencode: {{#replace: {{{page|}} |_ | }} }}
First we strip any underscores (common in MediaWiki URLs) then URL‑encode the result. A single line, but it prevents broken links and possible XSS vectors.
Mixing logic and strings – the sweet spot
Often you’ll find yourself chaining logical and string functions together. Let’s build a dynamic navigation breadcrumb that only shows the parent page if it exists.
{{#ifexist: {{FULLPAGENAME}}/Parent
|[[{{FULLPAGENAME}}/Parent]] > {{FULLPAGENAME}}
|{{FULLPAGENAME}}
}}
Here #ifexist checks for a subpage named “Parent”. If it’s there, we render a link followed by a right‑arrow and the current page name; otherwise we just show the current page. Notice the use of FULLPAGENAME to get the namespace‑aware title – a handy variable for any cross‑namespace logic.
A more elaborate case: automatically generate a “Read more” teaser for articles longer than 500 characters.
{{#if: {{#len: {{#invoke:TextExtract|get|{{FULLPAGENAME}}}} }} > 500
|{{#sub: {{#invoke:TextExtract|get|{{FULLPAGENAME}}}} |0|500}}… {{#ifexist: {{FULLPAGENAME}}/Full |[[{{FULLPAGENAME}}/Full|Read more]]}}
|{{#invoke:TextExtract|get|{{FULLPAGENAME}}}}
}}
We call a Scribunto module (#invoke:TextExtract) to pull the raw article text, then measure its length. If it crosses the 500‑character threshold, we slice it, add an ellipsis, and optionally link to a “Full” subpage. If not, we just dump the whole thing. This blend of #if, #len, #sub, and #ifexist showcases the power of chaining.
Best‑practice checklist (so you don’t pull a late‑night brain‑freeze)
- Enable string functions only if you truly need them. They add a slight parsing overhead; keep
$wgPFEnableStringFunctionsfalseon high‑traffic wikis where they’re not used. - Mind the length limit. By default, strings longer than
$wgPFStringLengthLimit(1000) are truncated, which can bite you when processing large bodies of text. Raise the limit cautiously. - Avoid deep nesting. While
#ifinside#ifworks, readability suffers fast. Prefer separate templates or modules for complex logic. - Sanitize user input. Use
#urlencode,#replace, or even a Scribunto module for heavy‑duty sanitisation. - Cache results. For computationally expensive expressions, store the outcome in a variable via
#vardefineand reuse it.
Common pitfalls – the “gotchas” you’ll hit
1. Forgot to enable string functions? You’ll see errors like “Parser function ‘len’ is not defined.” Double‑check $wgPFEnableStringFunctions in LocalSettings.php.
2. Running into the 1000‑character wall? The extension silently truncates. Use #ifexist:{{#vardefine:longtext|{{{large|}}}}} to test the length first, or bump the limit.
3. Accidental infinite loops. It’s easy to create a recursion with #ifexist calling a template that calls back. MediaWiki will eventually abort with a “Maximum recursion depth exceeded” error – but better to avoid it altogether.
Going beyond – Scribunto and external libraries
If the built‑in functions start feeling cramped, the Scribunto extension lets you write Lua modules that can be invoked from wikitext. Think of it as the “heavy‑weight” cousin of ParserFunctions. The bridge works like this:
{{#invoke:Math|add|2|3}}
Inside Module:Math you could define:
local p = {}
function p.add(frame)
local a = tonumber(frame.args[1]) or 0
local b = tonumber(frame.args[2]) or 0
return a + b
end
return p
When you need more sophisticated string handling – like regular‑expression replacements – Lua shines. Still, keep the simple cases inside ParserFunctions for speed and maintainability.
Final thoughts
So you’ve seen the logical gates, the string‑shaping tools, and the occasional edge‑case that can trip even seasoned editors. The real power lies in mixing them: a #ifexist that decides whether to #replace a fragment, or a #switch that hands off to a Lua module for complex calculations.
Next time you stare at a static page, ask yourself: “What if I could let the parser decide, on the fly, what to show?” Then reach for the appropriate function, sprinkle it in, and watch the page come to life. The wiki is no longer just a collection of pages; it becomes a responsive, logic‑driven experience.