Manual:Skinning Part 2

From MediaWiki.org
Jump to: navigation, search

If you're a person who prefers learning from examples, a basic skin built according to this guide exists. See Skin:Example for details and downloads.

Skin basics and file structure[edit]

Introduction[edit]

Let's start with the skin name – we'll call ours "Foo Bar" for tutorial purposes – and the blank files. You should come up with a name of your own for your skin.

When building a skin you'll be working with your skin name in two forms (and a half):

  • The localized skin name is displayed to wiki users in their preferences, where they can choose the skin to use. It may contain anything whatsoever, including spaces, and may be translated into other languages. It should be used as the name of skin description page here on MediaWiki.org if you decide to create one.
  • The skin name, usually CamelCased, is used as a part of the names of PHP classes used by the skin. It may only contain Latin letters and numbers (A-Z, a-z, 0-9)..
    • The lowercase skin name, identical to the skin name but lower cased, it is used for names of site-wide and user CSS/JS customization pages, for the name of the localization message used to define the localized skin name, and internally as value of the 'skin' user preference, parameter &useskin=, and identifier for the skin in JS and CSS requests.

In our example skin, these are, respectively, "Foo Bar", FooBar and foobar.

The name of the subdirectory under skins/ where your skin will be placed should be equal to either the skin name or its lowercase version (this guide uses the CamelCase skin name). The same name should also be used for the main .php file of the skin (see below) and as the name of the repository if you put the skin in version control.

Wherever we use "Foo Bar", FooBar or foobar in examples, remember to replace those with the name of your own skin.

The Example skin[edit]

To start building your skin, download or clone the Example skin (browse its source code) to a new directory in your skins/ folder, in our case skins/FooBar/.

Boilerplate and definitions[edit]

For this tutorial you should have the following blank files and empty subdirectories to start with. If you are using non-ANSI characters, ensure that the files are coded with UTF-8 (without BOM).

  • skins/FooBar/skin.json: the entry point containing metadata and definitions of resources used by your skin. This filename be exactly this or the MediaWiki engine cannot load your skin.
    • Before MediaWiki 1.25, the entry point was defined in skins/FooBar/FooBar.php
  • skins/FooBar/FooBar.skin.php: will contain the actual skin code.
  • skins/FooBar/i18n/: directory for localisation messages and their translations.

Starting with MediaWiki 1.25, it is possible to define the boilerplate in JSON format. This is the recommended way for skins compatible with only newer MediaWiki versions. The older PHP way is currently still supported, but deprecated. See Manual:Extension registration for details and migration guide.

Start with the documentation header.

MediaWiki 1.25 and later (supporting extension registration)

skin.json

MediaWiki 1.24 and older

FooBar.skin.php

Not added to skin.json
<?php
/**
 * Foo Bar skin
 *
 * @file
 * @ingroup Skins
 * @author Daniel Friesen (http://www.mediawiki.org/wiki/User:Dantman)
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 */
// Continue adding the code below
// ...

The practice of including this metadata can help with documentation generation. The @file and @ingroup are organizational and should be left as-is, while you'll want to customize the @author and @license to what's correct for your skin. You can note the typical practice for each is @author Name (URL) or @author Name (email@example.com) and @license URL name. For MediaWiki 1.25 and later, the skin.json file is already machine-readable.

Like extensions you may want to include a quick bit of boilerplate to prevent running standalone and credits so when installed people know who authored your skin:

MediaWiki 1.25 and later (supporting extension registration)

skin.json

MediaWiki 1.24 and older

FooBar.skin.php

{
	"name": "Foo Bar", // name as shown under [[Special:Version]]
	"author": "Daniel Friesen",
	"url": "https://www.mediawiki.org/wiki/Skin:FooBar",
	"descriptionmsg": "foobar-desc",
	"namemsg": "skinname-foobar",
	"license-name": "GPL-2.0+",
	"type": "skin",
	// continued below
}
// Continued from above

if ( !defined( 'MEDIAWIKI' ) ) {
	die( 'This is an extension to the MediaWiki package and cannot be run standalone.' );
}

$wgExtensionCredits['skin'][] = array(
	'path' => __FILE__,
	'name' => 'Foo Bar', // name as shown under [[Special:Version]]
	'namemsg' => 'skinname-foobar', // used since MW 1.24, see the section on "Localisation messages" below
	'version' => '1.0',
	'url' => 'https://www.mediawiki.org/wiki/Skin:FooBar',
	'author' => '[https://mediawiki.org/wiki/User:Dantman Daniel Friesen]',
	'descriptionmsg' => 'foobar-desc', // see the section on "Localisation messages" below
	'license' => 'GPL-2.0+',
);

