GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||
GeezerVison is showing www.mediawiki.org — Manual:Tag extensions - MediaWiki Tag extensions are extensions that extend the built-in wiki markup with Parser extension tags to provide additional capabilities ranging from simple string processing to full-blown information retrieval.
For example, one might want to create a tag extension to introduce a simple Before you start work on a tag extension, you should always check to make sure someone else hasn't done exactly what you are trying to do. Also consider creating a parser function as an alternative to creating a parser tag. A simple tag extension implements a callback function, which is hooked to the parser so that, when the parser runs, it will find and replace all instances of a specific tag, calling the corresponding callback function to render the actual HTML. Example
In extension.json , set up the hooks: ... "Hooks": { "ParserFirstCallInit": "ExampleExtensionHooks" }, "HookHandlers": { "ExampleExtensionHooks": { "class": "MediaWiki\\Extension\\ExampleExtension\\Hooks" } } ... And add the hook into a PHP file <?php namespace MediaWiki\Extension\ExampleExtension; class ExampleExtension implements ParserFirstCallInitHook { // Register any render callbacks with the parser public function onParserFirstCallInit( $parser ) { // When the parser sees the <sample> tag, it executes renderTagSample (see below) $parser->setHook( 'sample', [ $this, 'renderTagSample' ] ); } // Render <sample> public function renderTagSample( $input, array $args, Parser $parser, PPFrame $frame ) { // Nothing exciting here, just escape the user-provided input and throw it back out again (as example) return htmlspecialchars( $input ); } } This example registers a callback function for the
For a more elaborate example, see Tag extension example
AttributesLet's look at another example: <?php $wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit'; function onParserFirstCallInit( Parser $parser ) { $parser->setHook( 'sample', 'wfSampleRender' ); } function wfSampleRender( $input, array $args, Parser $parser, PPFrame $frame ) { $attr = []; // This time, make a list of attributes and their values, and dump them, along with the user input foreach( $args as $name => $value ) { $attr[] = '<strong>' . htmlspecialchars( $name ) . '</strong> = ' . htmlspecialchars( $value ); } return implode( '<br />', $attr ) . "\n\n" . htmlspecialchars( $input ); /** * The following lines can be used to get the variable values directly: * $to = $args['to'] ; * $email = $args['email'] ; */ } This example dumps the attributes passed to the tag, along with their values.
It's quite evident that this allows for flexible specification of new, custom tags.
You might, for example, define a tag extension that allows a user to inject a contact form on their user page, using something like There is a veritable plethora of tag extensions available for MediaWiki, some of which are listed on this site; others can be found via a quick web search. While a number of these are quite specialised for their use case, there are a great deal of well-loved and well-used extensions providing varying degrees of functionality. ConventionsSee Manual:Developing extensions for the general layout and setup of an extension. Publishing your extensions
See also publishing your extension. FAQSecurity concernsYou'll notice above that the input in the examples above is escaped using Loading modulesYour extension should add modules by attaching them to the ParserOutput. The module list will be taken from the ParserOutput object and added to the OutputPage, even when the page rendering is pre-cached. If you are adding the modules directly to the OutputPage they might not be cached in the parser output. public function renderTagSample( $input, array $args, Parser $parser, PPFrame $frame ) { // ... do stuff ... $parser->getOutput()->addModules( 'ext.ExampleExtension' ); $parser->getOutput()->addModuleStyles( 'ext.ExampleExtension.styles' ); // ... do more stuff ... }
Timing and extensionsIf you change the code for an extension, all pages that use the extension will, theoretically, immediately reflect the results of new code. Technically speaking, this means your code is executed each and every time a page containing the extension is rendered. In practice, this is often not the case, due to page caching - either by the MediaWiki software, the browser or by an intermediary proxy or firewall. To bypass MediaWiki's parser cache and ensure a new version of the page is generated, click on edit, replace "action=edit" in the URL shown in the address bar of your browser by "action=purge" and submit the new URL. The page and all templates it references will be regenerated, ignoring all cached data. The purge action is needed if the main page itself is not modified, but the way it must be rendered has changed (the extension was modified, or only a referenced template was modified). If this is not sufficient to get you a fresh copy of the page, you can normally bypass intermediary caches by adding '&rand=somerandomtext' to the end of the above URL. Make sure 'somerandomtext' is different every time. How do I disable caching for pages using my extension?Since MediaWiki 1.5, the parser is passed as the third parameter to an extension. This parser can be used to invalidate the parser cache like this: function wfSampleSomeHookFunction( $text, array $args, Parser $parser, PPFrame $frame ) { $parser->getOutput()->updateCacheExpiry(0); // ... } Regenerating the page when another page is editedMaybe you don't want to disable caching entirely, you just want the page to be regenerated whenever another page is edited, similar to the way that template transclusions are handled.
This can be done using the parser object that is passed to your hook function and calling the
Fine grained adjustment of caching behaviorYou can use fine grained caching for your extension by using cache keys to differentiate between different versions of your extension output. While rendering you can add cache keys for every feature by adding an addExtraKey method to your hook function, e.g.: function wfSampleSomeHookFunction( $text, array $args, Parser $parser, PPFrame $frame ) { $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup(); $setting1= (int)$userOptionsLookup->getOption( $parser->getUserIdentity(), 'setting1' ); $parser->getOptions()->optionUsed( 'setting1' ); $setting2= (int)$userOptionsLookup->getOption( $parser->getUserIdentity(), 'setting2' ); $parser->getOptions()->optionUsed( 'setting2' ); ... } However, modifying $wgHooks['PageRenderingHash'][] = 'wfMyExtOnPageRenderingHash'; function wfMyExtOnPageRenderingHash( &$confstr, $user, $optionsUsed ) { $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup(); if ( in_array( 'setting1', $optionsUsed ) ) { $confstr .= "!setting1=" . $userOptionsLookup->getOption( $user, 'setting1' ); } if ( in_array( 'setting2', $optionsUsed ) ) { $confstr .= "!setting2=" . $userOptionsLookup->getOption( $user, 'setting2' ); } } Some important notes on this:
How do I render wikitext in my extension?Since version 1.16
Parser hook functions are passed a reference to the parser object and a frame object; these should be used to parse wikitext. function wfSampleWonderfulHook( $text, array $args, Parser $parser, PPFrame $frame ) { $output = $parser->recursiveTagParse( $text, $frame ); return '<div class="wonderful">' . $output . '</div>'; }
The second parameter to recursiveTagParse,
However, one step of parsing that is still skipped for tags, even when using recursiveTagParse, is
The original call to preSaveTransform intentionally skips such conversions within all extension tags.
If you need pre save transform to be done, you should consider using a parser function instead.
All tag extensions can also be called as a parser function using How can I pass XML-style parameters in my extension tag?Since version 1.5Since MediaWiki 1.5, XML-style parameters (tag attributes) are supported.
The parameters are passed as the second parameter to the hook function, as an associative array.
The value strings have already had HTML character entities decoded for you, so if you emit them back to HTML, don't forget to use How can I avoid modification of my extension's HTML output?The return value of a tag extension is considered almost parsed text, which means its not treated as pure html, but still modified slightly. There are two main things that are done to the output of a tag extension (Along with a couple other minor things):
Tag extensions also support returning an array instead of just a string (Much like parser functions) in order to change how the return value is interpreted.
The 0th value of the array must be the HTML.
The "markerType" key can be set to How do I get my extension to show up on Special:Version?See Manual:Extension registration and register your extension accordingly. Retrieving the tag name inside of the callbackSuppose you have several tags $wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit'; # ... public function onParserFirstCallInit( Parser $parser ) { $parser->setHook( 'foo', 'sharedFunctionality' ); $parser->setHook( 'bar', 'sharedFunctionality' ); } # ... public function sharedFunctionality( $input, array $args, Parser $parser, PPFrame $frame ) { // How to distinguish between 'foo' and 'bar' calls? } The short answer is: the tag name ( $wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit'; # ... public function onParserFirstCallInit( Parser $parser ) { // For each tag name foreach ( [ 'foo', 'bar' ] as $tagName ) { // Dynamically create a callback function $callback = function( $input, $args, $parser, $frame ) use ( $tagName ) { // The callback invokes the shared function. // Notice we now pass the tag name as a parameter. return sharedFunctionality( $input, $args, $parser, $frame, $tagName ); }; // Assign the callback to the tag $parser->setHook( $tagName, $callback ); } } # ... public function sharedFunctionality( $input, array $args, Parser $parser, PPFrame $frame, $tagName) { // Now we can retrieve the tag name and perform custom actions for that tag switch ( $tagName ) { //... } } Toolbar buttonsExtension:WikiEditor provides an editing toolbar, allowing users to add tags into their editor by simply clicking a button.
If you want a toolbar button for your new tag, create a file named something like var customizeToolbar = function () { $('#wpTextbox1').wikiEditor('addToToolbar', { section: 'main', group: 'format', tools: { "ExtensionName": { // replace with the name of your extension label: 'TagName', // replace with the label that should appear when hoving the button type: 'button', icon: "extensions/ExtensionName/images/button-image.svg", // path to the image that should go on the button action: { type: 'encapsulate', options: { pre: "<tagName>", // tags that get inserted when the button is clicked post: "</tagName>" } } } } }); }; /* Check if view is in edit mode and that the required modules are available. Then, customize the toolbar … */ if ( [ 'edit', 'submit' ].indexOf( mw.config.get( 'wgAction' ) ) !== -1 ) { mw.loader.using( 'user.options' ).then( function () { // This can be the string "0" if the user disabled the preference ([[phab:T54542#555387]]) if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) { $.when( mw.loader.using( 'ext.wikiEditor' ), $.ready ).then( customizeToolbar ); } } ); } Further details about customizing this file can be found here.
Once you've created the file, you need to register it with ResourceLoader so it will be delivered to visitors; this is done by editing your "Hooks": { "BeforePageDisplay": "ExtensionName::onBeforePageDisplay" } "ResourceModules": { "ext.ExtensionName": { "scripts": ["toolbarButton.js"] } } Then, in your PHP file: public static function onBeforePageDisplay( OutputPage $out ) { $out->addModules( [ 'ext.ExtensionName' ] ); } See also
| ||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |