Manual:Special pages
From MediaWiki.org
| Tag Extensions | Parser Functions | Hooks | Special Pages | Skins | Magic Words |
Special pages are pages that are created by the software on demand to perform a specific function. For example, a special page might show all pages that have one or more links to an external site or it might create a form providing user submitted feedback. Special pages are located in their own namespace (Special:) and are not editable directly like other pages. Developers can also create new special pages. These pages can be user-accessible and will generally show up in the list of all special pages at Special:Allpages. Some special pages are only accessible to users with certain permissions and accesses. Other special pages don't show up on the special page list at all and are only used by the wiki internally.
Contents |
[edit] General Information
All of the ~70 built-in special pages that come with MediaWiki are called SpecialSomename.php and are located in the includes directory. Special pages created by third party developers are generally stored in the extensions directory in their own file or as part of a larger extension. All special pages inherit from a class called SpecialPage which is defined in SpecialPage.php. When a new special page is created, the user rights needed to access the page can be defined. These rights specify, among other things, whether the page will show up on Special:Specialpages and whether the page is includable in other pages.
Special pages also have unique names that can be customized on a wiki. The general form is "Special:Pagename" where both "Special" and "Pagename" are customizable. The Special pseudo namespace can be translated in other languages. This translated namespace can be produced with the wikitext {{ns:special}}, on this wiki giving "Special". The name of the special page can also be redefined in a system message, for the site language, with the generic name of the special page as the ID.
A special page may or may not allow input. For example, Special:Export allows a user to define a specific page to export by calling Special:Export/Sun. If the special page allows complex input, additional parameters will be sent to the query string component of the the URL for processing, e.g. http://www.mediawiki.org/w/index.php?title=Special:Recentchanges&days=3&limit=250.
Notes:
- 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 recommended. Also, be sure to include a credits block in the new special page for 'specialpage'. See $wgExtensionCredits for more details.
- After making a new special page, be sure to add it to Category:Special page extensions so other people can find it.
- It should be pointed out that the method used below will not work on PHP 4: it depends on "class autoloading" which was introduced with PHP 5. Special pages written in this style are therefore not necessarily compatible with MediaWiki prior to version 1.7.0: if using an earlier version of MediaWiki on a more-recent version of PHP, upgrade MediaWiki.
[edit] Basic special page template
Most special pages require three files: a small setup file, which will be loaded every time MediaWiki starts, an internationalization file, and a file with the bulk of the code. All of them should be placed in a new directory inside the MediaWiki extensions/ directory. MediaWiki coding conventions define the three files like this:
<special_page_name>.php- The setup file.<special_page_name>.i18n.php- The internationalization file.<special_page_name>_body.php- The special page code.
In the example below, <special_page_name> is MyExtension. A working copy is available for download, see further down.
[edit] The Setup File
The setup file looks like this:
<?php # Alert the user that this is not a valid entry point to MediaWiki if they try to access the skin file directly. if (!defined('MEDIAWIKI')) { echo <<<EOT To install my extension, put the following line in LocalSettings.php: require_once( "$IP/extensions/MyExtension/MyExtension.php" ); EOT; exit( 1 ); } $dir = dirname(__FILE__) . '/'; $wgAutoloadClasses['MyExtension'] = $dir . 'MyExtension_body.php'; # Tell MediaWiki to load the extension body. $wgExtensionMessagesFiles['MyExtension'] = $dir . 'MyExtension.i18n.php'; $wgSpecialPages['MyExtension'] = 'MyExtension'; # Let MediaWiki know about your new special page. $wgHooks['LanguageGetSpecialPageAliases'][] = 'myExtensionLocalizedPageName'; # Add any aliases for the special page. function myExtensionLocalizedPageName(&$specialPageArray, $code) { # The localized title of the special page is among the messages of the extension: wfLoadExtensionMessages('MyExtension'); $text = wfMsg('myextension'); # Convert from title in text form to DBKey and put it into the alias array: $title = Title::newFromText($text); $specialPageArray['MyExtension'][] = $title->getDBKey(); return true; }
This stub file registers four important things:
- The location of the MyExtension class
- The location of a messages file
- The new special page and its class name
- A LanguageGetSpecialPageAliases hook to register an alias for the special page. This alias might be a translation of the page title to another language. Although thanks to the LoadAllMessages hook, the page title can be customized into another language, the URL of the page would still be something like .../Special:Myextension, even when the user language is not English. To fix this,
myExtensionLocalizedPageNameregisters an alias so the page becomes accessible via .../Special:My_extension eg. .../Spezial:Meine_Erweiterung in German, and so on.
[edit] The Body File
The body file MyExtension_body.php will contain a subclass of SpecialPage. It will be loaded automatically when the special page is requested. In this example, the subclass MyExtension is called:
<?php class MyExtension extends SpecialPage { function MyExtension() { SpecialPage::SpecialPage("MyExtension"); wfLoadExtensionMessages('MyExtension'); } function execute( $par ) { global $wgRequest, $wgOut; $this->setHeaders(); # Get request data from, e.g. $param = $wgRequest->getText('param'); # Do stuff # ... # Output # $wgOut->addHTML( $output ); } }
execute() is the main function that is called when a special page is accessed. 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".
wfLoadExtensionsMessages('MyExtension') loads the messages defined in the message file that was given in MyExtension.php and that will be explained in the next section.
Note: If you create an execute function like the example above, none of the Special Page hooks (Hooks/SpecialPageExecuteBeforePage, Hooks/SpecialPageExecuteAfterPage, and Hooks/SpecialPageExecuteBeforeHeader) will be called. This can cause problems for other extensions that rely on these hooks. To get around this problem, you can do something like this:
<?php function efRunMyExtension( $par ) { MyExtension::run( $par ); } class MyExtension extends SpecialPage { function MyExtension() { SpecialPage::SpecialPage("MyExtension", '', true, 'efRunMyExtension'); wfLoadExtensionMessages('MyExtension'); } function run( $par ) { # Do stuff # ... } }
If you use this method, you don't have to call setHeaders() or check userCanExecute() as those functions will be called automatically by the SpecialPage execute() function. On the other hand, you can't not call those functions if you don't need them.
[edit] The Messages File
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 the special page. The name of this message is the name of the special page converted to lower case.
With this description, the near-minimal messages file will look like this:
<?php $messages = array(); $messages['en'] = array( 'myextension' => 'My Extension' ); $messages['de'] = array( 'myextension' => 'Meine Erweiterung' );
It defines the English (en) version of the myextension message to be equal to "My Extension". Of course, you can add versions of your messages in other languages; in this example we also have German (de).
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 an 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'.
A version of this example without the localized page name alias has been tested, and is checked in to MediaWiki SVN in examples/ThreeFileTemplate.
[edit] Other Important Files
[edit] SpecialPage.php
[edit] Constructor
You can overload the constructor to initialize your own data, but the main reason you would want to do it is to change the behavior 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
$nameName of the special page, as seen in links and URLs - string
$restrictionUser right required, e.g. "block" or "delete" - boolean
$listedWhether the page is listed in Special:Specialpages - string
$functionA global function to call at run time if your subclass doesn't override execute(). By default it is constructed from $name as "wfSpecial$name". - string
$fileFile which is included by execute(). It is also constructed from $name by default - boolean
$includableWhether the special page can be included from other pages using {{Special:...}}
[edit] 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.
[edit] 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. You can do this by adding the following in the __construct() method after the parent class initalization:
$this->mIncludable = true;
[edit] 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".
[edit] OutputPage.php
The global variable $wgOut is the variable you will use the most, because it is the way to send output to the browser (no, you don't use echo or print). If you want to use it somewhere, declare the variable global:
function randomFunction() { global $wgOut; $wgOut->addHTML('<b>This is not very random...</b>'); }
You can inspect the OutputPage object by viewing includes/OutputPage.php (indeed, all of these can be inspected), but there are a few methods you should definitely know about.
[edit] OutputPage->addHTML()
Essentially the quick and dirty substitute for echo. It takes your input and adds it to the buffer: no questions asked. In the below action, if $action 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">');
[edit] 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 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.
WARNING: If your special page is intended to be included in other pages, you should probably not use addWikiText(). Due to what seems to be a bug in MediaWiki, an included special page will mess up any inclusion before it on the same including page, showing just strings like UNIQ10842e596cbb71da. As a workaround, you can have your extensions convert Wikitext to HTML using a separate Parser object and then use addHTML(). Example:
$wgOut->addHTML(sandboxParse("Here's some '''formated''' text."));
function sandboxParse($wikiText) { global $wgTitle, $wgUser; $myParser = new Parser(); $myParserOptions = new ParserOptions(); $myParserOptions->initialiseFromUser($wgUser); $result = $myParser->parse($wikiText, $wgTitle, $myParserOptions); return $result->getText(); }
[edit] wfMsg()
In most of the real special pages, you will rarely see $wgOut->addWikitext() without wfMsg() popping in.
wfMsg() is a MediaWiki internationalization (i18n) function. See wfMsg() for more information.
[edit] 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.".
[edit] MessageCache.php
MessageCache is a class that will turn messages into the value defined in the wiki for that value. See m:Help:System message for more information. In most circumstances, system messages will come from one of these places, in increasing order of importance:
- The default language file
- Messages defined in extension internationalization files
- 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. Messages are accessible from extensions by including the global $wgMessageCache in the page.
[edit] 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 the key was, its value can be retrieved using wfMsg('key'). This allows MediaWiki to pass a customized string from a page in the MediaWiki database, specifically MediaWiki:Key.
[edit] WebRequest.php
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. The WebRequest object is accessible from extensions by including the global $wgRequest in the code.
[edit] WebRequest->getVal($key)
Returns a string that corresponds to the form input with the name $key.
[edit] WebRequest->get*()
Returns an int, bool, etc depending on the function called. For checkboxes for example, the function getBool is useful.
[edit] WebRequest->wasPosted()
Returns true if a form was posted.
[edit] Database.php
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 Database.php for a complete listing of all the convenience functions, because these docs will only tell you about the non-obvious caveats.
[edit] 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 DB_MASTER or DB_SLAVE. 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.
[edit] User.php
The User class is used to represent users on the system. The global $wgUser represents the currently logged in user, and is usually what you will deal with when manipulating users.
[edit] User->isAllowed($right)
Returns true or false depending on whether the user is allowed to do $right.
[edit] User->isBlocked()
Returns true if a user is blocked.
[edit] Title.php
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.
[edit] Title::makeTitle()
[edit] Title->escapeLocalURL()
[edit] FAQ
[edit] Setting an Extension Title
MediaWiki does not set the title of the extension, which is the developer's job. It will look for the name of the extension when Special:Specialpages is called or the special page is loaded (specifically right before the registered wfSpecial*() function is called). Use $wgOut to title the extension like: $wgOut->setPagetitle("your title");
The place where the extension can be found (as specified by what is passed into the SpecialPage constructor) is the key--except that it is not capitalized because of getDescription(), the internally used function that finds out the title (or, what they call description) of the special page, strtolower the name. "ThisIsACoolSpecialPage"'s key would be "thisisacoolspecialpage."
Theoretically, getDescription can be overloaded 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 behavior. Messages can be added at run-time--see MessageCache.php". Furthermore, this prevents the MediaWiki namespace from overloading the message, as below.
[edit] Localizing the Extension Name
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 DirtyPages 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:
- Navigate to MediaWiki:DirtyPages, this page may not exist, but edit it anyway
- 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". Check out Special:Allmessages to learn more.
Also, if your extension has a large block of text that does change, like a warning, don't directly output the text. Instead, add it to the message cache and when the time comes to output the text in your code, do this:
$wgOut->addHTML( wfMsg( 'dirtypageshelp' ) );
Then this message too can be customized at MediaWiki:Dirtypageshelp.
See also Help:System messages.