Be sure to customize things to what's correct for you too.

Next we want the boilerplate to declare our skin's name, auto loaded classes, and localisation messages (the content of the files and directories references here is described in the latter sections):

MediaWiki 1.25 and later (supporting extension registration)

skin.json

MediaWiki 1.24 and older

FooBar.skin.php

// Continued from above
	"ValidSkinNames": {
		"foobar": "FooBar"
	},
	"AutoloadClasses": {
		"SkinFooBar": "FooBar.skin.php"
	},
	"MessagesDirs": {
		"FooBar": "i18n"
	},
// Continued from above
$wgValidSkinNames['foobar'] = 'FooBar';

$wgAutoloadClasses['SkinFooBar'] = __DIR__ . '/FooBar.skin.php';
$wgMessagesDirs['FooBar'] = __DIR__ . '/i18n';

The value provided in the ValidSkinNames line, prepended with "Skin", is used as the name of your skin's main PHP class: the name of the class for your skin must be "Skin{Your Identifier}" (in this example, SkinFooBar). Keep that in mind since that means that you do want to replace the FooBar in SkinFooBar above with the identifier for your skin, and likewise you will want to do so in the class names in the .skin.php file.

Skin styles and scripts (Resource Loader modules)[edit]

To provide styles and/or scripts for your skin, you must define ResourceLoader modules that include them.

MediaWiki 1.25 and later (supporting extension registration)

skin.json

MediaWiki 1.24 and older

FooBar.skin.php

// Continued from above
	"ResourceModules": {
		"skins.foobar": {
				"styles": {
						"resources/screen.css": { "media": "screen" },
						"resources/print.css": { "media": "print" }
				}
		}
	},
	"ResourceFileModulePaths": {
		"localBasePath": "",
		"remoteSkinPath": "FooBar"
	},
// Continued from above
$wgResourceModules['skins.foobar'] = array(
	'styles' => array(
		'resources/screen.css' => array( 'media' => 'screen' ),
		'resources/print.css' => array( 'media' => 'print' ),
	),
	'remoteSkinPath' => 'FooBar',
	'localBasePath' => __DIR__,
);

The 'styles' array itself does not have to be a single style sheet, ResourceLoader combines all the style sheets into a single style sheet so you can separate your style sheet into as many separate files as you want. You'll probably want to read up on ResourceLoader because it has other features like @embed and RTL flipping to consider when writing the CSS for your skin.

  • You can use .less or .css with MediaWiki version 1.22 and up.
  • You can use three Resource Loader modules to get some common content styling without having to copy it into your own CSS: ' media wiki. skinning.elements', 'media wiki.skinning.content' and 'media wiki.skinning.interface', which provide progressively more default styling. They can be loaded like any other module (see the example in "Skin code" section below). We will use 'media wiki. skinning.interface'.
    • The modules are available as of MediaWiki 1.23.


MediaWiki version: 1.24

MediaWiki 1.24 adds a $wgResourceModuleSkinStyles global which allows skins to define custom styles for particular Resource Loader modules.

Only add a module for 'scripts' if your skin actually needs custom JavaScript:

MediaWiki 1.25 and later (supporting extension registration)

skin.json

MediaWiki 1.24 and older

FooBar.skin.php

// Continued from above
// Add this to the ResourceModules array
	"skins.foobar.js": {
			"scripts": [
				"cool.js",
				"awesome.js"
			],
			"position": "top",
			"dependencies": "jquery.ui.dialog"
		}
// Continued from above
$wgResourceModules['skins.foobar.js'] = array(
	'scripts' => array(
		'FooBar/resources/cool.js',
		'FooBar/resources/awesome.js',
	),
	'dependencies' => array(
		// In this example, awesome.js needs the jQuery UI dialog stuff
		'jquery.ui.dialog',
	),
	'remoteBasePath' => &$GLOBALS['wgStylePath'],
	'localBasePath' => &$GLOBALS['wgStyleDirectory'],
);

Localisation messages[edit]

MediaWiki version: 1.23

The next thing you'll want to deal with is the i18n files. These are stored in the JSON format.

At minimum you are going to need two i18n messages in English: One for the skin name so that it displays correctly in the lists of skins in Special:Preferences where the user selects his or her skin, and another for the credits that will be visible on Special:Version.

Create a file skins/FooBar/i18n/en.json with the following contents:

{
	"@metadata": {
		"authors": [ "John Doe" ]
	},
	"skinname-foobar": "Foo Bar",
	"foobar-desc": "Some skin of mine"
}

