Manual:Special pages

There are various ways to make special pages, but the one below is used by the bulk of official extensions, and adherence to this style is necessary for acceptance to the MediaWiki SVN.

Basic special page template
Most special pages require three files: a small setup file, which will be loaded every time MediaWiki starts, an internationalisation file, and a file with the bulk of your code. All of them should be placed in a new directory inside the MediaWiki extensions directory. The setup file will typically be named after your extension, and looks like this:



This stub file registers three important things: the location of the MyExtension class, the new special page and its class name, and a LoadAllMessages hook which will be explained later.

The body file MyExtension.body.php will contain a subclass of SpecialPage. It will be loaded automatically when your special page is requested. In this example, we have called this subclass MyExtension. It will look like this:

setHeaders;

# Get request data from, e.g.		$param = $wgRequest->getText('param'); # Do stuff ...

# Output $wgOut->addHTML( $output ); }

function loadMessages { static $messagesLoaded = false; global $wgMessageCache; if ( $messagesLoaded ) return; $messagesLoaded = true;

require( dirname( __FILE__ ) . '/MyExtension.i18n.php' ); foreach ( $allMessages as $lang => $langMessages ) { $wgMessageCache->addMessages( $langMessages, $lang ); }	} } ?>

"execute" is a fixed function name that has to be used. The function overloads the function SpecialPage::execute. It passes a single parameter $par, the subpage component of the current title. For example, if someone follows a link to Special:MyExtension/blah, $par will contain "blah". MyExtension::loadMessages is a bit complicated at present, hopefully it will become easier in future versions of MediaWiki. It loads an internationalisation file (MyExtension.i18n.php), which provides an array of messages. It then puts these messages into the cache. This function was called from the LoadAllMessages in our stub file, MyExtension.php, so that MediaWiki can find all messages and present them to translators.

MyExtension.i18n.php will give any snippets of text (i.e. messages) you use, ultimately translated into multiple languages. There is one very important message which all special pages must define: the special page description. This will appear on Special:Specialpages, and in the title and h1 elements of your special page.

''There seems to be a bug, the description seems available on the special page itself only, not on Special:Specialpages, where we get , or on Special:Allmessages, where we get a PHP warning, except if the description is defined in the page concerned in the MediaWiki namespace. As a temporary fix, comment out the line with $wgHooks and add to the setup file:''

$wgExtensionFunctions[] = 'myspecialpagesetup';

function myspecialpagesetup { global $wgMessageCache; $wgMessageCache->addMessage('myextension', 'My Extension'); }

''repeating the description (page title) also specified as mentioned below. Alternatively, use a global array $wgMyExtensionMessages like ExpandTemplates does.''

The name of this message is the name of your special page, converted to lower case.

So here's what our minimal i18n file will look like:

 array( 'myextension' => 'My Extension' ) ); ?>

It defines the English (en) version of the myextension message to be equal to "My Extension".

It is convenient if the English page title is the same as the ID. Note however that the ID should not start with an uppercase letter, and that a space in the ID should be written in the code as un underscore. For the page header and linking the usual rules for page names apply: if $wgCapitalLinks is true, a lowercase letter is converted to uppercase, and an underscore is displayed as a space. Example: instead of the above we use 'my_extension' => 'My extension'.

Basic special page template (2 file version)
This simplified version works for MW 1.10, other versions not checked.

The following two files are ment to copy-and-paste for your extension. You may want to change Gunter to your name or an even better description.

This is your file "GuntersExtension.php" containing the inclusion in Special:SpecialPages and the extension functionality.

 This is the ExpandTemplates extension. To enable it, put &lt;pre>require_once("$IP/extensions/GuntersExtension/GuntersExtension.php");&lt;/pre> at the bottom of your LocalSettings.php  'Special:GuntersExtension',        'description' => 'adds a special page for Gunter',        'url' => 'http://www.wikimedia.org/wiki/Extension:Gunter',        'author' => 'Gunter',        'version' => $Ext_Version );

require_once "$IP/includes/SpecialPage.php"; require_once( dirname( __FILE__ ) . '/GuntersExtension.i18n.php' );
 * 1) Internationalisation file

function wfGuntersExtensionStart { global $wgMessageCache, $ExtensionTitles;

// Load messages, so we have a title in Special:SpecialPages foreach ( $ExtensionTitles as $lang => $langMessages ) { $wgMessageCache->addMessages( $langMessages, $lang ); }	SpecialPage::addPage(new GuntersExtensionPage); }

class GuntersExtensionPage extends SpecialPage {       function GuntersExtensionPage { SpecialPage::SpecialPage('GuntersExtension' ); }

function execute( $par ) { global $wgRequest, $wgOut;

self::loadMessages; $this->setHeaders;

#$wgOut->setPagetitle("Gunters Extension"); // not necessary if you do not want a different title than in Special:Specialpages # Get request data from, e.g.               $param = $wgRequest->getText('param'); # Do stuff $wgOut->addWikiText( "" . wfMsg( 'intro' ) . "" );

# Output $wgOut->addHTML( $output ); }

function loadMessages { static $messagesLoaded = false; global $wgMessageCache, $allMessages; if ( $messagesLoaded ) return; $messagesLoaded = false;

foreach ( $allMessages as $lang => $langMessages ) { $wgMessageCache->addMessages( $langMessages, $lang ); }       } }

?>

Here is your internationalization file, save it as "GuntersExtension.i18n.php". I split the title and text messages, so the translators kind of see what they change.

 array( 'guntersextension' => 'Gunters Extension Title' ),        'de' => array( 'guntersextension' => 'Gunters Erweiterung Titel' ), );

$allMessages = array(       'en' => array( 'intro'          => 'This special page ...', ),       'de' => array( 'intro'          => 'Diese Spezialseite ...', ) );

?>

Constructor
You can overload the constructor to initialise your own data, but the main reason you would want to do it is to change the behaviour of the SpecialPage class itself. When you call the base class constructor from your child class, the following parameters are available:

 function SpecialPage( $name = , $restriction = , $listed = true, $function = false, $file = 'default', $includable = false )


 * string $name Name of the special page, as seen in links and URLs
 * string $restriction User right required, e.g. "block" or "delete"
 * boolean $listed Whether the page is listed in Special:Specialpages
 * string $function Function called by execute. By default it is constructed from $name
 * string $file File which is included by execute. It is also constructed from $name by default
 * boolean $includable Whether the special page can be included from other pages using

SpecialPage::setHeaders
This initialises the OutputPage object $wgOut with the name and description of your special page. It should always be called from your execute method.

SpecialPage::including
This returns a boolean value telling you what context the special page is being called from: false if it is a separate web page, and true if it is being included from within another web page. Usually you will want to strip down the presentation somewhat if the page is being included.

Including from another web page is only possible if you declared the page to be includable in the constructor.

SpecialPage::execute
This is the function which your child class should overload. It passes a single parameter, usually referred to cryptically as $par. This parameter is the subpage component of the current title. For example, if someone follows a link to Special:MyExtension/blah, $par will contain "blah".

OutputPage $wgOut
The global variable  is the variable you will use the most, because it is the way to send output to the browser (no, you don't use   or  ). If you want to use it somewhere, declare the variable global:

function randomFunction { global $wgOut; $wgOut->addHTML('This is not very random...'); }

$wgOut contains an OutputPage object, which you can inspect by viewing  (indeed, all of these can be inspected), but there are a few methods you should definitely know about.

OutputPage::addHTML
Essentially the quick and dirty substitute for. It takes your input and adds it to the buffer: no questions asked. In the below action, if  contains user-data, it could easily have XSS, evil stuff, or the spawn of Satan injected in. You're better off using escaping or the XML builders class to build trusted output.

$wgOut->addHTML('<form action="'.$action.'" method="post">');

OutputPage::addWikiText
For most output, you should be using this function. It's a bit of a black magic function: wikitext goes in, HTML comes out, and a whole lotta of arcane code and demon summonings happen in between.

$wgOut->addWikiText("This is some lovely wikitext that will get parsed nicely.");

What's worth noting is that the parser will view your chunks as cohesive wholes and paragraph accordingly. That is...

$wgOut->addWikiText('* Item 1'); $wgOut->addWikiText('* Item 2'); $wgOut->addWikiText('* Item 3');

Will output three lists with one item each, which probably wasn't intended.

wfMsg
In most of the real special pages, you will rarely see  without   popping in. is MediaWiki's way of internationalization (i18n). An example:

$wgOut->addWikiText( wfMsg( 'flubbersuccess' ) );

looks up the system message called, and then returns it. The actual text of the message can come from a variety of places. Find out more about how to tell MediaWiki what to output in MessageCache.

OutputPage::errorpage
Obsoleted by showErrorPage

OutputPage::showErrorPage
An error page is shown. The arguments $title and $msg specify keys into wfMsg, not text. An example: $wgOut->showErrorPage('error','badarticleerror');
 * 'error' refers to the text "Error".
 * 'badarticleerror' refers to the text "This action cannot be performed on this page.".

MessageCache $wgMessageCache
MessageCache is a class that will figure out what the string corresponding to the key you give it. In most circumstances, they will come from these places, with the overriding one on the bottom:


 * 1) Default language file
 * 2) Added on extension strings
 * 3) The MediaWiki namespace

The default language file is all the stuff that comes bundled with Wikipedia. Since we're writing extensions, and we're implementing new functionality, this isn't very useful. Next is extension strings.

MessageCache::addMessages
MessageCache::addMessages is usually used for adding messages for extensions, and they are internally marked as such. The syntax is very simple:

function addMessages( $messages )

Where $messages is an array that looks like:

array (   'key1' => 'Value 1'   ,'key2' => 'Value 2' )

Whatever your key was, you can get the value using. This allows MediaWiki to pass a customized string from a page in the MediaWiki database, specifically MediaWiki:Key.

Title of your extension
NOTE: You use the $wgOut to title your extension like: $wgOut->setPagetitle("your title");

MediaWiki does not set the title of your extension: that is your job. It will look for the name of your extension when Special:Specialpages is called or you actually load the special page (specifically right before your registered wfSpecial* function is called).

I have come to the conclusion that the best place to define the name of your special page is right before it gets registered using. You definitely should not call it inside the actual function (whether it be an overloaded SpecialPage::execute or your wfSpecial* function): SpecialPages will never find out about it! (besides the fact that you will have to SpecialPage::setHeaders again).

The place where your extension can be found, as specified by what you pass into the SpecialPage constructor, is the key, except that it is not capitalized. This is because, the internally used function that finds out the title (or, what they call description) of the special page,   the name. "ThisIsACoolSpecialPage"'s key would be "thisisacoolspecialpage."

You can, theoretically, overload getDescription in order to avoid interacting with the message cache, but, as the source code states: "Derived classes can override this, but usually it is easier to keep the default behaviour. Messages can be added at run-time, see MessageCache.php". Furthermore, this prevents the MediaWiki namespace from overloading the message, as below.

MediaWiki namespace
So you've just installed a shiny new MediaWiki extension and realize: "Oh no, my wiki is in French, but the page is showing up as English!" Most people wouldn't care, but it's actually a quite simple task to fix (as long as the developer used the method explained on this page). No noodling around in source code. Let's say the name of the page is  and the name comes out to "List of Dirty Pages" but you want it to be (and excuse my poor French) "Liste de Pages Sales". Well, it's as simple as this:


 * 1) Navigate to MediaWiki:DirtyPages, this page may not exist, but edit it anyway
 * 2) Insert "Liste de Pages Sales" and save

And voilà (pardon the pun), the change is applied.

This is also useful for customizing the title for your wiki within your language: for instance, the developer called it "List of Dirty Pages" but you don't like that name, so you rename it "List of Pages needing Cleanup".

But even further: this is a sound bit of advice that applies to every single message that uses MessageCache, ones that are core and ones added by extensions. Check out Special:Allmessages to learn more.

This means that if your extension has a large block of text, don't directly output it using wgOut, instead, add it to the message cache, and then when the time comes, do:

$wgOut->addHTML( wfMsg( 'dirtypageshelp' ) );

Then this message too can be customized at MediaWiki:Dirtypageshelp.

See also Help:System messages.

WebRequest $wgRequest
The WebRequest class is used to obtain information from the GET and POST arrays. Using this is recommended over directly accessing the superglobals, since the object does fun stuff like magic_quotes cleaning.

WebRequest::wasPosted
NOTE: Don't access this statically like it implies by the title, create an instance first.

Database
MediaWiki has a load of convenience functions and wrappers for interacting with the database. It also has an interesting load balancing scheme in place. It's recommended you use these wrappers. Check out  for a complete listing of all the convenience functions, because these docs will only tell you about the non-obvious caveats.

wfGetDB
As this name suggests, this function gets you a reference of the database. There is no global that contains a database object.

When you call the function, you should pass it a parameter, the constant  or. Generally, you interact with the slave database when you're only performing read operations, and interact with the master when you're writing to the database. It's real easy to do, so do it, even if you only have one database.

User $wgUser
The User class is used to represent users on the system. The global  represents the currently logged in user, and is usually what you will deal with when manipulating users.

Title
Title represents the name of a page in the wiki. This is useful because MediaWiki does all sorts of fun escaping and special case logic to page names, so instead of rolling your own convert title to URL function, you create a Title object with your page name, and then use escapeLocalURL to get a URL to that page.