Advanced Templating in MediaWiki: Creating Dynamic Content

The advanced templating toolkit: named parameters, ParserFunctions patterns, #ifexist and #switch, and moving complex logic into Lua modules.

Templates are MediaWiki's component system. The advanced layer — parameters, parser functions, Lua — is what separates reusable components from copy-paste walls. This article is the practical upgrade path from basic templates to maintainable logic, with the patterns that hold up on real wikis.

1. Parameters done properly

The main template:
{{#invoke:Example}}
{{Infobox book
 | title = {{PAGENAME}}
 | author = {{{author|Unknown}}}
 | year = {{{year|}}}
}}
  • Always named parameters — positional parameters break the moment someone inserts a field; named params survive every refactor
  • Defaults for everything{{{param|default}}} makes templates render even when callers omit fields; empty defaults ({{{year|}}}) suppress the field entirely when combined with {{#if}}
  • Pass-through — templates calling templates forward {{{param|}}} rather than re-declaring logic

2. ParserFunctions: the logic layer

ParserFunctions (bundled) provides the conditional toolkit:

{{#if: {{{year|}}} | Published in {{{year}}} | Publication year unknown }}

{{#ifeq: {{{status|}}} | draft | {{draft-banner}} | {{live-banner}} }}

{{#switch: {{{type|}}}
 | book = {{book-section}}
 | article = {{article-section}}
 | #default = {{generic-section}}
}}

Patterns that matter:

  • {{#if:...}} / {{#ifeq:...}} — conditional rendering and value comparison
  • {{#ifexist:Page|A|B}} — react to page existence; the foundation of 'create me' links and dynamic navigation
  • {{#switch:...}} — value dispatch; cleaner than nested #ifeq
  • {{#expr:}} / {{#iferror:}} — arithmetic (with |R= raw output) and error handling

3. Performance: expansion limits and costs

Every parser function costs expansion time; deeply nested templates hit MediaWiki's expansion depth and time limits, which surface as 'expansion depth limit exceeded' or truncated output. Rules of thumb:

  • Keep conditionals shallow — move repeated logic into the template once, not per call site
  • Avoid #ifexist in hot templates (it queries the DB); cache its result in Lua or restrict to low-use templates
  • Long pages with many transclusions benefit from splitting into fewer, thicker templates

4. Lua: when ParserFunctions is not enough

Logic beyond #switch chains — loops, string manipulation, table lookups — belongs in Scribunto Lua modules:

local p = {}

function p.ordinal( frame )
    local n = tonumber( frame.args[1] or 1 )
    local suffix = 'th'
    if n % 10 == 1 and n % 100 ~= 11 then suffix = 'st'
    elseif n % 10 == 2 and n % 100 ~= 12 then suffix = 'nd'
    elseif n % 10 == 3 and n % 100 ~= 13 then suffix = 'rd' end
    return tostring( n ) .. suffix
end

return p

Invocations: {{#invoke:Ordinal|ordinal|{{#expr:{{PAGENUMBER}}}}}}. Lua runs in a sandbox with strict CPU/memory limits, but it is faster than parser-function chains for real work — Wikipedia's most complex templates are Lua for this reason.

5. Template architecture that survives

  1. One responsibility per template — layout components (boxes, headers) separate from data holders (infoboxes)
  2. Document the contract — TemplateData on every parameter (which also powers VisualEditor's form UI)
  3. Version the behavior — big template changes through a new parameter or a staging template, with the diff reviewable on the talk page
  4. Cap the nesting — 3–4 levels of transclusion depth is the comfort zone; beyond that, Lua

The reference material: Help:Template for basics, parser functions in templates, and the Scribunto reference. Build from named parameters up, push logic down into Lua at the first sign of parser-function spaghetti.

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