You'll want to customize the keys and contents of both messages (foobar-desc is the description that will appear on Special:Version) and the authorship metadata. You can add translations in further files named after language codes, e.g. de.json for German and es.json for Spanish. A special "language code" of qqq.json is for documentation explaining the message keys.


MediaWiki version: 1.17

The above way is only compatible with MediaWiki 1.23 and later. To be compatible with earlier versions up to and including MediaWiki 1.17, you should provide a compatibility shim file. The generateJsonI18n.php maintenance script generates one. You invoke it by entering the following command line: php maintenance/generateJsonI18n.php --shim-only skins/FooBar/FooBar.i18n.php skins/FooBar/i18n/ . You declare it by adding another line in main skin file below $wgMessagesDirs:

$wgExtensionMessagesFiles['FooBar'] = __DIR__ . '/FooBar.i18n.php';

Skin code[edit]

The last PHP file to deal with now is the FooBar.skin.php file where the bulk of our actual skin is. In this tutorial, the two classes of the skin are in this single file.

Start with the usual header comment:

<?php
/**
 * Skin file for skin Foo Bar.
 *
 * @file
 * @ingroup Skins
 */

// [...]

Extend SkinTemplate[edit]

Then extend the SkinTemplate class.

/**
 * SkinTemplate class for Foo Bar skin
 * @ingroup Skins
 */
class SkinFooBar extends SkinTemplate {
	var $skinname = 'foobar', $stylename = 'FooBar',
		$template = 'FooBarTemplate', $useHeadElement = true;

	/**
	 * This function adds JavaScript via ResourceLoader
	 *
	 * Use this function if your skin has a JS file(s).
	 * Otherwise you won't need this function and you can safely delete it.
	 *
	 * @param OutputPage $out
	 */
	
	public function initPage( OutputPage $out ) {
		parent::initPage( $out );
		$out->addModules( 'skins.foobar.js' );
		/* 'skins.foobar.js' is the name you used in your skin.json file */
	}

	/**
	 * Add CSS via ResourceLoader
	 *
	 * @param $out OutputPage
	 */
	function setupSkinUserCss( OutputPage $out ) {
		parent::setupSkinUserCss( $out );
		$out->addModuleStyles( array(
			'mediawiki.skinning.interface', 'skins.foobar'
			/* 'skins.foobar' is the name you used in your skin.json file */
		) );
	}
}

// [...]

SkinFooBar is your class in skin.json (or FooBar.php for MW 1.25 and earlier) from above. It inherits a lot of functionality from the SkinTemplate class, which sets up many of the elements described in Skinning Part 1 that a MediaWiki skin needs to render. Also many MediaWiki extensions "hook" into events it fires such as PersonalUrls and SkinTemplateNavigation in order to add elements to skins.

You'll want to update the skin name and also the $skinname and $stylename variables (the first declares the internal skin name used for $wgValidSkinNames again, the second declares the directory name used in $wgResourceModules definitions again).

Both the initPage() and setupSkinUserCss() functions import the necessary ResourceLoader modules you declared in your skin.json file. Remember to update the key there!

Extend BaseTemplate[edit]

In addition to implementing a lot of common skin functionality, class SkinTemplate approaches skin construction by relying on a separate template class that outputs the HTML markup for the skin. Hence its name "SkinTemplate" – it isn't the template, it's a kind of skin that uses a template.

This separate template class usually extends the BaseTemplate class, which defines various useful methods to organize and output items for a skin, such as getPersonalTools(), makeSearchInput(), etc. BaseTemplate in turn extends the QuickTemplate class, which provides some convenience methods to get() and set() items in the template.

<?php
/**
 * BaseTemplate class for Foo Bar skin
 *
 * @ingroup Skins
 */
class FooBarTemplate extends BaseTemplate {
	/**
	 * Outputs the entire contents of the page
	 */
	public function execute() {
		$this->html( 'headelement' ); ?>

/** Your skin's code goes here.
  * The rest of this page explains what to write here.
**/

<?php $this->printTrail(); ?>
</body>
</html><?php
	}
}

This is the outermost part of the boilerplate. Keep in mind that headelement defines the <body> tag itself, so you shouldn't include one. If you want to add some attributes or classes to the body tag, override the addToBodyAttributes() method in your SkinFooBar class.

Now we get into your actual skin-specific markup here. Because that's entirely dependent on the skin you are building, the remaining examples on this page show you how to output the MediaWiki elements to HTML.

To start with you should take your markup and insert it into the /* Your skin's code goes here.. You may want to consider taking this time to also setup the CSS for your skin. Doing so should give you a skin that doesn't function but displays all the dummy markup you have inserted. It's a good way to test your skin with just dummy markup and then make pieces of it functional and test them piece by piece.

Adding skin elements[edit]

General information about adding elements[edit]

There are different ways of getting the skin elements to be output to the user's browser. All of the navigation items are contained within PHP arrays.

  • The notable items in arrays are Namespaces, Sidebar, Actions and Personal Tools.
  • These arrays then contain sub-arrays which hold the data that needs to be output to the browser.
    • Example: you can find the data needed for the namespace links in the $this->data['content_navigation']['namespaces'], array, which then contains an array with [href], [tooltip] and others, which, when assembled into the proper HTML, create the link for the user to click on.
  • The examples below generally use the helper method $this->makeListItem( $key, $item ); within a foreach loop to generate items from an array of data. This helper intelligently knows how to properly format a list item and all the attributes it needs, as well as create the correct links and other contents that belong in the list item.
    • By default, this method outputs a <li>. If you wish to output something other than an unordered or ordered list of items, makeListItem can accept an array of options as a third argument. You can use that to change the tag from a 'li' to something else.
      • For example, to use <span> tags instead of <li> tags, you can use $this->makeListItem( $key, $item, array( 'tag' => 'span' ) );. Naturally when doing this you would also change the boilerplate examples to output something other than a <ul> to surround the list.

User message (newtalk)[edit]

MediaWiki can output a message to a user about new messages on their talkpage. Historically MonoBook and Vector have outputted the newtalk message in the content area and for now they are still there for compatibility with some out-of-content area hacks used on Wikipedia. However practically the newtalk message may actually make more sense alongside the JavaScript message inside your skin.

The boilerplate to output it is:

<?php $this->html( 'newtalk' ); ?>

The newtalk message has no wrapping or style on its own, so you should wrap this in a block to style. The message doesn't always show up so be sure to wrap it in a conditional:

<?php if ( $this->data['newtalk'] ) { ?>
  <div class="usermessage"> <!-- The CSS class used in Monobook and Vector, if you want to follow a similar design -->
    <?php $this->html( 'newtalk' );?>
  </div>
<?php } ?>

Site notice[edit]

The boilerplate to output a wiki's sitenotice is:

<?php $this->html( 'sitenotice' ); ?>

Because you'll likely be wrapping the sitenotice in a block you'll probably want to test if the sitenotice is present, to do that you'll use similar boilerplate:

<?php if ( $this->data['sitenotice'] ) { ?>
  <div id="siteNotice"> <!-- The CSS class used in Monobook and Vector, if you want to follow a similar design -->
    <?php $this->html( 'sitenotice' ); ?>
  </div>
<?php } ?>

Site name[edit]

The boilerplate to output a wiki's sitename is:

<?php $this->text( 'sitename' ); ?>

Logo and main page link[edit]

The logo is comprised primarily of the key for the logo, the key for the main page's URL, and a call to insert a tooltip and accesskey for the logo.

<a
	href="<?php 
		echo htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] );
		// This outputs your wiki's main page URL to the browser.
		?>"
	<?php echo Xml::expandAttributes( Linker::tooltipAndAccesskeyAttribs( 'p-logo' ) ) ?>
>
	<img src="<?php 
		 	$this->text( 'logopath' ); 	
		 	// This outputs the path to your logo's image
		 	// You can also use $this->data['logopath'] to output the raw URL of the image. Remember to HTML-escape
		 	// if you're using this method, because the text() method does it automatically.
		?>"
		alt="<?php $this->text( 'sitename' ) ?>"
	>
</a>
  • Linker::tooltipAndAccesskeyAttribs( 'p-logo' ) creates an array containing a tooltip and associated accesskey. 'p-logo' is the id typically used for the logo so that's the key that is used by MW to define the accesskey and tooltip.
  • If you output a second logo in the page you should avoid re-using the accesskey. Use Linker::titleAttrib( 'p-logo' ) as a value of the title attribute instead of the Linker::tooltipAndAccesskeyAttribs call.
  • Linker::tooltipAndAccesskeyAttribs returns an associative array of attributes that can be used with the Html:: interface, here it is expanded to HTML code with Xml::expandAttributes.
  • Be sure to remember to HTML-escape the href and logopath, either using htmlspecialchars or text().

Keep in mind a something about the logo itself. We currently only have one config for logopath. As a result the same logo will be used in every skin, that includes the built-in skins. MediaWiki's built-in skins generally have a logo area that restricts logo sizes to around 155x155px. If your skin has a logo area intended for a logo of a different size you may want to consider including a separate config variable to let users of your skin define a skin-specific logo.

Title[edit]

The title of the page is included into the skin's keys as HTML. Generally, a title is plain text. However, a limited set of HTML formatting may be permitted inside of a DISPLAYTITLE and some extensions may add HTML to it.

The boilerplate to output the page's title is:

<?php $this->html( 'title' ); ?>

If you want to use extra styling:

<?php
if ( $this->data['title'] != '' ) { // Do not display the HTML tag if it the header is empty
	echo "<h1 id=\"firstHeading\" class=\"firstHeading\">";	// The CSS ID used by MonoBook and Vector.
	$this->html( 'title' );
	echo "</h1>";
}

The content area[edit]

The content area in MediaWiki usually has some extra styles like icons on external links.

MonoBook and Vector both have a <div id="content"> and a <div id="bodyContent"> though MonoBook styles stuff inside bodyContent while Vector styles stuff inside content.

Whether you keep these ids or not you should consider adding a class="mw-body" wherever you do decide links should be styled. 1.19 has some stylesheets you can opt-in to that will use that class.

Tagline[edit]

MediaWiki has a "Tagline" which usually goes right below the title, however is also typically hidden by default. The text usually goes something like "From Your Wiki's Name". Some wiki like to show it and style it, though the primary purpose of this seems not to be for normal viewing, but for printing to identify the source of the content. Be sure to include this and test your print styles, we'll go into more detail in a later print section.

The tagline's boilerplate is:

<?php $this->msg( 'tagline' ); ?>

If you want to add styling:

<?php 
if ( $this->data['isarticle'] ) {	// This is an optional test. Vector uses this if-statement to determine if the current page is an article (in the main namespace.)
	 echo '<div id="siteSub">';	// An optional div and CSS ID. This is what MonoBook and Vector use.
	 $this->msg( 'tagline' ); 
	 echo '</div>';
}

Subtitles[edit]

Besides the tagline MediaWiki has two subtitles below the title to take into account. One is used for various things like the subpage hierarchy and redirected from line while the other is specifically for the undelete message.

The two pieces to output the subtitle lines are:

<?php $this->html( 'subtitle' ); ?>
<?php $this->html( 'undelete' ); ?>

Naturally both of these are optional so you'll want to test for them:

<?php if ( $this->data['subtitle'] ) { ?>
	  <div id="contentSub"> <!-- The CSS class used in Monobook and Vector, if you want to follow a similar design -->
	  <?php $this->html( 'subtitle' ); ?>
	  </div>
<?php } ?>
	  <?php if ( $this->data['undelete'] ) { ?>
	  <div id="contentSub2"> <!-- The CSS class used in Monobook and Vector, if you want to follow a similar design -->
	  <?php $this->html( 'undelete' ); ?>
	  </div>
<?php } ?>

Body text[edit]

The body of the page is dead simple to output, you might even want to do this first:

<?php $this->html( 'bodytext' ); ?>

Categories[edit]

The function to output the categories block is different from other functions. Many other functions hold an array, but the function for categories contains a string of HTML. Here is the code to use:

<?php $this->html( 'catlinks' ); ?>

Because this function outputs HTML, it is trickier to format in your skin. Here is an example of what is output using the function above:

<div id="catlinks" class="catlinks"> 
	<?php /* The catlinks function always uses this CSS ID and class;
	Your skin's CSS can specify formatting for this class and ID */ ?>

	<div id="mw-normal-catlinks" class="mw-normal-catlinks">
		<a href="/wiki/Special:Categories" title="Special:Categories">Category</a>: 
		<?php /* The word "category" in this <a> tag can be customized by updating Mediawiki:pagecategories
		You can also change link that this <a> tag points to by updating Mediawiki:pagecategorieslink */ ?>
		<ul>
			<li><a href="/wiki/Category:Help" title="Category:Help">Help</a></li>
		</ul>
	</div>
</div>

This function is the only way to display the categories on the page, so you can have only one category list.

Page status indicators[edit]

MediaWiki version: 1.25
Gerrit change 162609

Page status indicators are icons (or short text snippets) usually displayed in the top-right corner of the page, outside of the main content, or right before page title. They are also known as top icons, page icons, heading icons or title icons. (In wikitext they can be added using <indicator name="foo">[[File:Foo.svg|20px]]</indicator>; see Help:Page status indicators for more information.)

In the simplest version, the page status indicators block can be inserted on a page using:

<?php echo $this->getIndicators(); ?>
  • The PHP above produces <div class="mw-indicators"></div> in the HTML that is output to the browser.
  • Your skin's CSS should, therefore, have a definition for .mw-indicators.
  • Each time a user adds <indicator name="foo"></indicator> to a page in the wiki, the MediaWiki software will generate <div id="mw-indicator-foo"></div> inside the empty "mw-indicators" div above. This means that a particular wiki needs to define the style for the "mw-indicator-foo" div within its common.css.

dataAfterContent[edit]

MediaWiki skins have another little hack in place. Extensions have the ability to add blocks which should go somewhere after the body text, but they aren't supposed to go before the catlinks block. Because the catlinks block typically goes right after the body text we have a separate key to insert these.

<?php $this->html( 'dataAfterContent' ); ?>

