Extended template syntax

From Meta, a Wikimedia project coordination wiki
Note: this page is outdated. Some suggestions may still be relevant, but many have been addressed by Help:ParserFunctions.

The new parameterized template feature is very useful. However, it is limited enough that some useful things remain difficult to do. There is currently no simple way of having optional parameters or a variable number of parameters.

(This was first proposed in message substitution. The version there uses the more programming-language-like single word pseudo-namespaces "ifdef" and "foreach", while this version takes advantage of wikitext's support for spaces in URLs and the like to make things more readable)

Basic syntax[edit]

The syntax proposed here is an extention of the {{{parameter}}} parameter inclusion syntax, based on the {{template|parameters}} template transclusion syntax. The various constructs are specified through the use of "pseudo-namespaces": prefixes that look like namespace declarations (ending with a colon) but would be used in triple-braced parameter inclusions where namespaces are not currently used. The conditional inclusion constructs defined here generally follow the pattern {{{construct:parameter|inserted wikitext}}}.

Optional arguments: the "if defined" construct[edit]

It is sometimes the case that a certain field in a template is important enough for inclusion for some articles but not for others. However, no argument may be unspecified when a template is included in an article, or else bits of the template code show through. The only solutions are to either specify the argument in all uses of the template (even in articles where it is irrelevant) or make two separate templates, one with the field and one without. As an example, look at w:Template:Language: the "Regulated by" row in the table is important information for languages with a regulatory academy (like French) but just takes up space in articles for languages that do not. Clearly, this is not ideal.

The if defined: pseudo-namespace would be useful for situations like this. An "if defined" construct would follow this syntax:

{{{if defined:parameter|inserted wikitext}}}

When used in a template, this would insert inserted wikitext only if parameter was specified in the referring article, and nothing otherwise.

Thus, in the language databox template, this code:

{{{if defined:agency|
|-
| valign="top"|Regulated by:
| valign="top"|{{{agency}}} }}}

would result in the "regulated by" table row appearing only if the referring article specified the agency argument.

If no pipe and inserted wikitext were provided, it would insert the value of the parameter:

{{{if defined:parameter}}}

would be the same as {{{if defined:parameter|{{{parameter}}} }}}

This would simplify the syntax for what would probably be a common case.


Variable argument length[edit]

Sometimes it is useful to accept an indefinite number of parameters, and treat them in the same fashion. A (convoluted) example is printf(format,...). What I suggest is a syntax to allow this:

In the template code:

In {{{1}}}, {{{2}}} is true.  See also: [[{{{3}}}]]&&, [[{{{...}}}]]&&.

In the calling article:

{{foo|this case|that|article 1|article 2|article 3}}

Which produces:

In this case, that is true.  See also: [[article 1]], [[article 2]], [[article 3]].

The contents of the && block would be repeated for each parameter that isn't explicitly mentioned (as parameters 1, 2 and 3 are). This can be used for lists, for example, and combined with the if structures suggested elsewhere in this article can lead to complex and powerful templates.

The && block can also be used to iterate through multiple parameters, as an alternative or in addition to the {{{for each:...}}} suggestion below.

Extended conditional syntax[edit]

Further proposals for the branching construct.

Benc's proposal[edit]

A generalized if condition as follows:

{{{if:type|arguments...}}}

The type could be:

  1. defined — the arguments being: parameter-name|replacement-if-true, with the last being optional, meaning the parameter itself if omitted. To conform with equal and contains (below), the parameter-name can optionally be enclosed in triple-braces.
  2. equaltext1|text2|replacement-if-equal — substitute then if text1 and text2 are equal
  3. containshaystack|needle|replacement-if-contained
  4. not (type) — simple boolean negation to emulate else constructs. Elses are not implemented as part of the if construct itself to allow for table markup and other things that use pipes. There's no need to support more than one not (i.e. {{{if:not not defined|parameter}}} is equivalent to {{{if:defined|parameter}}}).

Examples:

  • {{{if:defined|extrainfo|Note: {{{extrainfo}}} }}}
  • The following are equivalent:
    • {{{if:defined|{{{param}}}|{{{param}}}}}}
    • {{{if:defined|param|{{{param}}}}}}
    • {{{if:defined|{{{param}}}}}}
    • {{{if:defined|param}}}
  • {{{if:equal|{{{SERVER}}}|http://en.wikipedia.org/|I'm the Real McCoy}}}
  • {{{if:not equal|{{{SERVER}}}|http://en.wikipedia.org/|I'm a mirror}}}
  • {{{if:contains|{{{text}}}|shit|(WARNING: the following message contains profanity)}}} {{{text}}}
  • {{{if:contains|motherfucker shit cunt|{{{username}}}|(offensive username removed)}}} {{{if:not contains|motherfucker shit cunt|{{{username}}}|{{{username}}} }}}

These would be very useful, and each type could be implemented independantly of the others. This sub-proposal is more robust than its parent, though it still lacks the ability to construct complex boolean expressions (and, or, etc.). Such functionality might very well be more trouble than it's worth.

Gwalla's proposal[edit]

The syntax of a conditional would be {{{if:parameter|options}}} where "if:" is the pseudo-namespace for the conditional, parameter is the template parameter to be compared, and options is one or more pairs of comparison and text to be inserted. The syntax of an option is {condition|inserted text} where condition is one of a set of tests that can be applied to parameter, and inserted text is wikitext to be transcluded if the test is true.

The possible conditions are:

is:value
The text is inserted if the value of parameter is equal to value.
contains:substring
The text is inserted if the value of parameter contains the substring substring. If parameter is a multi-value parameter, the text is inserted if any of the subparameters contain substring.
does not contain:substring
The text is inserted if substring is not in parameter.
in:set
The text is inserted if the value of parameter matches one in set. Set is a cmma-separated list of one or more values or ranges. Ranges are of the form range start--range end, and may be of any type MediaWiki knows how to order (numbers, dates).
undefined
The text is inserted if parameter is undefined (that is, the argument was not provided in the template call). This is the opposite of the "if defined" construct.
else
The text is inserted if parameter doesn't match any preceding condition. This "test" always succeeds if it is reached.

A single if construct may contain several options, which parameter is tested against in order until one succeeds. It therefore behaves more like a switch/case statement than a traditional if/then statement, but the term "if" was chosen because it is more readable to English-speaking nonprogrammers.

An example of an if construct in action:

{{{if:color| {in:red,fuschia,crimson,scarlet|red} {is:blue|blue} {contains:green|green} {undefined|} {else|technicolor} }}}

A template containing this conditional would insert "red" if the color parameter was given as one of a few types of red; "blue" if it was exactly equal to "blue"; "green" if color was "green", "bluegreen" or any other string containing the substring "green"; nothing if the color argument wasn't given; and "technicolor" if the value of color was something unexpected.

AzaToth's proposal[edit]

Because extended template syntax does not need to adhere to normal wiki syntax, it might perhaps be better to have a syntax that is distiguish from normal wiki syntax, and allow a more programmable way to handle the syntax.

Example of proposed syntax (might look lot like perl):

{#
foreach($params) {
  echo "param: $_<br>\n";
}
echo $params['param'];
echo $variables['date'];
call 'Template:Main', $params[2], $params['note'];

if($params['type'] eq 'true' AND ($params['year'] gt 1997 AND $params['year'] lt 2005)) {
  echo "true $params['year']";
} else {
  echo 'false';
}

$tmpvar = $params[3];
$tmpvar ~= s/a/b/g;

#}

Text manipulation[edit]

Another feature would be nice for Wiktionaries. The possibility to strip a suffix/prefix from parameter. Proposed syntax:

{{{subst:in-text|regexp|replacement}}}

This should be as simple as one eregreplace() call in PHP.

Message truncation[edit]

This functionality would be immensely useful for huge multi-part pages like en:WP:VFD. Note that this can be accomplished (messily) using regular expressions, but a cleaner syntax would be preferable.

Proposed syntax: (length is an optional integer parameter, defaulting to 64 (or some arbitrary number) if omitted or if a non-integer is entered)

{{{trunc:in-text|length}}}

The output would simply be the template's normal output, truncated after length characters. A bolded ellipsis (...) linking to the full text would be appended whenever there is text left over after truncation.

The template would have to be parsed before being truncated to avoid situations where there's half of a wikilink (e.g., [[Page nam).

Also, a truncnw mode would be useful, analogous to the difference between msg and msgnw. The template being included and truncated would not be parsed in this case, of course.

Parameters with multiple values[edit]

In some cases a single field in a template may contain a variable number of items. For example, the language databox contains a field for "genetic classification", which contains one or more language family names.

The solution proposed here would allow a parameter name to be used more than once when a template is used in an article. The parameter would be treated as a list or array by the template code. Simply including the parameter in the template code would insert a comma-separated list of the values assigned to that parameter.

Octothope #subscript notation[edit]

Individual elements of a multi-value parameter could be included by using a subscript notation: the parameter name followed by an octothorpe (#) and the index of the element: {{{parameter#index}}}. The numeric indexes could be provided explicitly in the template call, but would otherwise be implicitly assigned based on the order in which the values are given.

So these two template calls:

{{example|param=A|param=B|param=C}}

{{example|param#2=B|param#1=A|param#3=C}}

would both result in {{{param#1}}} being "A", {{{param#2}}} being "B", and {{{param#3}}} being "C".

An argument could also use a named index. The resulting element would be accessible by name ( {{{parameter#indexname}}} ) and by the implicitly assigned numeric index.

Inserting multiple elements: the "for each" construct[edit]

The "for each" pseudo-namespace would be used to insert a bit of wikitext for each element in a multi-valued parameter. The syntax is:

{{{for each:parameter|inserted wikitext}}}

Inside inserted wikitext, {{{#}}} would be replaced with the value of each element in turn. Additionally, equivalently-indexed elements from other multi-valued parameters could be inserted with {{{otherparameter#}}}, allowing multi-valued paramters to be used in pairs.

The "number of" construct[edit]

The "number of" construct is replaced by the number of elements in the given parameter. It would mainly be useful for specifying the rowspan or colspan attributes of table cells so that they can sit next to an arbitrary number of for each-created cells. The syntax is simple: {{{number of:parameter}}}.

Silence Missing Pages[edit]

The transclusion of non-existent templates and pages is now rendered as a link to that template's or page's Edit page. Sometimes it's useful to have nothing rendered instead. A special template keyword of the form:

 {{EXISTS:pagename}}

would return the pagename if it exists, and nothing otherwise. Combining this feature with phaseIII's default-parameter substitution, one could achieve numerous desired results, and without sacrificing simplicity. For instance, using this it would not be hard to change the link title, depending on whether or not the file exists. Using the {{if}} template:

 {{if|test={{EXISTS:newpagename}}|then=[[newpagename|An updated topic]]|else=[[newpagename|Please Add this topic!}}


Conclusion[edit]

The template syntax features proposed above would, admittedly, potentially make some templates more difficult to edit. However, they could also make templates easier to use in articles. As the syntax for coding templates is already somewhat technical and difficult for casual editors, and as articles outside of the Template: namespace are, in general, edited more often than the templates themselves, this seems like a reasonable trade-off.

What do you think, sirs?

Most of the functions listed here are already fairly easily achievable. See Wikipedia's Cateogory for If templates, which offers a fair array of "if defined"'s, "if parameter = value"'s, and so on. These are all achieved with the introduction of being able to put parameters anywhere, including within other parameters. In short, most of the above-described extensions to template syntax aren't required.
Furthermore, templates should never be turned into ways of inserting code or complex functions. Look at the name: template. Templates should ultimately transclude. And templates should ultimately be simple to use. That we are able to do some quite complex things (i.e. If templates) with the very simple {{{parameter|default}}} code is astonishing. But we can. No need to go beyond that simplicity. --131.111.8.104 03:42, 28 February 2006 (UTC)[reply]