Help talk:Extension:ParserFunctions

About this board

May214 (talkcontribs)

I'm working with the #if statement inside a cargo_query statement, and the #ifs are not parsing. I tested outside of the cargo_query, and still not working. See example here

After the If Testing header, you can see the #if not parsing - just printing to screen as if regular wiki text. What am I doing wrong? The template with the #if testing is Repertoire. Link to the template page here

May214 (talkcontribs)

Never Mind. The problem was in LocalSettings. It's working

Reply to "#if not working?"
Dandorid (talkcontribs)

It took me a while to figure out why my Template:IPaddr broke when I moved a {{lc:}} that encompassed the whole template to somewhere deep within, where it was actually needed. Instead of {{lc: [template contents]}} I wrote just {{lc:{{{1|}}}}}, as only the first anonymous argument needed lower case substitution. At first glance this code is perfectly right and it worked like a charm. However, when used to display the IPv6 loopback address ('::1') the working of the template collapsed, as the wikicode generated a <dl><dd></dd>...</dl> sequence!

Using {{lc:<nowiki>{{{1|}}}</nowiki>}} seems to stop the interpretation of {{{1}}}, or even {{lc:<nowiki></nowiki>{{{1|}}}}}, but I am wondering if there is a nicer way to tell {{lc:}} not to interpret the argument if it starts with a colon.

Verdy p (talkcontribs)

Why not using {{lc:<nowiki/>{{{1|}}}}} ?

Internally the empty <nowiki/> tag is first replaced before preprocessing the wikitext, by a special marker (delimited by a pair of reserved ASCII controls forbidden in valid HTML, but containing an identifier which is not case-sensitive 'the identifier is referencing the hidden content of the nowiki tag, but here it is empty): this should prevent the interpretation of the next colon following this stripped marker as being part of the "lc:" syntax for calling the builtin parser function or as being part of a namespace prefix, so this colon (at start of the value of the IPv6 address coming from the expanded value of parameter {{{1|}}}) will be passed verbatim to the builtin function (the builting function will also receive the special marker, it may eventually decide to drop it).

Later that special stripped marker will be stripped when the final HTML is tidied (at end of the template/functions expansion phase), if the builtin function has not already stripped it in its return value from its input parameter (some parser functions first strip their parameters, for example removing leading/trailing spaces or stripped markers; others don't and preserve them (but this may have suprising results in some parser functions, notably those extracting substrings or computing string lengths, if they are not aware of the possible presence of stripped markers, which should be either kept entirely or removed completely, but not subdivided; the same remark applies to invokations of Lua functions stored in Scribunto modules, but it is less visible, given the fact that function invokations start by #invoke: which is immediately followed by a module name that cannot start by a colon, then follwed by a vertical bar and the function name which also cannot start with a colon, and all other optional function parameters are prefixed by a single vertical bar).

If this still does not work, maybe a workaround would be to invoke a Lua function invokation (instead of a wiki template transclusion) to process the IPv6 address (it may be even more efficient, as it has many subtle complexities due to its variable allowed format, if you want to transform it into canonical form).

Note also that an IPv6 address starting by :: may also be written by prefixing it with 0:: instead (so ::1 and 0::1 are both valid and equivalent): this 0:: prefix in IPv6 is currently only used in IPv6 for some local link addresses and only the least significant 64-bit part (in fact only 32-bit in almost all existing implementations) may have an host address part (there's no other assignment in the 0::/16 IPv6 address block).

Note also that there exists two "canonical forms" for IPv6 addresses: one where only the first sequence of /(0{1,4}:)+/ 16-bit fields is replaced by "::" and all other occurences of /0{1,4}:/ are replaced by "0:"; the other one removes any occurence of "::" and insert the necessary number of "0:" fields to match the expected 128-bit length of IPv6 (i.e. with eight 16-bit fields). There cannot be two occurences of "::" in the same IPv6 adress specification. As well, both canonical forms effectively have its letter case unified (for its ASCII hexadecimal digits, generally to lowercase). Some applications also do not compress leading zeroes in each 16-bit field, to use instead a fixed format so that a fields starts by 2, 3 or 4 zeroes, but usually the compressed form without duplicate leading zeroes in fields, and where the first sequence of zero fields separated by ":" is cleared to exhibit a remaining "::" is the most widely used, as it is easier to read

For internal processing this formatting generally does not matter, all is performed internally in protocol frame formats using 128-bit binary fields, not binary... except for IPv6 addresses between square brackets when they are used as hostnames in URLs: because URLs are indexed also for domain names, canonicalization of the string form is necessary and usually uses the most compact format, even if this does not change the protocol for DNS queries, or for reverse IPv6 DNS lookups which uses a very different "backward" dotted format, grouping hexadecimal digits one by one and not by group of four... with an exception for a small range of IPv6 addresses that are designed for "compatibility" to be strictly equivalent to IPv4 addresses: in that case the reverse IPv6 DNS lookup "fallbacks" at the final least significant 32-bit part, to use reverse IPv4 lookup byte by byte, but modern DNS implementations do not need such fallback and can also reverse lookup in that space without using any special delegation: this IPV4 address is already reindexed inside IPv6 by internet gateways for routing and delegation announcements; but if your DNS provider does not handle this small IPv6 space, the fallback to IPv4 queries still works in that subspace and will work for long and in practice its is rarely used by final clients which for now all uses a dual stack, it is only used by IPv6-only clients but generally immediately handled by the router of their upstream ISP or DNS provider, as well modern OSes all have support for this specific ccompatiblity space in their existing IPV6 implementation when performing IPV4 lookup via an IPV6 connection, either with UDP, or TCP, or the new secure HTTP proxying protocol aka "DOH").

Other forms are not using strings, but just binary representation, unsigned 128-bit integer values, or an ordered pair of unsigned 64-bit integer values, or an ordered vector of sixteen unsigned 8-bit bytes: this is generally used for internal purpose, such as indices and the efficient implementation of filters/routers/firewalls, to internally compress their database and faster processing, but it is of course also the format on which it is used in the core IPv6 protocol itself.

Note also that if the IP address was already preprocessed once using {{lc:}} in a template, and the template result is then passed as a parameter value to another template, you may have dififculty to pass this value if you don't use again another empty nowiki tag to prefix this value. You should also not embed the IPv6 address inside a nowiki tag. Stripped markers for empty wiki tags are also normally constant in all occurences as their content value is also a constant empty string and so these markers use the same internal reference identifier (MediaWiki may also optimize internally these constants and reduce automatically sequences of empty nowiki markers to a single one; the internal form of this marker is implementation dependant but does not matter, what only matters is the presence of the pair of leading/trailing forbidden controls to surround them).

Dandorid (talkcontribs)

Thanks for this elaborate answer. I think that your proposed solution is a valid one. I have, for the moment, settled for putting a <span> inside it, which also works.

Your explanation about IPv6 addresses is correct, but the point is that we need to describe exactly that on the Wiki page for IPv6 addresses. Therefore, the IPaddr template needs to take any form (full, shortened, valid or even invalid, as the text may be) and still try to display it like an IP address. It is not likely that this template would be called from another template, as it is a markup template used directly in the written text. But anyway it is good to know that these issues with {{lc:}} exists, so I can be vigilant.

Matěj Suchánek (talkcontribs)

Sounds like another interesting case of phab:T14974. I think no way of avoiding it will be nice.

Reply to "Using {{lc:}} in templates"
Lhoussine AIT TAYFST (talkcontribs)

Hi all,

I'm one of the admins of Recently, I want to insert the amazigh date on this project according to the Berber calendar

I'm here to ask about adding this calendar in the function #time.

Thank you a lot

Reply to "Amazigh date"

use the output of {{Special:Editcount/User}} in #expr

Plasmarelais (talkcontribs)

Hi all, thanks for having an eye this: I want to use the output of Special:Editcount/User in #expr to calculate something. But of course the output is handled a string, even if I split it into its figures with #sub. So how can I make it being recognized as int? Any idea? Thank you in advance! --~~~~

Jrooksjr (talkcontribs)

{{Special:Editcount/Jrooksjr}} output should be interger! At, least on Fandom it is!

I see it is not turned on on MediaWiki though!

Reply to "use the output of {{Special:Editcount/User}} in #expr"

#ifexist for a "real" article

GhostInTheMachine (talkcontribs)

Is there any way to test for the article being a "real" one -- i.e. not being a redirect? ~~~~

Tacsipacsi (talkcontribs)

I don’t think it’s possible using ParserFunctions. However, if you have Scribunto installed (on Wikimedia projects it’s installed), you can use it, as its mw.title objects’ properties include isRedirect.

RobinHood70 (talkcontribs)
Dinoguy1000 (talkcontribs)

That template uses wikipedia:Module:Redirect, which itself uses the isRedirect property. It's a convenient packaging if you're just looking for the functionality and don't want to spend time writing something yourself, but if you aren't able to use Lua modules it won't help you.

RobinHood70 (talkcontribs)

Oh, I didn't look closely enough. I saw other checks there and just figured there was some trickery going on. My mistake.

Reply to "#ifexist for a "real" article"

Time, timel not compatible with MediaWiki timestamp (?)

Summary by Valerio Bozzolan

Cannot reproduce. It just works.

Valerio Bozzolan (talkcontribs)

It seems that both #time and #timel do not support MediaWiki's timestamp format.

That's strange from my perspective. People may want to do something like:

{{#time: Y m d | {{REVISIONTIMESTAMP}} }}

How do you usually do such a thing? I mean, applying a custom format to a {{REVISIONTIMESTAMP}} (20210703010617). I have a way in mind but it's pretty complicated and unreadable without a template or Lua.

Dinoguy1000 (talkcontribs)

This seems to work fine to me. For example, {{REVISIONTIMESTAMP}} here currently returns 20210703011745, and {{#time: Y m d | {{REVISIONTIMESTAMP}} }} results in 2021 07 03.

Valerio Bozzolan (talkcontribs)

I absolutely don't know why now it works also for me. Thank you and my apologies.

Jonteemil (talkcontribs)


{{#ifeq: string 1 | string 2 | value if identical | value if different }}

Can you make /value if not identical/ render /string 1/?

MarMi wiki (talkcontribs)

{{#ifeq: string 1 | string 2 | value if identical | string 1 }}?

Dinoguy1000 (talkcontribs)

If you mean without repeating yourself, there's no straightforward way without using other extensions. The obvious suggestion is Extension:Scribunto , though this does require you to be able to code in Lua; the one I'm personally much more familiar/comfortable with is Extension:Variables , though it's unfortunately basically unmaintained, and parser changes in future MW versions may break it at some point.

Reply to "#ifeq question"
DavidL (talkcontribs)

The #sub function doesn't work on sites where ParserFunctions is enabled. --  David L  discuter ► 19:02, 23 March 2021 (UTC)

MarMi wiki (talkcontribs)

Only #sub? And on what sites? #sub is from the Extension:StringFunctions.

Edit: Oh, it was integrated into Extension:ParserFunctions. Does those sites have it enabled in config ($wgPFEnableStringFunctions; if other string functions works, then they have)?

DavidL (talkcontribs)
MarMi wiki (talkcontribs)

Integrated functions from StringFunctions needs to be enabled in config in order to work, read the extension pages. I'm guessing that after enabling, they should also appear on the parser functions list (at the bottom of the Special:Version).

Edit: They indeed appear on that function list:, where that extension is enabled by default (Per-wiki settings for Wikimedia wikis from, search for wmgPFEnableStringFunctions).

Since on your wikis there is no "sub" function, then most likely that extension isn't enabled. And judging by, it most likely wont be enabled.

Dinoguy1000 (talkcontribs)

The mentioned wikis are both WMF wikis, and StringFunctions will never be enabled on WMF wikis. The recommended alternative is Lua via Scribunto.

Pppery (talkcontribs)
DavidL (talkcontribs)

If the module is not enabled, it should not appear in Special:Version, or at least there should be a column indicating the module status (enabled or disabled). I found another solution to use in my template, copied from Thanks for replies.

Dinoguy1000 (talkcontribs)

ParserFunctions is enabled on these wikis (you'll note that the functions #if and #expr, among others, work just fine); however, the StringFunctions components of the extension (including #sub) are behind a configuration flag, which is not enabled on WMF wikis.

Reply to "#sub doesn't work"

explode, limit parameter, ... ???

Summary by MvGulik

Explains and shows how explode works.

MvGulik (talkcontribs)

Doc: "{{#explode:string|delimiter|position|limit}}"

OK. Seems simple enough.

Doc: "The limit parameter is available in ParserFunctions only, not the standalone StringFunctions version,"

OK, checked.
So far so good.

Doc: "..., and allows you to limit the number of parts returned, ..."

That's what I'm looking for.

Doc: "..., with all remaining text included in the final part."

??? Come again.
If its "including all remaining text" in the "final result". What's the point of that limiter value?

O well, lets just see how it actually works.

  • explode: "{{#explode:aaa bbb ccc ddd eee fff| |2|2}}"
  • Looking for: "ccc ddd eee"
  • Returns: "" (ie: empty string)

Wtf ???

MediaWiki: 1.31.0
ParserFunctions: 1.6.0

Clump (talkcontribs)

I interpret the limit parameter to be a count, while the position is an index. So if you say divide it into at most 2 pieces and then ask for the 3rd piece (index 2) then you get an empty string. Try {{#explode:aaa bbb ccc ddd eee fff| |2|3}} instead.

Dinoguy1000 (talkcontribs)

If you have a wiki with string functions enabled and Extension:Arrays handy, try the following code:

{{ #arraydefine: pos | 0,1,2,3,4,5,6,7 }}
{{ #arraydefine: lim | 0,1,2,3,4,5,6,7 }}
<table class="wikitable">
    <th>Pos →<br />Lim ↓</th>
{{ #arrayprint: pos || $pos | <th>$pos</th> }}
{{ #arrayprint: lim || $lim | <nowiki/>
{{ #arrayprint: pos || $pos | <td>"{{ #explode: aaa bbb ccc ddd eee fff || $pos | $lim }}"</td> }}

It results in the following table (provided for those who don't have access to Ext:Arrays):

0 "aaa""bbb""ccc""ddd""eee""fff"""""
1 "aaa bbb ccc ddd eee fff"""""""""""""""
2 "aaa""bbb ccc ddd eee fff"""""""""""""
3 "aaa""bbb""ccc ddd eee fff"""""""""""
4 "aaa""bbb""ccc""ddd eee fff"""""""""
5 "aaa""bbb""ccc""ddd""eee fff"""""""
6 "aaa""bbb""ccc""ddd""eee""fff"""""
7 "aaa""bbb""ccc""ddd""eee""fff"""""

Based on this, I don't really understand what the limit parameter is doing, but it doesn't strike me as particularly useful (and it definitely doesn't behave as I'd expect from documentation that says it "allows you to limit the number of parts returned").

MvGulik (talkcontribs)

Thanks (both).

I see it now. (also vaguely remembering having run into this a long time ago)
The limiter part is uses to control the initial splitting of the source string.
(that also means a direct "ccc ddd eee" output in this example case is not possible, ... with one single #explode that is.)

The doc page definitely seems in need of some adjusting on this. Although it is giving some hints towards how it actual works, its not very clear or none-ambiguous on this part in my view.

Definitely going to look into requesting the Extension:Arrays to be added to the wiki I'm running around in. (very nice table btw)

#switch doesn't work with #while

Gunnar.offel (talkcontribs)

i tried to use a #while and deside by #switch how the reply would be.

in meta-code

       | i < count
       | i++
          | 1 = 
          | count = 
          | #default = 

So, not work isn't exactly right, it works for the first run, all other runs are empty. i solved it now by several #ifeq - compares. Is it a wanted behavior?

Dinoguy1000 (talkcontribs)

#while is not added by Extension:ParserFunctions; I don't know what extension adds it. Looking at your code, and knowing how while loops operate in general, though, I wonder if you didn't forget a pipe before the #switch:

       | i < count
       | i++
       | {{#switch:
          | 1 = 
          | count = 
          | #default = 
Gunnar.offel (talkcontribs)

The code was just to illustrate in which way i wanted do use.

No, the third pipe isn't correct, the #while has just a head and the instructions. i set the increment as first to get sure, that the loop terminates correctly. #while comes with the extension loops. i posted it here, since it works as said with #ifeq-compares.

I just wanted to get more information how it works. i could swear if i divide it in two pages it would works flawless (calling the secound page like a function). To look more in the philosophy may it be, that the #switch is set late in the page generation, so the loop couldn't generate properly?

Dinoguy1000 (talkcontribs)

I don't know any of the specifics of how/when #switch parsing happens, and I don't have any experience at all with the #while parser function (as you might have guessed when I incorrectly suggested you were missing a pipe in it). At this point, all I can offer is to experiment until you find something that works, and maybe file a bug report for constructions that you think should work, but don't currently (you would do this wherever the #while extension's issues are tracked, and if necessary mark your report(s) as belonging to that extension). I can at least say that it's unlikely any changes will be made to #switch or the other Ext:ParserFunctions functions to make them play nicely with #while, unless the cause of the issues is an actual bug in them that needs to be fixed for other reasons (but if you believe the cause is a bug in them, I'd encourage you to file a bug report anyways, especially if you can come up with a demonstration that only uses extensions enabled on WMF wikis).

Reply to "#switch doesn't work with #while"