Parser function for content model {{#contentmodel:}}
Closed, ResolvedPublicFeature

Description

Feature summary

There should be a parser function for the content model of a page.
Suggestion: {{#contentmodel:}}.

A standard Wikitext page would return Wikitext. Other content types could not return the variable within the page itself, but this variable could be used in wikitext-based system messages; so a JavaScript page returns JavaScript, a CSS page returns CSS, etc. This info can be used to trigger switches.

This would not affect caching, given that content model changes are rare.

The way this has now been implemented is as follows:

  • {{#contentmodel:canonical}} returns the canonical content model (in English)
  • {{#contentmodel:local}} returns the local name of the content model.

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

@Bugreporter2 Could you please give a example on how this could be used?

Examples of the system messages I mentioned earlier would include, for example:

[[Mediawiki:editinginterface]] which could be changed depending on content model. For example 'you are editing a CSS page, etc'

Another one: [[Mediawiki:ns-tab]] could say something different for different content models, like 'user CSS page'.

Or [[Mediawiki: sitenotice]] could display something based on content model. [[Mediawiki:copyrights]] can also be used as a page-bottom general element, with switches (I know it's not intended as such, but it can be used that way).

There is also the potential for its use in things like custom toolbars, if and when that happens, and they are wikitext-based. Just one extra building block towards that.

Some notes:

"Magic Variables" are defined in <code>\includes\parser\CoreMagicVariables.php</code>

The following lines of code need to be added to an appropriate place. The second one with the e on the end is to return <code>plain_text</code> (with an underscore) rather than <code>plain text</code> (with a space character):

<pre>

			case 'contentmodel':
			case 'contentmodele':

</pre>

There is an array called <code>$wgContentHandlers</code> which should contain these four values:

<pre>
CONTENT_MODEL_CSS
CONTENT_MODEL_JSON
CONTENT_MODEL_UNKNOWN
CONTENT_MODEL_WIKITEXT
</pre>

And may have others added to it; in particular there's one for "Sanitized CSS" and possibly another one called JavaScript (though JSON=JavaScript, potentially. It's confusing.)

Now then, if matches, then output...

Does this help anyone?

Bugreporter2 renamed this task from ParserFunctions variable for content model to Magic word variable for content model {{CONTENTMODEL}}.Nov 7 2023, 7:07 AM
Aklapper lowered the priority of this task from Medium to Low.Nov 14 2023, 8:59 AM

@Bugreporter2: A good first task is a self-contained, non-controversial task with a clear approach. It should be well-described with pointers to help a completely new contributor. Given the current short task description I'm removing the good first task tag. Please add details what exactly has to happen where and how for a new contributor, and then add back the good first task project tag. Thanks a lot in advance!

Some notes:

"Magic Variables" are defined in <code>\includes\parser\CoreMagicVariables.php</code>

This is a file in MW core, yet this task has the ParserFunctions tag, which is for the extension. I don't think this magic word makes a lot of sense in Extension:ParserFunctions, in my opinion this task should have some tag for MW Core instead.

Yes, I think you are right @SomeRandomDeveloper I have updated the task description.

I still think this is a straightforward task that is a suitable "first task." Are you interested in taking on the challenge?

image.png (365×978 px, 61 KB)

image.png (263×995 px, 36 KB)

Managed to add the magic word. Since there are no content model names in core that need to be url-encoded, I switched my language to a different one with characters that actually need to be encoded to test it:

image.png (139×967 px, 29 KB)

Change #1094385 had a related patch set uploaded (by SomeRandomDeveloper; author: SomeRandomDeveloper):

[mediawiki/core@master] Add {{CONTENTMODEL}} and {{CONTENTMODELE}} magic words

https://gerrit.wikimedia.org/r/1094385

Content model is available via Lua. I don't see a point in this proliferation of magic words which we should be moving away from. Gerrit patch even includes some discussion on four new magic words – CONTENTMODEL, CONTEMODELE, CONTENTMODELID, CONTENTMODELIDE – which is the exactly the kind of madness prevented by using Lua which provides a structured and intuitive way to access such data.

Content model is available via Lua. I don't see a point in this proliferation of magic words which we should be moving away from. Gerrit patch even includes some discussion on four new magic words – CONTENTMODEL, CONTEMODELE, CONTENTMODELID, CONTENTMODELIDE – which is the exactly the kind of madness prevented by using Lua which provides a structured and intuitive way to access such data.

{{CONTENTMODELIDE}} would be redundant, as discussed on Gerrit.
Scribunto seems to provide the content model id ("Scribunto", "wikitext", "css", "javascript") but not the translated version, which would primarily be useful for non-English languages which use different words/characters. If you'd want to display the current content model e.g. in a system message as shown in T328254#10347646, you'd need to have a scribunto module that provides a translated version for the id of each content model. So in my opinion while whether we need {{CONTENTMODELID}} (which is currently not included in the patchset) is debatable, {{CONTENTMODEL}} and {{CONTENTMODELE}} would be useful and more simple than having hardcoded translations in a lua module. I also don't think it's a good idea to execute lua for system messages like Mediawiki:Editinginterface due to the overhead it produces.

While it seems there's no cleaner way, it can be done without hardcoding translations, by reading the i18n message content-model-$model where $model is the lowercased model id (T358341). For example, mw.message.new('content-model-' .. string.lower( mw.title.getCurrentTitle().contentModel ) ):plain().

I also don't think it's a good idea to execute lua for system messages like Mediawiki:Editinginterface due to the overhead it produces.

Do you have any profiling that indicates this is a problem?

While it seems there's no cleaner way, it can be done without hardcoding translations, by reading the i18n message content-model-$model where $model is the lowercased model id (T358341). For example, mw.message.new('content-model-' .. string.lower( mw.title.getCurrentTitle().contentModel ) ):plain().

You could apply this to many other magic words like {{FULLPAGENAME}}, {{NAMESPACE}} and a lot more, yet those exist and are used over their lua equivalent as well.

Do you have any profiling that indicates this is a problem?

Not directly, this is stated at https://en.wikibooks.org/wiki/Scribunto:_An_Introduction/When_to_convert_a_template (which was written by someone who had created a ton of modules for wikipedia). Also considering that scribunto uses the same function to get the content model and the value first has to go through lua before it is printed out it would not make a lot of sense to be faster.

Those magic words predate the creation of Scribunto.

I didn't mean to say that Lua will be faster, just that a negligible loss of performance doesn't seem to warrant the costs of adding new magic words.

Good comments and interesting discussion.

I understand the argument for using Lua. I think the best thing to do is to get some implementation of this that works. So, an implementation of this via a template at https://en.wikipedia.org/wiki/Template:CONTENTMODEL referencing https://en.wikipedia.org/wiki/Module:Content_model would likely work equally well in practice as the magic word solution.

The main argument against this is that Lua is not part of MediaWiki Core, and some third party wikis might not have Lua installed, or enabled, because reasons. And if it's not included, should references to a template be included in the standard system messages? I would suggest probably not. As it is, third party wikis have to spend time copy-pasting a lot of modules and templates to get the same functionality as Wikipedia takes for granted.

And also someone would need to write the template and module, if you go down that route.

SomeRandomDeveloper renamed this task from Magic word variable for content model {{CONTENTMODEL}} to Parser function for content model {{#contentmodel:}}.Jul 2 2025, 12:49 PM
SomeRandomDeveloper updated the task description. (Show Details)

Updated the patch and the task to use a parser function instead of a magic word, per https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1094385/comments/1ace2918_1991367c

My reasoning for including this as part of core is so that it can be used in system messages.

Change #1094385 merged by jenkins-bot:

[mediawiki/core@master] Add {{#contentmodel}} parser function

https://gerrit.wikimedia.org/r/1094385

For Tech News: How would you suggest describing this in an entry? Is there any documentation to link to? Will this be available immediately on Monday, or during the week with the deployment train? Thanks. [Note: I may postpone until the following week's edition, especially if it's a train-deployed feature, so that editors can start using it immediately upon learning about it. Plus potentially to give time for good docs to be written!]

For Tech News: How would you suggest describing this in an entry?

The new parser function {{#contentmodel}} has been added. It returns either the localized or the canonical name of the content model of a specific page. The function is primarily intended for use in system messages, such as Mediawiki:editinginterface, and in switches.

Is there any documentation to link to?

Not yet, it should probably be added to https://www.mediawiki.org/wiki/Help:Magic_words, which I might do in the next days when I have time to (unless somebody else does before me)

Will this be available immediately on Monday, or during the week with the deployment train?

I assume it will go out with the train just like any other patch.

For Tech News: How would you suggest describing this in an entry?

The new parser function {{#contentmodel}} has been added. It returns either the localized or the canonical name of the content model of a specific page. The function is primarily intended for use in system messages, such as Mediawiki:editinginterface, and in switches.

Thanks! I've tweaked and added that at https://meta.wikimedia.org/wiki/Tech/News/2025/38

Is there any documentation to link to?

Not yet, it should probably be added to https://www.mediawiki.org/wiki/Help:Magic_words, which I might do in the next days when I have time to (unless somebody else does before me)

Sounds good.
Note, Re: "either the localized or the canonical name" - I assume those options(?) will be clarified in the docs, and thus don't need context in the Tech News entry.
Plus, please update the first link in the Tech News draft, if/when there's better #anchor to link to. Thanks again!

From the source code, I think to get the canonical name, you need {{#contentmodel:canonical}}

Great addition. So, the usage is {{#contentmodel:|<pagename>? Why the parameters are not in opposite order?

Great addition. So, the usage is {{#contentmodel:|<pagename>? Why the parameters are not in opposite order?

This way it's possible to get the canonical name of the content model of the current page without specifying the page name. If the order was reversed, the name of the page would always have to be specified (and an empty string as the page name causes the Title to be null and therefore the function would output an empty string)

I see. So, maybe better to have two magic words, contentmodel and contentmodelc for canonical.

I see. So, maybe better to have two magic words, contentmodel and contentmodelc for canonical.

That was the initial plan, but having one parser function with arguments is preferred over having multiple magic words (see the comment on gerrit and T204370)

A pity. Straight ":|" is a very bad syntax, IMHO.

I think the assumption was that this is primarily for getting the contentmodel of the current page for localized system messages where {{#contentmodel}} would be the expected thing, and maybe {{#contentmodel:canonical}} would be used in a switch.

But before this gets deployed and used would also be a prime opportunity to swap the arguments if that seems preferable. There are a number of parser functions/magic variables for which a missing first argument is interpreted as "the current title", like {{PAGENAME}}, {{PAGEID}} etc. So it would be fine for {{#contentmodel}} to fit into that pattern, but as @SomeRandomDeveloper pointed out {{#contentmodel:|canonical}} wouldn't work in that case, since it would be parsed as an empty-string title, not a "missing argument", and so you'd have to use {{#contentmodel:{{PAGENAME}}|canonical}} to get the canonical form of the current page.

Also worth noting as a matter of style with the current argument order you'd probably want to use {{#contentmodel:local|Some Page Title}} not {{#contentmodel:|Some Page Title}}. The parsing just wants an argument here which is not canonical but it's better form to use an argument which specifies what you want (the localized form). We could probably enforce that if we really wanted to, and have {{#contentmodel:|Some Page Title}} (aka an "unknown format option") return an error or the empty string.

as well as {{#contentmodel||canonical}} (assuming T204371 eventually lands).

Did you mean {{#contentmodel:|canonical}}?

as well as {{#contentmodel||canonical}} (assuming T204371 eventually lands).

Did you mean {{#contentmodel:|canonical}}?

Sorry, I'd gotten myself mixed up and had to edit my comment. You're just too fast at reading phab. :)

Change #1187091 had a related patch set uploaded (by C. Scott Ananian; author: C. Scott Ananian):

[mediawiki/core@master] CoreParserFunctions: enforce validity of first argument to {{#contentmodel}}

https://gerrit.wikimedia.org/r/1187091

Note that it's probably OK to set up {{CONTENTMODEL}} and {{CONTENTMODELC}} as templates that call this function:

For Tech News timing, I believe the ongoing discussion/patches here are an indicator that we should postpone announcing it. I.e. until the feature is stable, and has documentation that we can link it to. If nobody replies by tomorrow, then I will move the draft-entry into the following week's edition, so that translators don't waste some of their time if it needs to be rewritten. [EDIT: Now moved.] Thanks!
For content, the current draft is:

  • A new parser function has been added: {{#contentmodel}}. It returns either the localized name or the canonical name of the content model of a specific page. The function is primarily intended for use in system messages, such as Mediawiki: editing interface, and in switches. [5]

which I hope we can make clearer by more clearly describing (or giving an example of?) the use-cases, plus a better #section-link for the first link once it's been documented there. Thanks!

Change #1187091 merged by jenkins-bot:

[mediawiki/core@master] CoreParserFunctions: enforce validity of first argument to {{#contentmodel}}

https://gerrit.wikimedia.org/r/1187091

Hello @cscott is this ready to be announced now? I have moved this to be announced next Tech/News since I am not sure if it is ready. If it should be announced in this current one, please let me know. Thank you!

I've added the parser function to the page on mediawiki.org: https://www.mediawiki.org/wiki/Help:Magic_words#Technical_metadata_of_another_page .
Additionally, I've updated the tech news draft to provide more information on the parameters.

Since the concern raised above has been fixed (thanks @cscott!), IMO this should be ready to announce next week.

I've added the parser function to the page on mediawiki.org: https://www.mediawiki.org/wiki/Help:Magic_words#Technical_metadata_of_another_page .
Additionally, I've updated the tech news draft to provide more information on the parameters.

Since the concern raised above has been fixed (thanks @cscott!), IMO this should be ready to announce next week.

Thank you, @SomeRandomDeveloper. I edited the entry to clarify who can use it and its value. Please feel free to make further edits if anything is missing.

Is it intentional that this is a non-expensive parser function?

Previously getting the content model (for pages other than the current page) incremented the expensive parser function count in lua. Calling $title->getContentModel() can result in a database query.

This comment was removed by Bawolff.

Change #1191011 had a related patch set uploaded (by SomeRandomDeveloper; author: SomeRandomDeveloper):

[mediawiki/core@master] CoreParserFunctions: Make {{#contentmodel}} expensive

https://gerrit.wikimedia.org/r/1191011

Change #1191011 merged by jenkins-bot:

[mediawiki/core@master] CoreParserFunctions: Make {{#contentmodel}} expensive

https://gerrit.wikimedia.org/r/1191011

Hello! I'm having trouble creating the aawiki database in train-dev using install.php from the wmf/1.45.0-wmf.20 branch.

$ php php-1.45.0-wmf.20/maintenance/install.php aawiki admin --pass secret --dbserver db --dbname aawiki --dbuser wikiuser --dbpass password
PHP 8.1.33 is installed.
ICU 67.1 is installed (supports Unicode 13.0.0).
Found GD graphics library built-in. Image thumbnailing will be enabled if you enable uploads.
Git version control software not found. You can ignore this for now. Note Special:Version will not display commit hashes.
Using server name "http://localhost".
Using server URL "http://localhost/php-1.45.0-wmf.20".
Warning: Your default directory for uploads (/srv/mediawiki-staging/php-1.45.0-wmf.20/images/) is not checked for vulnerability to arbitrary script execution during the CLI install.
Warning: Because of a connection error, it was not possibly to verify that images in your uploads directory, respond with the HTTP header X-Content-Type-Options: nosniff to protect browsers from potentially unsafe files. It is highly recommended to configure appropriate response headers on your webserver before enabling uploads.
The environment has been checked. You can install MediaWiki.
Including extensions... done
Setting up database... done
Creating tables... Warning: MediaWiki tables seem to already exist. Skipping creation.
done
Initializing statistics... done
Populating default interwiki table... Warning: The interwiki table seems to already have entries. Skipping default list.
done
Prevent running unneeded updates... done
Restoring MediaWiki services... UnexpectedValueException from line 105 of /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/parser/MagicWord.php: Error: invalid magic word 'contentmodel'
#0 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/parser/MagicWordFactory.php(178): MediaWiki\Parser\MagicWord->load('contentmodel')
#1 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/parser/Parser.php(5063): MediaWiki\Parser\MagicWordFactory->get('contentmodel')
#2 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/parser/CoreParserFunctions.php(135): MediaWiki\Parser\Parser->setFunctionHook('contentmodel', Array, 1)
#3 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/parser/Parser.php(470): MediaWiki\Parser\CoreParserFunctions::register(Object(MediaWiki\Parser\Parser), Object(MediaWiki\Config\ServiceOptions))
#4 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/parser/ParserFactory.php(234): MediaWiki\Parser\Parser->__construct(Object(MediaWiki\Config\ServiceOptions), Object(MediaWiki\Parser\MagicWordFactory), Object(LanguageEn), Object(MediaWiki\Utils\UrlUtils), Object(MediaWiki\SpecialPage\SpecialPageFactory), Object(MediaWiki\Linker\LinkRendererFactory), Object(MediaWiki\Title\NamespaceInfo), Object(MediaWiki\Logger\LegacyLogger), Object(MediaWiki\Page\File\BadFileLookup), Object(MediaWiki\Language\LanguageConverterFactory), Object(MediaWiki\Language\LanguageNameUtils), Object(MediaWiki\HookContainer\HookContainer), Object(MediaWiki\Tidy\RemexDriver), Object(Wikimedia\ObjectCache\WANObjectCache), Object(MediaWiki\User\Options\UserOptionsManager), Object(MediaWiki\User\UserFactory), Object(MediaWiki\Title\TitleFormatter), Object(MediaWiki\Http\HttpRequestFactory), Object(MediaWiki\Category\TrackingCategories), Object(MediaWiki\Preferences\SignatureValidatorFactory), Object(MediaWiki\User\UserNameUtils))
#5 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/language/MessageParser.php(249): MediaWiki\Parser\ParserFactory->create()
#6 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/language/MessageParser.php(121): MediaWiki\Language\MessageParser->acquireParser()
#7 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/language/Message/Message.php(1510): MediaWiki\Language\MessageParser->parse('done', Object(MediaWiki\Page\PageReferenceValue), true, true, Object(LanguageEn))
#8 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/language/Message/Message.php(1086): MediaWiki\Message\Message->parseText('done')
#9 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/language/Message/Message.php(1138): MediaWiki\Message\Message->format('parse')
#10 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/installer/CliInstaller.php(310): MediaWiki\Message\Message->parse()
#11 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/installer/CliInstaller.php(302): MediaWiki\Installer\CliInstaller->formatMessage(Object(MediaWiki\Message\Message))
#12 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/installer/CliInstaller.php(271): MediaWiki\Installer\CliInstaller->getMessageText('config-install-...', Array)
#13 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/installer/CliInstaller.php(262): MediaWiki\Installer\CliInstaller->showMessage('config-install-...')
#14 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/installer/Task/TaskRunner.php(159): MediaWiki\Installer\CliInstaller->endStage(Object(MediaWiki\Installer\Task\RestoredServicesProvider), Object(MediaWiki\Status\Status))
#15 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/installer/Task/TaskRunner.php(52): MediaWiki\Installer\Task\TaskRunner->runTask(Object(MediaWiki\Installer\Task\RestoredServicesProvider))
#16 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/installer/Installer.php(1478): MediaWiki\Installer\Task\TaskRunner->execute()
#17 /srv/mediawiki-staging/php-1.45.0-wmf.20/includes/installer/CliInstaller.php(228): MediaWiki\Installer\Installer->performInstallation(Object(Closure), Object(Closure))
#18 /srv/mediawiki-staging/php-1.45.0-wmf.20/maintenance/install.php(221): MediaWiki\Installer\CliInstaller->execute()
#19 /srv/mediawiki-staging/php-1.45.0-wmf.20/maintenance/includes/MaintenanceRunner.php(696): CommandLineInstaller->execute()
#20 /srv/mediawiki-staging/php-1.45.0-wmf.20/maintenance/doMaintenance.php(102): MediaWiki\Maintenance\MaintenanceRunner->run()
#21 /srv/mediawiki-staging/php-1.45.0-wmf.20/maintenance/install.php(292): require_once('/srv/mediawiki-...')
#22 {main}

Since the error message mentions contentmodel a few times, and this ticket shows recent activity in this area, I thought I'd ask for help here. Can anyone tell what's going on?

Since the error message mentions contentmodel a few times, and this ticket shows recent activity in this area, I thought I'd ask for help here. Can anyone tell what's going on?

Might this be because the magic word is set up as {{#lowercase}} rather than being {{ALLCAPS}}?

Since the error message mentions contentmodel a few times, and this ticket shows recent activity in this area, I thought I'd ask for help here. Can anyone tell what's going on?

I've seen this error before multiple times for other magic words, and it usually was caused by an outdated localisation cache

Since the error message mentions contentmodel a few times, and this ticket shows recent activity in this area, I thought I'd ask for help here. Can anyone tell what's going on?

I've seen this error before multiple times for other magic words, and it usually was caused by an outdated localisation cache

As an experiment I deleted the l10n cache and recreated it.

debian@deploy:/srv/mediawiki-staging/php-1.45.0-wmf.20/cache/l10n$ sudo rm -f *
debian@deploy:/srv/mediawiki-staging/php-1.45.0-wmf.20/cache/l10n$ scap mwscript --user www-data rebuildLocalisationCache.php --wiki=aawiki --lang en --store-class LCStoreCDB
Rebuilding en...
1 languages rebuilt out of 1
debian@deploy:/srv/mediawiki-staging/php-1.45.0-wmf.20/cache/l10n$ ls -l
total 5748
-rw-r--r-- 1 www-data deployment 5885810 Oct  4 15:20 l10n_cache-en.cdb

However, the attempt to create the aawiki database still fails in the same way.

Perhaps this isn't the best place for this conversation...

Yes that error message means there is something wrong with your localization cache. If you're running install.php, I would expect it is not using WMF style localization cache since that's non-default and install.php would only be using defaults, so its not surprising rebuildLocalisationCache.php didn't do anything - its rebuilding a different localization cache than the one in use. My go to suggestions (these are gueses so YMMV) would be: double check that your git checkout is clean and all the language files are correct, manually clear apc cache, If the DB you are creating already exists (which the error message says it does), truncate the l10n_cache table (Does kind of beg the question of why are you trying to create a database that already exists?).

Perhaps this isn't the best place for this conversation...

Yes that error message means there is something wrong with your localization cache. If you're running install.php, I would expect it is not using WMF style localization cache since that's non-default and install.php would only be using defaults, so its not surprising rebuildLocalisationCache.php didn't do anything - its rebuilding a different localization cache than the one in use.

That makes sense.

If the DB you are creating already exists (which the error message says it does), truncate the l10n_cache table

That did the trick. Thank you!

(Does kind of beg the question of why are you trying to create a database that already exists?).

That's a reasonable question. :-) The answer is that the approach of re-running install.php has worked fine in train-dev since 2020. This made it easy to write a re-runnable script to ensure that all the necessary dbs are created. If you're curious, this is the script: https://gitlab.wikimedia.org/repos/releng/train-dev/-/blob/main/exp/files/deploy/scripts/create-databases?ref_type=heads.

I assume this can be closed now that the parser function has been available for everyone to use for a while.