Be sure to include this or else some extensions may not work properly in your skin.

Personal tools[edit]

BaseTemplate includes some helpers that make building a list of personal tool links easy. Vector and MonoBook display the personal tools in the far upper corner of the page. They generally contain things like the login link, logout link, the user's username with a link to their userpage, talkpage, watchlist, preferences, and other links.

This boilerplate can output the personal tools as an unordered list.

<ul>
<?php
	foreach ( $this->getPersonalTools() as $key => $item ) {
		echo $this->makeListItem( $key, $item );
	}
?>
</ul>

Content actions[edit]

As of 1.18 MediaWiki supports the use of two different lists to access what is usually outputted as tabs for a page.

  • The content_actions array provides these tabs as a single flat array, and is was the original format of the actions. This was is used by Mono Book.
  • The other is content_navigation which was introduced by Vector. content_navigation provides the list of tabs as an array of arrays array containing 'namespaces', 'views', 'actions', and 'variants' with the tabs that are put into content_actions nicely separated into groups.
  • If you want to differentiate between any of the tabs in any way at all, be it some special styling, or outputting them in separate lists, you are better off making use of the new content_navigation. Note that the content_navigation also includes a redundant 'Read' tab in views which is omitted in the flat content_actions list.

This is better explained with a number of examples.

This example outputs just the links of the Namespaces.

<ul>
<?php
	foreach ( $this->data['content_navigation']['namespaces'] as $key => $tab ) {
		echo $this->makeListItem( $key, $tab );
	}
?>
</ul>

You can use this to output the Namespaces links wherever you want in whatever order you want.

This example outputs all the Namespaces links as separate lists:

<?php foreach ( $this->data['content_navigation'] as $group => $tabs ) { ?>
<ul>
<?php
	foreach ( $tabs as $key => $tab ) {
		echo $this->makeListItem( $key, $tab );
	}
?>
</ul>
<?php } ?>

This example outputs all the the Namespaces links as one unified list. This will include the slightly redundant 'Read' tab, however you can use the separation of groups to add separators or other things wherever you want.

<ul>
<?php
	foreach ( $this->data['content_navigation'] as $group => $tabs ) {
		foreach ( $tabs as $key => $tab ) {
			echo $this->makeListItem( $key, $tab );
		}
	}
?>
</ul>

This example outputs the flat content_actions list as a single list:

<ul>
<?php
	foreach ( $this->data['content_actions'] as $key => $tab ) {
		echo $this->makeListItem( $key, $tab );
	}
?>
</ul>

For most of these you'll probably want to add something like a CSS class or id based off the $group to target with styles as you please.

Sidebar[edit]

Currently for navigation MediaWiki only supports a built-in sidebar – including the toolbox, language links, and site-defined navigation (see Manual:Interface/Sidebar). For other types of navigation you can hard code or preferably have someone implement the code to support your own custom navigation message. For now all I can show is the sidebar boilerplate.

<?php
foreach ( $this->getSidebar() as $boxName => $box ) { ?>
<div id="<?php echo Sanitizer::escapeId( $box['id'] ) ?>"<?php echo Linker::tooltip( $box['id'] ) ?>>
	<h5><?php echo htmlspecialchars( $box['header'] ); ?></h5>
	 <!-- If you do not want the words "Navigation" or "Tools" to appear, you can safely remove the line above. -->

<?php
	if ( is_array( $box['content'] ) ) { ?>
	<ul>
<?php
		foreach ( $box['content'] as $key => $item ) {
			echo $this->makeListItem( $key, $item );
		}
?>
	</ul>
<?php
	} else {
		echo $box['content'];
	}
?>
</div>
<?php } ?>

The boilerplate is of course a little plain. This contains the typical CSS ID and a tooltip; you can also add a class or other formatting. If you don't care about the ability to customize the output of lists, you can use $this->getSkin( array( 'htmlOnly' => true ) ) and drop the whole is_array test and just keep the <?php echo $box['content']; ?>.

Language links[edit]

Note that language links are already included in the sidebar, above. If you use that method, you can skip this section.

A MediaWiki page may have links to the same page in other languages on the wiki when inter-language links are added to the page. If you do wish to follow the MonoBook and Vector methods, you may output this as part of the sidebar.

<?php
	// Language links are often not present, so this if-statement allows you to add a conditional <ul> around the language list
	if ( $this->data['language_urls'] ) {
		echo "<ul>";
		foreach ( $this->data['language_urls'] as $key => $langLink ) {
			echo $this->makeListItem( $key, $langLink );
		}
		echo "</ul>";
	} 
?>

Toolbox[edit]

Note that language links are already included in the sidebar, above. If you use that method, you can skin this section.

The MediaWiki toolbox contains various links. Some are general links like a links to a list of Special Pages so a user always has a way to access them. Others are page-sensitive links like permalinks, printable links, block links, feed links, and a link to a list of pages linking to the current page.

The boilerplate to output the toolbox is:

<ul>
<?php
	foreach ( $this->getToolbox() as $key => $tbitem ) {
		echo $this->makeListItem( $key, $tbitem );
	}
	wfRunHooks( 'SkinTemplateToolboxEnd', array( &$this ) );
?>
</ul>

The SkinTemplateToolboxEnd hook is included for compatibility with some extensions. As more skins use the BaseTemplateToolbox hook and more extensions switch to using it we may be able to drop the hook and no longer include it.

Like personal URLs the array that $this->getToolbox(); returns can be set to a variable can can be easily modified and unset if you want to move parts of the toolbox elsewhere in your skin.

Search form[edit]

MediaWiki skins usually include a search form that can be used to search the wiki. If the feature is enabled and the form is setup correctly this form usually also supports search suggestions. MonoBook does this as part of the sidebar, while other skins such as Vector have a dedicated place for the search form.

To start the search form, let's begin with the form itself:

<form action="<?php $this->text( 'wgScript' ); ?>">
	<input type="hidden" name="title" value="<?php $this->text( 'searchtitle' ) ?>" />
	// The code for the <input> box and the Go button go here,
	// as explained below.
</form>

A search form itself uses the HTTP GET method rather than a POST. As a result you can't include any query arguments in the action="". So a search form is built initially of a form with the action pointed to the wiki's index.php and a hidden input with the search page's title to ensure it's in the URL.

You should probably give the form itself an id. Keep in mind that MediaWiki supports autocompletion of the search form. Starting in version 1.18, MediaWiki will only look for search forms with one of the id's "searchform" "searchform2" "powersearch" or "search". So the best practice is to use id="searchform" for your form. It is recommended you use the CSS class mw-search for your form.

Moving on, naturally every search form needs a text field to enter a search query into. At its base level you can use this helper method to build a search input:

<?php echo $this->makeSearchInput(); ?>

However, this helper supports an array, which is output to the user's screen. Note that:

  • The form uses <input type="search"> by default. A browser that supports this type of input field usually displays it with a special style.
  • This means that, if you wish to add a special style like what Vector does for its simple search, you may want to override this and force MediaWiki to output a text<input type="text"> instead. See the following example:
<?php echo $this->makeSearchInput( array( 'type' => 'text' ) ); ?>

Another thing to keep in mind is you may want to use an id on your search input. You'll probably have some label nearby like "Search:" or something, at the very least it may be one that is hidden but is still around for accessibility purposes. You'll probably need an id to target the input with a label if you don't put the input inside the label itself. This is especially true if you put the label inside a header like vector does. The search input's helper also accepts an id to use. For example MonoBook and Vector use the id 'searchInput' to output a search input with the searchInput id you can use:

<?php echo $this->makeSearchInput( array( 'id' => 'searchInput' ) ); ?>

Note that the array is basically a list of attributes that are modified with the pieces important to a search input then passed to the HTML method that generates the input. This means you can add just about any HTML attribute that you want. Feel free to use it to add a CSS class, an inline style, some HTML5 data-attributes, or so on.

Next we're going to need a search button so that the user can submit the search. However this helper has 3 different modes to keep in mind. MediaWiki supports two forms of search.

  • The default "Go" search which may redirect directly to a page if the search term matches a page's title.
  • A "Full Text" search that will always go to the search page.

The search input's helper supports both a 'go' mode and a 'fulltext' mode. The 3rd mode is an 'image' mode which outputs a 'go' mode button but does it using an image instead of text. Vector uses this last mode to create its simple search icon. This helper also accepts an array of attributes as the second argument. The difference here is that in the 'image' mode the required 'src' attribute and optional 'alt' attribute go on the <img> while the rest of the attributes you specify go on the <button>. Here are some examples:

<?php
// A "Go" button
 echo $this->makeSearchButton( 'go' );
// A Full Text "Search" button
 echo $this->makeSearchButton( 'fulltext' );
// Go button using the button text "Search"
 echo $this->makeSearchButton( 'go', array( 'value' => $this->translator->translate( 'searchbutton' ) ) );
// An image search button using the images/searchbutton.png image in your skin's folder.
 echo $this->makeSearchButton( 'image', array( 'src' => $this->getSkin()->getSkinStylePath( 'images/searchbutton.png') ) );
?>

The tradition in MonoBook and Vector for CSS IDs here is to use search Go Button and MW-search button for a pair of Go and Full Text Search buttons, both with a searchButton class. And to use the ID search Button for a Vector simple search style image button. The examples for those cases:

<?php
// A "Go" button
 echo $this->makeSearchButton( 'go', array( 'id' => 'searchGoButton', 'class' => 'searchButton' ) );
// A Full Text "Search" button
 echo $this->makeSearchButton( 'fulltext', array( 'id' => 'mw-searchButton', 'class' => 'searchButton' ) );
// An image search button using the images/searchbutton.png image in your skin's folder.
 echo $this->makeSearchButton( 'image', array( 'id' => 'searchButton', 'src' => $this->getSkin()->getSkinStylePath( 'images/searchbutton.png') ); 
?>

There's no standard for toggling between a classic Go+Search and a simple search as that introduction was specific to Vector. You're also free to just have a plain go button with a "Search" title if it fits your theme. The old MonoBook had a config option to only have a Go button and instead have a power search link – that is beyond the scope of this manual.

Image paths[edit]

In the above code notice that if you need to output <image src="..."> tags in PHP code, you need to get the path to the image asset on the server using $this->getSkin()->getSkinStylePath(). Where possible it's cleaner to refer to images from CSS code, e.g. background-image: url( relative/path/to/image.png );. See also ResourceLoader/Images.

Footer[edit]

Footer links[edit]

A MediaWiki skin may contain a common list of links and pieces of text intended to be in the footer. These footer links may contain things like a license line and other links like about, privacy policy, and disclaimer links.

The footer links array is returned by the $this->getFooterLinks(); helper which also accepts a "flat" argument to return a flat array instead of a categorized one.

The boilerplate to output a collection of footer links lists is:

<?php
foreach ( $this->getFooterLinks() as $category => $links ) { ?>
<ul>
<?php
	foreach ( $links as $key ) { ?>
	<li><?php $this->html( $key ) ?></li>

<?php
	} ?>
</ul>
<?php
} ?>

You can output the footer links as a flat array using this code instead:

<ul>
<?php foreach ( $this->getFooterLinks( 'flat' ) as $key ) { ?>
	<li><?php $this->html( $key ) ?></li>

<?php } ?>
</ul>

Remember that like the content_navigation array this is a categorized list, however in this case it's not a fixed set of categories. You may want to output these as separate lists, give each list a class or id based on the category, and do the same for the list items as well.

Footer icons[edit]

The footer may also contain a common list of icons in it. Included in these icons are the "powered by MediaWiki" icon, an optional "copyright" icon, and an icon representing the license the wiki has chosen. There will be any other icon that a user or extension has defined with $wgFooterIcons.

The footer icons list is categorized into groups.

To output a list of only icons where each group is a list item containing one or more icons you can use:

<ul>
<?php
	foreach ( $this->getFooterIcons( 'icononly' ) as $blockName => $footerIcons ) { ?>
	<li>
<?php
		foreach ( $footerIcons as $icon ) {
			echo $this->getSkin()->makeFooterIcon( $icon );
		}
?>
	</li>
<?php
	} ?>
</ul>

You can use the 'without Image' parameter (shown next) to make Footer Icon you can instead output a textual list instead of icons. Modern uses this kind of technique. Note that footer links has a textual representation of the wiki's license, so including the copyright/license icon as a second piece of text doesn't make that much sense. Hence to omit the copyright icon/text you can use the "nocopyright" parameter to getFooterIcons.

<ul>
<?php
	foreach ( $this->getFooterIcons( 'nocopyright' ) as $blockName => $footerIcons ) { ?>
	<li>
<?php
		foreach ( $footerIcons as $icon ) {
			echo $this->getSkin()->makeFooterIcon( $icon, 'withoutImage' );
		}
?>
	</li>
<?php
	} ?>
</ul>

Further reading[edit]