Help:Substitution

From Meta, a Wikimedia project coordination wiki
This is an archived version of this page, as edited by Patrick (talk | contribs) at 14:35, 21 November 2007 (→‎Substitution of part of the parameters: rm dup). It may differ significantly from the current version.

Substitution is automatic conversion of wikitext of a page referring to a template, variable, or parser function when the referring page is saved.

In the case of template substitution the template call is replaced by the template content with substitution of the parameters. Thus a template is used as macro and the page is macro expanded when the page is saved rather than, as usually happens, when the page is viewed.

In the case of substitution of a variable or parser function the reference to it is replaced by the resulting value.

Substitution is done by putting the modifier subst: after the double opening braces.

The result (in the form of the difference with the saved wikitext) can be seen before (or without) saving by pressing "Show changes". However, if the text covers more than one paragraph this diff page is not very suitable for copying the result (e.g. for stepwise substitution without saving every step), because of plus signs in the margin.

Applications

Substitution of a template:

  • Make a rendered page independent of the template:
    • The rendered page does not change when the template is edited.
    • The page can be copied to another project without copying the template.
  • Make page rendering easier and therefore faster for the server.
  • Stay under the Template:Peisl.
  • Analyse and demonstrate the working of templates.
  • Make the correspondence between wikitext and rendered page easier to understand (this may apply, the opposite may also apply).

Substitution of a time-dependent variable:

  • Make a rendered page independent of the time.

Substitution of a page-dependent variable:

  • Make a rendered page independent of renaming of the page and of copying the wikitext to another page (the opposite applies if the variable PAGENAME is used in a no-include part of the page to include the page itself).

Some MediaWiki extensions have the restriction that if they are used in a template with parameters, they only work if the template is substituted. This applies for example in the case of a template parameter inside an in-page query in Semantic MediaWiki.

Overview

For the discussion of substitution, an "ordinary template" is any page included by {{subst:pagename }} for pages in the template namespace or {{subst:fullpagename }} for pages in other namespaces. It's also possible to substitute variables and parser functions collectively known as "predefined templates".

Substitution is a separate process before expansion of non-substituted templates, parser functions and variables. Substitutions in the expression for the name of the template or parser function, in the parameter definitions of the substituted template or parser function and in the body of the substituted template are done first. Non-substituted expansion is done later, so at the time of the substitution these expressions with pairs of double braces are treated as plain text. Thus during substitution there can be a parameter name with braces in the call of the substituted template (e.g. a{{bc}}d) that matches a parameter with the same name in the template body.

If one attempts to apply substitution to a non-existing template etc. there is no substitution, the "subst:" prefix is kept in the wikitext.

After the substitution process, expansion of templates etc. and other processing of the resulting wikitext works as usual. However, this cannot undo a mismatch of parameter names during substitution (see also the second header "Partial substitution" below).

Examples:

  • {{subst:Help:L{{tc}}k}} using Template:Tc, does not do substitution, because Help:L{{tc}}k is not an existing page, although Help:L{{tc}}k is rendered as Help:Link. Thus the resulting wikitext is the same as the original wikitext and rendered as {{subst:Help:Link}}.
  • {{subst:#if:{{x0|abc}}|yes|no}} using Template:X0, gives the wikitext "yes", while {{subst:#if:{{subst:x0|abc}}|yes|no}} gives the wikitext "no", and {{#if:{{x0|abc}}|yes|no}} is rendered as "no".

In principle the wikitext resulting from full substitution is, immediately after that, rendered the same as the wikitext with ordinary inclusion.

There are exceptions, for example in the case of an undefined parameter with a default value:
  • {{#expr:2*{{{p|3}}}}} gives 6, while {{subst:#expr:2*{{{p|3}}}}} gives "Expression error: unrecognised punctuation character "{"", because in the case of substitution of #expr, {{{p|3}}} is not reduced to 3 and therefore #expr concludes that the expression is not valid. (See also below.)

{{ {{t6}} }} using Template:t6 containing "t2demo|a" is rendered as {{ t2demo|a }}; {{subst:{{subst:t6}} }} gives the wikitext {{subst:t2demo|a }} rendered the same as the wikitext, and on the next edit/save changed into start-a -middle-{{{2}}}-end; {{ {{subst:t6}} }} gives the wikitext {{ t2demo|a }}, rendered as start-a -middle-{{{2}}}-end. This is because, both without substitution and in the case of full substitution, the pipe characters in template calls, excluding those inside inner template calls, template parameters, links, and image tags, determine the separation of parameter definitions from each other and from the template name. This separation does not depend on possible extra pipe characters in the expanded form of the template name and parameter definitions. However, if after substitution of an inner template the pipe character is in the outer template call it is one like any other and plays its part in determining the separation. In other words, parsing is done first once for substitution, and then once for rendering, but in both cases not an extra time in between. In the case of substitution of the inner template only, two subsequent parsings are effective.

Usage considerations

As mentioned, a change of an ordinary template after substitution does not affect the page in which it was substituted, and a substituted variable depending on time no longer depends on time, etc. However, a substitution of e.g. {{#expr:2*3}} does not affect rendering at all.

The relationship between wikitext of a page and its rendering can become easier to understand after substitution, because one has all wikitext together, and parameter substitutions have been performed.

It can also become more complex. Separately focusing on understanding a template call and understanding the template content can be easier. Wikitext after substitution is often more complex than when the required wikitext would have been written directly.

Unlike a template call (if one knows about templates), wikitext after substitution does not show how one can produce a similar result. The wikitext can be long and complicated, and therefore cumbersome to write directly, or it can be simple, e.g. a number resulting from a computation, but cumbersome to find directly. One may think that the wikitext is what one is supposed to write and find directly to get the result, even in cases where that would be very impractical.

In such cases documentation of the template call is useful. Just like in computer programming we change the source code and/or the data to produce new results, and we do not directly change the object file, here we would change the template calls and/or the templates, instead of changing the wikitext resulting from substitution directly.

Ordinary templates

In the case of substituting an ordinary template, the template tag is replaced by the wikitext of the template, with the parameter values substituted for the parameters. Even parameters in comments are substituted.

Example: Template:T2, containing
start-{{{1}}}-middle-{{{2}}}-end
and called as {{subst:t2|[[a]]|{{tc}}}} (see {{tc}}) gives the wikitext:
start-[[a]]-middle-{{tc}}-end, rendering as
start-a-middle-in-end.

Substitution removes the noinclude parts and the includeonly tags.

Parameters:

  • A substitution with p=r replaces {{{p}}} and {{{p|q}}} by r; this includes the cases that r is of the form {{{s}}} or {{{s|t}}}.
  • A substitution with undefined p preserves {{{p}}} and {{{p|q}}}; the latter is not replaced by the default q (see below for a construct that is replaced by p if p is defined, and by q if not).

With "subst:" the replacement of a template tag by wikitext does not work recursively. For full recursive substitution use Special:ExpandTemplates. See also substall, and optional substitution below.

Stepwise substitution of templates including other templates including more templates etc. can be useful for analyzing problems or documenting the expected behaviour of complex templates, for an example see m:Template talk:Lop.

Stepwise substitution for template names depending on the parameter default mechanism doesn't work as one may expect, this also affects parameter defaults in the left hand side of parser functions, see below for examples.

In the absence of parameters, template substitution can be compared with copying the wikitext, or the rendering of a previewed or saved {{ msgnw:pagename }} inclusion. However, template substitution excludes <noinclude> parts, and removes <includeonly> tags.

Predefined templates

In the case of substituting a predefined template, without parameters depending on other templates, the tag is replaced by the result. Please note that subst: has to be added directly in front of the predefined template name without intervening spaces.

Applying subst to a variable works like applying it to a template. E.g. a timestamp:

{{subst:CURRENTDAY}} {{subst:CURRENTMONTHNAME}} {{subst:CURRENTYEAR}}, {{subst:CURRENTTIME}} (UTC)
10 March 2005, 08:23 (UTC)

In the case of substituting a predefined template with a parameter depending on another template, that has to be substituted too, with a separate subst: modifier, otherwise the result is undefined.

  • {{subst:UC:{{subst:tc}}}} gives IN, the same wikitext as {{UC:{{tc}}}} is expanded to; UC: is applied to the output "in" of Tc.
  • {{subst:ns:{{subst:#expr:2*3}}}} gives Image.
  • {{ns:{{subst:#expr:2*3}}}} gives wikitext {{ns:6}} rendered as File.
  • {{subst:t1|{{subst:NAMESPACE}}}} gives the wikitext startHelpend (see {{t1}})
  • {{subst:t1|{{subst:#expr:3*4}}}} gives the wikitext start12end
  • {{subst:t1|{{subst:uc:AbCdEf}}}} gives the wikitext startABCDEFend
  • {{subst:#expr:{{subst:3X|11*}}1}} gives the wikitext 1331
  • {{subst:UC:{{subst:3X|abc}}}} gives the wikitext ABCABCABC
  • {{subst:LC:{{subst:#expr:1/100000}}}} gives the wikitext 1e-05 (see LC:)
  • {{subst:#expr:2*{{subst:CURRENTDAY}}}} gives (at the time of writing) the wikitext 30
  • {{subst:UC:{{subst:CURRENTDAYNAME}}}} gives (at the time of writing) the wikitext THURSDAY

However:

  1. {{subst:UC:{{tc}}}} gives the wikitext {{TC}} rendered as Template:TC.
  2. {{subst:ns:{{#expr:2*3}}}} stays {{subst:ns:{{#expr:2*3}}}}, rendered as {{subst:ns:6}} (see ns:).

As mentioned before, on substitution, all calls without substitution of templates, variables, and parser functions are treated as plain text. As a result substitution of the outer x: in a nested {{ x:...{{ y:...}} }} often is only suitable if all inner y: are also substituted.

In the case of substitution of a predefined template, if the expression for one of its parameters contains {{{p|3}}} with undefined p, this code does not reduce to 3, so a string function like lc can be applied but not e.g. #expr. For example:

  • {{#expr:2*{{{p}}}}} gives Expression error: Unrecognized punctuation character "{".
  • {{#expr:2*{{{p|3}}}}} gives 6
  • {{subst:#expr:2*{{{p|3}}}}} gives the wikitext and rendering Expression error: unrecognised punctuation character "{"
  • substituting a template containing {{<includeonly>subst:</includeonly>#expr:2*{{{p|3}}}}} or {{{{{subst}}}#expr:2*{{{p|3}}}}} gives the same error if p is not assigned a value, but twice the number p if it is assigned a value.

Compare:

  • {{uc:2*{{{p}}}}} gives 2*{{{P}}}
  • {{uc:2*{{{p|q}}}}} gives 2*Q
  • {{subst:uc:2*{{{p|q}}}}} gives the wikitext 2*{{{P|Q}}} rendered as 2*Q

and also (from above):

  • {{subst:UC:{{subst:tc}}}} gives IN, just like {{UC:{{tc}}}} does; UC is applied to the output "in" of Tc.
  • {{subst:UC:{{tc}}}} gives the wikitext {{TC}} rendered as Template:TC.

In the substitution of UC, the inclusion tag {{tc}} is treated as string just like {{{p|q}}}.

Derived template names

Substitution of a template whose name depends on another template like {{A{{B}}}} or a parameter like {{A{{{P}}}}}, can only be applied if template B is substituted too, or if the parameter P has a value. Like above, a specified default as in {{A{{{P|D}}}}} is not enough.

Saving e.g. {{subst:H:f {{NAMESPACE}}|enname=Substitution}} is rendered as wikitext, not the desired effect: {{subst:H:f Help|enname=Substitution}}.

However {{subst:H:f {{subst:NAMESPACE}}|enname=Substitution}} would be replaced by the result of {{H:f Help|enname=Substitution}} as expected for a substitution in namespace Help.

Summary: Substitution of the whole {{ x...{{ y...}} }} works only if all inner y are also substituted.

Partial substitution

Inside an ordinary template one can apply substitution to an ordinary template call containing a parameter, to replace it by the direct wikitext containing the parameter. It amounts to automatically merging the two templates (creating a "composite template" like a composite function). It is not possible if the inner and/or outer template is predefined. (However, manually merging e.g. a call of #expr inside another one is useful for increasing the accuracy of the result by avoiding intermediate rounding to 12 digits.)

This way one can dispense with the optional substitution technique described below, and apply substitution of the resulting outer template by simply using "subst:" (unless there are more nesting levels).

Example:

  • {{subst:t}}}} gives the wikitext start-{{{1|pqr}}}-end, just that of Template:T, without noinclude parts and includeonly tags
  • {{subst:t|a{{{p|q}}}b}} gives the wikitext start-a{{{p|q}}}b-end

Examples with double substitution:

  • {{subst:3X|{{subst:t}}}} gives the wikitext start-{{{1|pqr}}}-endstart-{{{1|pqr}}}-endstart-{{{1|pqr}}}-endstart-{{{1|q}}}-end
  • {{subst:3X|{{subst:t|{{{1|q}}}}}}} gives the wikitext start-{{{1|q}}}-endstart-{{{1|q}}}-endstart-{{{1|q}}}-end

Multilevel substitution

When substituting a template it may be desirable to carry out a substitution inside the template too. This requires "subst:" in the template. There are two methods to prevent premature substitution (i.e., when the template is saved): the code "subst:" can be the possible value of an expression containing a parameter, or includeonly tags can be used (see below).

With the first-mentioned method (the code "subst:" can be the possible value of an expression) we can:

  • apply multilevel transclusion by making the expression the empty string;
  • apply one-level substitution by substituting the outer template and making the expression the empty string;
  • apply two-level substitution by substituting the outer template and making the expression evaluate to "subst:";
  • apply multi-level substitution by substituting the outer template, making the expression evaluate to "subst:", and calling the inner template with parameters controlling further inner substitutions in the same way; these parameters may depend on the substitution parameter controlling the substitution of the inner template, since if that is not substituted, inner substitutions within that template are not possible.

Similarly, if there are multiple templates, parser functions, and/or variables in the inner template(s) we can control substitution of all, either independently by using different parameters, or with some or all using the same parameter.

The simplest code to control whether we get the empty string of "subst:" is using a parameter which is assigned either value, for example with the name "subst", possibly with a postfix, for independent control of multiple substitutions. If we also specify a default value q by the code {{{subst|q}}}, then with substitution and undefined parameter "subst" this evaluates to the literal code "{{{subst|q}}}" (see below), so regardless of q, never to "subst:". Therefore in the case of substitution parameter "subst" has to be defined anyway. In the case of transclusion and undefined parameter "subst" it evaluates to q. Since inner substitution in only carried out if the outer template is also substituted, the only sensible value of q is the empty string. This is indeed convenient because with non-substituted transclusion we can then dispense with the parameter definition "subst=" in the outer template call.

Thus adding the feature of optional substitution to an existing template X can be done as follows:

  1. For each template, parser function, and variable Y used within X, say {{Y|a|b|c}}, replace Y by {{{subst|}}}Y resulting in {{{{{subst|}}}Y|a|b|c}}.
  2. For ordinary templates add a parameter subst={{{subst|}}} resulting in {{{{{subst|}}}Y|a|b|c|subst={{{subst|}}}}} (predefined templates like parser functions and variables don't get the additional parameter).

This allows to use {{X|d|e|f}) as is, or {{subst:X|d|e|f|subst=subst:}) with recursive substitution, as far as all ordinary templates Y used within X support this technique. Even if they don't support it they are still substituted, but won't propagate this recursive substitution into templates or variables Z used within Y.

Using {{subst:X|d|e|f}] without additional parameter subst=subst: should be okay, otherwise it also won't work with additional parameter. For some templates substitution breaks their function, and for some predefined templates (see below) and variable REVISIONID it won't work as expected.

As mentioned, also multiple parameters like subst can be used, to control which templates, parser functions, and variables are substituted, see e.g. Template:For#Substitution.

See also Help:Calculation#Substitution and Template:Example table with computations, with optional substitution.

Partial substitution

Using a template prepared for optional subst=subst: only with ordinary substitution, without specifying parameter values, allows to insert its code into another template, like copy and paste, but all <noinclude> parts and <includeonly> keywords automatically stripped. Executing inserted code instead of calling it may be more efficient for the server.

A typical example for this technique is expanding, within another template, a template used as test expression in a #switch: like Template:Len:

  1. Development code:
    {{#switch: {{len|parameter tag }}|0=case 0 etc.}}
  2. Standard solution:
    {{{{{subst|}}}#switch: {{{{{subst|}}}len|parameter tag |subst={{{subst|}}}}}|0=case 0 etc.}}
  3. Better solution: create template code by applying substitution using this wikitext:
    {{{{{subst|}}}#switch: {{subst:len|parameter tag }}|0=case 0 etc.}}

Template:Len is prepared for optional substitution, therefore both solutions work, but the latter solution substituting its code is simpler and more efficient.

Template:H:

If a template uses a parameter whose name is an expression containing a template or parser function, and the template is called with a corresponding parameter definition (in terms of the final name of the parameter) it expands properly only if at the time of expansion of the template the expression for the name of the parameter is or has been evaluated. Thus if the template is substituted without substituting the expression for the parameter name, the parameter definition is "lost", so the parameter becomes undefined. Therefore in such a case no substitution can give the same rendered result as full substitution, while partial substitution gives a different result. See e.g. Template:Ts1.

Composite operations

By {{A|{{B|p}}}} a template A is called with, as parameter, a call of template B with a parameter p. We could integrate such template calls to a single call {{C|p}} of a "composite template" C with parameter p.

The wikitext for template C would be {{A|{{B|{{{1}}}}}}}, or with optional substitution the following construct:
{{ {{{subst|}}} A|{{ {{{subst|}}} B|{{{1}}} |subst={{{subst|}}} }} |subst={{{subst|}}} }}
The subst={{{subst|}}} is only necessary for recursive substitution as explained above.

Note that it is not useful to specify "{{subst|subst:}}" since in the substitution phase this tag does not reduce to the default "subst:".

If A and/or B is predefined the construct is similar, but without subst={{{subst|}}} for that template.

Includeonly

A less versatile method for multilevel substitution is with a pair of includeonly tags: they can be used to prevent substitution on the page itself, while not having any effect when transcluding the page. Substitution is prevented by having one or both tags anywhere in the template call except inside a parameter definition. Thus the tag(s) can be before, inside, or after "subst:", or inside or after the template name. The positions of the two tags only influence the rendering of the template page itself. If the closing tag is put immediately after the opening tag the full wikitext is rendered, e.g.

{{<includeonly></includeonly>subst:tc}} is shown as {{subst:tc}}

The most common form of this technique, known as "includeonly subst magic", is {{<includeonly>subst:</includeonly>something}}. This suggests that substitution is prevented by discarding "subst:" on the page itself, but actually substitution is prevented because the subst-syntax is disturbed by the tags.

It doesn't substitute "something" at the time of the creation of the relevant template, but has the desired effect when the template is substituted. Please note that this works as expected only for substitution, not for normal (unsubstituted) inclusion. For examples see "preload" in Help:Inputbox and "substitution" in Help:Variable.

Creating a page which applies substitution on the next save

See Help:Recursive conversion of wikitext.

Forced substitution

Some templates deliberately refuse to work without substitution, for an example see w:en:Template:Conv-dist. This technique is essential for templates like w:en:Template:Prod producing some kind of timestamp, e.g. adding pages to dated categories.

The following code in any template T outputs a warning unless recursive substitution with subst=subst: is in effect:
{{{{{subst|}}}ifdef|{{{{{subst|subst:}}}ns:0}}|'''Warning'''}}.
  1. Output for {{T}} or {{subst:T}}: Warning,
  2. output for {{T|subst=subst:}}: Warning,
  3. output for {{subst:T|subst=subst:}}: nothing (no remaining wikitext).
This is a rare case where replacing ifdef by #if: doesn't work directly.

Parameter default considerations

When substituting a template containing {{{p|q}}} (a parameter tag with default) this results in the value of p if it is defined, and otherwise not in q but in {{{p|q}}} rendered as q. An advantage may be that if the page is transcluded it can still depend on p. A disadvantage is that if this is not needed the wikitext {{{p|q}}} instead of q clutters the wikitext, and that some operations one may want to apply to q cannot be applied to {{p|q}}, for example, if q is a number, a computation with substitution.

In plain text and links the code {{p|q}} is cluttering, but otherwise not a problem, for example:

Template:T link default, containing
[[{{{a|b}}}]] and called as
{{subst:t link default}} gives the wikitext
[[{{{a|b}}}]], rendering as b.

In other cases there are complications. With substitution a numeric expression containing {{{p|q}}} gives an error message. A string comparison is possible but one should realize that the string contains {{{p|q}}} and not just q if p is undefined.

Instead of {{{p|q}}} one can use

{{{{{subst|}}}#ifeq:{{{p|+}}}|{{{p|-}}}|{{{p}}}|q}}

With substitution (subst=subst:) this results in the wikitext q if p is undefined, so this can be used in a numeric expression, e.g.:

{{{{{subst|}}}#expr:2*{{{{{subst|}}}#ifeq:{{{1|+}}}|{{{1|-}}}|{{{1}}}|1}}}}

which doubles the parameter if is defined, and otherwise returns 2, see Template:T double.

The alternative code for specifying a default is also useful in the then- and else-part of a parser function if the parameter is 1, 2, or 3, and also in a switch if the parameter name is a possible value of the switch parameter, as workaround for the bug mentioned below.

With Special:ExpandTemplates, {{{p|q}}} gives the wikitext q.

Attempts of direct substitution

{{subst:#expr:{{{a|1}}}}} gives
Expression error: unrecognised punctuation character "{"
An unsubstituted inclusion {{#expr:{{{a|1}}}}} yields 1.
{{subst:#ifexpr:{{{a|1}}}>7|1|0}} gives
Expression error: unrecognised punctuation character "{"
An unsubstituted inclusion {{#ifexpr:{{{a|1}}}>7|1|0}} yields 0.
Parameter tags with default are compared as strings instead of comparing the default:
{{subst:#if: {{{a|1}}}|1|0}} gives 1 like a simple inclusion: 1,
{{subst:#if: {{{a|}}}|1|0}} gives 1, but inclusion yields 0,
{{subst:#ifeq: {{{a|1}}}|7|1|0}} gives 0 like a simple inclusion: 0,
{{subst:#ifeq: {{{a|1}}}|1|1|0}} gives 0, but inclusion yields 1,
{{subst:#ifeq: {{{a|1}}}|{{{a|1}}}|1|0}} gives 1 like an inclusion: 1,
{{subst:#ifeq: {{{a|+}}}|{{{a|-}}}|1|0}} gives 0 like an inclusion: 0.

Thus {{#ifeq: {{{a|+}}}|{{{a|-}}}|1|0}}, a common way to determine if a given parameter is really undefined and not only empty, works also with substitution. Please note that #if: and templates like ifdef don't get this nuance, in the case of #if: an intentional feature for backwards compatibility. For details see advanced templates, in essence now obsolete because #ifeq: unlike #if: solves this problem even if substituted.

URLs

Fullurl and localurl with an undefined parameter cannot be substituted at all, even if a default value is specified. This is a variation of the case of derived template names.

  • {{subst:fullurl:{{{1|a}}}}} gives {{subst:fullurl:{{{1|a}}}}}.
    {{fullurl:{{{1|a}}}}} gives //meta.wikimedia.org/wiki/A.
  • {{subst:localurl:{{{1|a}}}|x=y}} gives {{subst:localurl:a|x=y}}.
    {{localurl:{{{1|a}}}|x=y}} gives /w/index.php?title=A&x=y.
  • {{subst:fullurl:a}} gives http://meta.wikimedia.org/wiki/A.
    {{fullurl:a}} gives http://meta.wikimedia.org/wiki/A.

Corrupted default value

If the value of a parameter of a parser function is given in the parser function call as an expression containing an undefined parameter, then the value taken for that undefined parameter is the value of the parameter with that name of the parser function itself, even ignoring a specified default value, if for the parser function a parameter with that name is defined. Compare this with the case without substitution, where this oddity only occurs if no default value was specified. Names and values of parameters of a parser function call are, starting from the first "|", determined as if it were a template. Thus "names" include implicit names 1, 2, ..; an "=" in a parser function parameter, even if treated by the parser function as plain text, is thus interpreted as separator between name and value; also, while "p|q=3" in a switch is normally interpreted as "p=3|q=3", in this connection it is interpreted as "1=p|q=3", etc. The parameter before the first "|" is not affected, it does not have implicit name "0".

Thus the value of undefined parameters {{{1}}}, {{{2}}}, {{{3}}}, and others used with parser functions is corrupted in a predictable way. Instead of the literal string {{{1}}} the part between first and second "|" vertical bar or pipe in the parser function is used. In other words the second parameter of the parser function is applied as default of {{{1}}}. Similarly, the third parameter of the parser function is applied as default of {{{2}}}, etc. Also the value of a named parameter defined in the parser function call is applied as default value for This is not only a theoretical case, a #switch: can have many parameters. See also bug 5678.

For an unsubstituted inclusion this is generally no serious issue: a parameter is supposed to be used in a template, and if it is not assigned a default value, it is supposed to get a value when the template is called. The exact behaviour where that's not the case is less relevant, though it's anyway erroneous.

Unfortunately with substitution the default values are also corrupted following the same pattern, only defined parameters still work. Some parser functions like ns: support only one parameter and are therefore not affected.

Example:

"{{subst:#if:x|{{{1|a}}}b}}" gives the wikitext "{{{1|a}}}bb" rendered as "abb".

Workaround:

"{{subst:#if:x|{{subst:#ifeq:{{{1|+}}}|{{{1|-}}}|{{{1}}}|a}}b}}" gives the wikitext "ab" rendered as "ab".
{{subst:plural:1|{{{2|singular}}}|error}} gives error.
{{plural:1|{{{2|singular}}}|error}} gives singular,
The subst: error is already visible in a preview before the actual substitution.
{{subst:#ifeq: error|{{{2|-}}}|error|{{{1|no}}}}} gives -.
{{#ifeq: error|{{{2|-}}}|error|{{{1|no}}}}} gives no,
Not equal is correctly concluded, but the else part gives different results.
{{subst:#ifeq: {{{s|+}}}|{{{s|-}}}|{{{s}}}|{{{2|@}}}}} gives {{{s}}}
{{#ifeq: {{{s|+}}}|{{{s|-}}}|{{{s}}}|{{{2|@}}}}} gives @
Same idea, here the {{{s}}} after the 2nd "|" clobbers an undefined {{{2}}}.
{{subst:#ifeq: {{{s|+}}}|{{{s|-}}}|.|o{{{3|ps}}}}} gives oops
The "3rd" (actually fourth) parameter clobbers itself, oops instead of ops.
{{subst:#ifeq: {{{s|+}}}|{{{s|-}}}|.|o{{{4|k}}}|ops}} gives oops
The extraneous "4th" ops corrupted the parameter default k.
{{subst:#ifeq: {{{s|+}}}|{{{s|-}}}|.|o{{{4|k}}}}} gives ok
Without "4th" parameter the specified 4th parameter default k survived.
{{subst:#if:|error|{{{1|void}}}}} gives error.
{{#if:|error|{{{1|void}}}}} gives void.
Similar the word error after the 1st vertical bar overwrites {{{1|void}}}.
{{subst:#ifexpr:0|error|{{{1|zero}}}}} gives error.
{{#ifexpr:0|error|{{{1|zero}}}}} gives zero.
The same issue as before for another parser function.
{{subst:#ifexpr:1|{{{0|okay}}}|-}} gives okay.
{{#ifexpr:1|{{{0|okay}}}|-}} gives okay.
For what's it worth, it doesn't hit an unnamed parameter {{{0}}}.

Because these examples actually substituted the shown code they won't reflect future fixes automatically. For the actual state of the underlying problem without substitution see ParserFunctions/5678.

In the case of #switch: the bug can apply in wild and wonderful ways:
{{#switch:a|a={{{1|c}}}|b={{{1|c}}}}} gives c,
{{#switch:a|a|b={{{1|c}}}}} gives c,
{{#switch:a|a={{{b|0}}}{{{d|0}}}|b=c|d=e}} gives 00, and
{{subst:#switch:a|a={{{1|c}}}|b={{{1|c}}}}} gives c as expected.
However:
{{subst:#switch:a|a|b={{{1|c}}}}} gives a,
{{subst:#switch:a|a={{{b|0}}}{{{d|0}}}|b=c|d=e}} gives ce.
As shown this oddity isn't limited to unnamed parameters {{{1}}} etc., it can also hit named parameters, here {{{b}}} and {{{d}}}.

A similar problem does not occur with regular templates:

{{subst:t2|error|{{{1|void}}} gives start-error-middle-void-end.

Workarounds

As mentioned above, instead of {{{p|q}}} one can use {{{{{subst|}}}#ifeq:{{{p|+}}}|{{{p|-}}}|{{{p}}}|q}}. This way parameter tags with defaults only appear as strings to be compared, and these do not seem to be affected by the bug.

If a switch inside a template is optionally substituted, and a parameter with default inside the switch has a name equal to a listed switch index value, or equal to a positive integer not larger than the number of items, one can either apply the same workaround, or avoid listed switch index values or numbers being equal to names of parameters for which a default is supplied by adding some prefix to the expression for the index and to each of its listed values.

For parameters without default a workaround is less needed because the result in the case a parameter is undefined is of limited use anyway. Such a workaround does not seem possible either, except if the parameter has only a small number of known possible values.

If in

  • {{#ifexpr:p|q|r}}

q and r are numeric expressions, it can be replaced by

  • {{#expr:p*q+(1-p)*r}} (suitable if p is short)
  • {{#expr:q+(1-p)*(r-q)}} (suitable if q is short)
  • {{#expr:p*(q-r)+r}} (suitable if r is short)

(not the same if p is different from 0 and 1), and similarly for #if, #ifexist, and #ifeq.

If r=0 we can simply take

  • {{#expr:p*q}}

Of course, if the expression is inside another expression we do not need another #expr.

Substitution of part of the parameters

Let template A use parameters 1 and 2. Consider creating a template B with one parameter 1, corresponding to A, with a given value q of parameter 2. Compare {{A|2=q}} and {{A|1={{{1}}}|2=q}}. They look the same on the template page, see e.g. Template:T ps, but the first does not work because {{{1}}} is treated as text, not as parameter.

However, with substitution (using "subst:" or Special:Expandtemplates) the resulting wikitext is the same, without distinction between a text {{{1}}} and a parameter, it is a parameter anyway, so "1={{{1}}}" is not needed.

If A contains e.g. #expr with an expression containing both parameters the same applies, except that we can only substitute the highest level (A), not the parser function, so we cannot use Special:Expandtemplates.

This substitution of one parameter can be affected by the bug mentioned below. However, we can then replace e.g. {{{1}}} by {{{1{{{{{substvoid|}}}void}}}}} and do full substitution, except that substvoid is undefined, preventing the bug. This works already correctly with transclusion. Subsequently the result can be substituted with substvoid=subst: so that we get the plain {{{1}}}.

Substituting a parameter and applying a template or parser function sometimes gives the same result as substituting the template or parser function with the triple-braced parameter code and then substituting the parameter.

Examples with equality:

  • A template containing p{{{1}}}q{{{2}}}r substituted with 1=u, 2=v gives puqvr; substituted with 1={{{1}}}, 2=v it gives p{{{1}}}qvr, which itself, substituted with 1=u gives also puqvr.
  • A template containing {{#if:{{{4}}}|{{{3}}}p}} substituted with 3=u, 4=v gives u; substituted with 3={{{3}}}, 4=v it gives {{{3}}}p, which itself, substituted with 3=u gives up.

Examples without equality:

  • A template containing {{{4}}}p substituted with 3=, 4=v gives the empty string; substituted with 3={{{3}}}, 4=v it gives vp, which itself, substituted with 3=u remains vp.
  • A template containing {{#if:{{{2}}}|{{{1}}}p}} substituted with 1=u, 2=v gives up; substituted with 1={{{1}}}, 2=v it gives {{{1}}}pp (the bug), which itself, substituted with 3=u, gives upp.
  • A template containing {{#expr:{{{1}}}*{{{2}}}}} substituted with 1=7, 2=8 gives 56; substituted with 1={{{1}}}, 2=8 it gives <strong class="error">Expression error: Unrecognised punctuation character "{"</strong>, which itself, substituted with 1=7, remains the same.

Documenting substitution

Usage of a template through subst: does not automatically show up in page histories. Therefore providing the line of wikitext containing "subst:" in the edit summary is especially useful.

Also pages with a substituted template do not show up in backlinks, and the template does not appear in the list of transcluded templates on the edit page. The template could add pages to a category to track substitutions, but listing this category on a page may clutter the list of content-based categories the page is in. Also, comments outside noinclude tags are included in the wikitext. Thus a comment can be used to mention the template. It can even contain the values of the parameters, because substitution of parameters works even in comments.

See also

Links to other help pages

Help contents
Meta · Wikinews · Wikipedia · Wikiquote · Wiktionary · Commons: · Wikidata · MediaWiki · Wikibooks · Wikisource · MediaWiki: Manual · Google
Versions of this help page (for other languages see further)
What links here on Meta or from Meta · Wikipedia · MediaWiki
Reading
Go · Search · Namespace · Page name · Section · Backlinks · Redirect · Category · Image page · Special pages · Printable version
Tracking changes
Recent changes (enhanced) | Related changes · Watching pages · Diff · Page history · Edit summary · User contributions · Minor edit · Patrolled edit
Logging in and preferences
Logging in · Preferences
Editing
Starting a new page · Advanced editing · Editing FAQ · Export · Import · Shortcuts · Edit conflict · Page size
Referencing
Links · URL · Interwiki linking · Footnotes
Style and formatting
Wikitext examples · CSS · Reference card · HTML in wikitext · Formula · Lists · Table · Sorting · Colors · Images and file uploads
Fixing mistakes
Show preview · Reverting edits
Advanced functioning
Expansion · Template · Advanced templates · Parser function · Parameter default · Magic words · System message · Substitution · Array · Calculation · Transclusion
Others
Special characters · Renaming (moving) a page · Preparing a page for translation · Talk page · Signatures · Sandbox · Legal issues for editors

Other languages: