Manual:Skinning

From MediaWiki.org
Jump to: navigation, search

This page contains instructions on how to create a skin for MediaWiki.

Note Note: The term FooBar will be used as a placeholder for the newly-created skin's name. (Notice the use of the uppercase FooBar and the lowercase foobar in different contexts.)

Note Note: There is also a more general walkthrough here.

File Locations[edit | edit source]

All skin files are located in the skins subfolder of the MediaWiki installation directory (see $wgStylePath and $wgStyleDirectory for actual location.)

There are two files for each skin in that folder:

  • FooBar.php: The main file, defining the page layout.
  • FooBar.deps.php: a workaround for a bug in the APC opcode cache on PHP 5

For all other files, a subfolder with the skin's name should be created - for example:

  • skins/foobar/main.css: The FooBar skin's main style sheet
  • skins/foobar/IE60Fixes.css: browser-specific style sheet fixes

Code Structure and Elements[edit | edit source]

This section outlines the code structure of a typical MediaWiki skin.

The respective code portions have been extracted from MediaWiki's default MonoBook skin. For the full PHP code in its entirety, see /Vector/Example.

Dependencies[edit | edit source]

This section contains the dependency information about the skin to work around a caching bug in PHP 5.

<?php
/**
 * [FooBar] skin dependencies
 */
 
if ( ! defined( 'MEDIAWIKI' ) )
        die( 1 );
 
require_once( dirname( dirname( __FILE__ ) ) . '/includes/SkinTemplate.php');

Metadata[edit | edit source]

This section contains meta-information about the skin.

<?php
/**
 * [FooBar] skin
 *
 * @file
 * @ingroup Skins
 * @version [#].[#].[#]
 * @author [name] ([URL] / [E-Mail])
 * @license [URL] [name]
 */

Initialization[edit | edit source]

This section sets up your skin to inherit from the main skin template class and shows the beginning of the template callback class. Here the required classes are defined. Instances of [FooBar] and [foobar] need to be replaced with the skin's name. Usually nothing else in this section needs to be altered.

// initialize
if( !defined( 'MEDIAWIKI' ) ){
	die( "This is a skins file for mediawiki and should not be viewed directly.\n" );
}
 
// inherit main code from SkinTemplate, set the CSS and template filter
class Skin[FooBar] extends SkinTemplate {
	var $useHeadElement = true;
 
	function initPage( OutputPage $out ) {
		parent::initPage( $out );
		$this->skinname  = '[foobar]';
		$this->stylename = '[foobar]';
		$this->template  = '[FooBar]Template';
	}
	function setupSkinUserCss( OutputPage $out ) {
		parent::setupSkinUserCss( $out );
		// Append to the default screen common & print styles...
		$out->addStyle( '[foobar]/main.css', 'screen' );
	}
}
class [FooBar]Template extends QuickTemplate {
	/**
	 * Template filter callback for this skin.
	 * Takes an associative array of data set from a SkinTemplate-based
	 * class, and a wrapper for MediaWiki's localization database, and
	 * outputs a formatted page.
	 */
	public function execute() {
		global $wgRequest;
 
		$skin = $this->data['skin'];
 
		// suppress warnings to prevent notices about missing indexes in $this->data
		wfSuppressWarnings();
 
		$this->html( 'headelement' );

Page Elements[edit | edit source]

The following sections consist of page elements that your skin can use with an example usage. You can use page elements in whatever order you like or alter the way you use these elements. Elements presented below are in the order that the Monobook skin uses them.

Site Notice[edit | edit source]

[conditional]

<?php if( $this->data['sitenotice'] ) { ?><div id="siteNotice"><?php $this->html('sitenotice') ?></div><?php } ?>

Page Name[edit | edit source]

<h1 id="firstHeading"><?php $this->html('title'); ?></h1>

Tagline (Site Subtitle)[edit | edit source]

<div id="siteSub"><?php $this->msg('tagline') ?></div>

Page Subtitle[edit | edit source]

(e.g. redirect notice)

<div id="contentSub"><?php $this->html('subtitle') ?></div>

Undelete Notice[edit | edit source]

[conditional]

<?php if( $this->data['undelete'] ) { ?><div id="contentSub2"><?php $this->html('undelete') ?></div><?php } ?>

User-Messages Notification[edit | edit source]

[conditional]

<?php if( $this->data['newtalk'] ) { ?><div class="usermessage"><?php $this->html('newtalk') ?></div><?php } ?>

Jump-To Links[edit | edit source]

(intra-page navigation) [conditional], [optional]

<?php if( $this->data['showjumplinks'] ) { ?><div id="jump-to-nav"><?php $this->msg('jumpto') ?> <a href="#column-one"><?php $this->msg('jumptonavigation') ?></a>, <a href="#searchInput"><?php $this->msg('jumptosearch') ?></a></div><?php } ?>

Page Contents[edit | edit source]

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

Category Links[edit | edit source]

[conditional]

<?php if( $this->data['catlinks'] ) { $this->html('catlinks'); } ?>

Page Toolbar[edit | edit source]

[iterative]

<div id="p-cactions" class="portlet">
	<h5><?php $this->msg('views') ?></h5> <!-- Page Toolbar Label/Caption [optional] -->
	<div class="pBody">
		<ul><?php
			foreach( $this->data['content_actions'] as $key => $tab ) {
				echo '
			<li id="', Sanitizer::escapeId( "ca-$key" ), '"';
				if ( $tab['class'] ) {
					echo ' class="', htmlspecialchars($tab['class']), '"';
				}
				echo '><a href="', htmlspecialchars($tab['href']), '"',
					$skin->tooltipAndAccesskeyAttribs('ca-'.$key), '>',
					htmlspecialchars($tab['text']),
					'</a></li>';
			}?>
		</ul>
	</div>
</div>

User Toolbar[edit | edit source]

[iterative]

<div class="portlet" id="p-personal">
	<h5><?php $this->msg('personaltools') ?></h5> <!-- User Toolbar Label/Caption [optional] -->
	<div class="pBody">
		<ul>
<?php 			foreach( $this->data['personal_urls'] as $key => $item ) { ?>
				<li id="<?php echo Sanitizer::escapeId( "pt-$key" ) ?>"<?php
					if ($item['active']) { ?> class="active"<?php } ?>><a href="<?php
				echo htmlspecialchars( $item['href'] ) ?>"<?php echo $skin->tooltipAndAccesskeyAttribs('pt-'.$key) ?><?php
				if( !empty( $item['class'] ) ) { ?> class="<?php
				echo htmlspecialchars( $item['class'] ) ?>"<?php } ?>><?php
				echo htmlspecialchars( $item['text'] ) ?></a></li>
<?php			} ?>
		</ul>
	</div>
</div>

[edit | edit source]

<div class="portlet" id="p-logo">
    <a href="<?php echo htmlspecialchars($this->data['nav_urls']['mainpage']['href']) ?>"  <?php echo $skin->tooltipAndAccesskeyAttribs('n-mainpage')  ?>  >
        <img src="<?php echo htmlspecialchars( $this->data['logopath'] ) ?>" border="0" />
  </a>   
</div>
<script type="<?php $this->text('jsmimetype') ?>"> if (window.isMSIE55) fixalpha(); </script> <!-- IE alpha-transparency fix -->

Sidebar Navigation[edit | edit source]

[iterative]

	<?php foreach( $this->data['sidebar'] as $bar => $cont ) { ?>
	<div class='portlet' id='p-<?php echo Sanitizer::escapeId( $bar ) ?>'<?php echo $skin->tooltip('p-'.$bar) ?>>
		<h5><?php $out = wfMsg( $bar ); if( wfEmptyMsg( $bar, $out ) ) echo $bar; else echo $out; ?></h5>
		<div class='pBody'>
			<ul>
<?php 			foreach( $cont as $key => $val ) { ?>
				<li id="<?php echo Sanitizer::escapeId( $val['id'] ) ?>"<?php
					if( $val['active'] ) { ?> class="active" <?php }
				?>><a href="<?php echo htmlspecialchars( $val['href'] ) ?>"<?php echo $skin->tooltipAndAccesskeyAttribs($val['id']) ?>><?php echo htmlspecialchars( $val['text'] ) ?></a></li>
<?php			} ?>
			</ul>
		</div>
	</div>
	<?php } ?>

Search[edit | edit source]

<div id="p-search" class="portlet">
	<h5><label for="searchInput"><?php $this->msg('search') ?></label></h5>
	<div id="searchBody" class="pBody">
		<form action="<?php $this->text('searchaction') ?>" id="searchform"><div>
			<input id="searchInput" name="search" type="text"<?php echo $skin->tooltipAndAccesskeyAttribs('search');
				if( isset( $this->data['search'] ) ) {
					?> value="<?php $this->text('search') ?>"<?php } ?> />
			<input type='submit' name="go" class="searchButton" id="searchGoButton"	value="<?php $this->msg('searcharticle') ?>"<?php echo $skin->tooltipAndAccesskeyAttribs( 'search-go' ); ?> />&nbsp;
			<input type='submit' name="fulltext" class="searchButton" id="mw-searchButton" value="<?php $this->msg('searchbutton') ?>"<?php echo $skin->tooltipAndAccesskeyAttribs( 'search-fulltext' ); ?> />
		</div></form>
	</div>
</div>

Toolbox[edit | edit source]

	<div class="portlet" id="p-tb">
		<h5><?php $this->msg('toolbox') ?></h5>
		<div class="pBody">
			<ul>
<?php
		if( $this->data['notspecialpage'] ) { ?>
				<li id="t-whatlinkshere"><a href="<?php
				echo htmlspecialchars($this->data['nav_urls']['whatlinkshere']['href'])
				?>"<?php echo $skin->tooltipAndAccesskeyAttribs('t-whatlinkshere') ?>><?php $this->msg('whatlinkshere') ?></a></li>
<?php
			if( $this->data['nav_urls']['recentchangeslinked'] ) { ?>
				<li id="t-recentchangeslinked"><a href="<?php
				echo htmlspecialchars($this->data['nav_urls']['recentchangeslinked']['href'])
				?>"<?php echo $skin->tooltipAndAccesskeyAttribs('t-recentchangeslinked') ?>><?php $this->msg('recentchangeslinked') ?></a></li>
<?php 		}
		}
		if( isset( $this->data['nav_urls']['trackbacklink'] ) ) { ?>
			<li id="t-trackbacklink"><a href="<?php
				echo htmlspecialchars($this->data['nav_urls']['trackbacklink']['href'])
				?>"<?php echo $skin->tooltipAndAccesskeyAttribs('t-trackbacklink') ?>><?php $this->msg('trackbacklink') ?></a></li>
<?php 	}
		if( $this->data['feeds'] ) { ?>
			<li id="feedlinks"><?php foreach($this->data['feeds'] as $key => $feed) {
					?><span id="feed-<?php echo Sanitizer::escapeId($key) ?>"><a href="<?php
					echo htmlspecialchars($feed['href']) ?>"<?php echo $skin->tooltipAndAccesskeyAttribs('feed-'.$key) ?>><?php echo htmlspecialchars($feed['text'])?></a>&nbsp;</span>
					<?php } ?></li><?php
		}
 
		foreach( array( 'contributions', 'blockip', 'emailuser', 'upload', 'specialpages' ) as $special ) {
 
			if( $this->data['nav_urls'][$special] ) {
				?><li id="t-<?php echo $special ?>"><a href="<?php echo htmlspecialchars($this->data['nav_urls'][$special]['href'])
				?>"<?php echo $skin->tooltipAndAccesskeyAttribs('t-'.$special) ?>><?php $this->msg($special) ?></a></li>
<?php		}
		}
 
		if( !empty( $this->data['nav_urls']['print']['href'] ) ) { ?>
				<li id="t-print"><a href="<?php echo htmlspecialchars($this->data['nav_urls']['print']['href'])
				?>"<?php echo $skin->tooltipAndAccesskeyAttribs('t-print') ?>><?php $this->msg('printableversion') ?></a></li><?php
		}
 
		if( !empty( $this->data['nav_urls']['permalink']['href'] ) ) { ?>
				<li id="t-permalink"><a href="<?php echo htmlspecialchars($this->data['nav_urls']['permalink']['href'])
				?>"<?php echo $skin->tooltipAndAccesskeyAttribs('t-permalink') ?>><?php $this->msg('permalink') ?></a></li><?php
		} elseif( $this->data['nav_urls']['permalink']['href'] === '' ) { ?>
				<li id="t-ispermalink"<?php echo $skin->tooltip('t-ispermalink') ?>><?php $this->msg('permalink') ?></li><?php
		}
 
		wfRunHooks( 'SkinTemplateToolboxEnd', array( &$this ) );
?>
			</ul>
		</div>
	</div>

Interlanguage Links[edit | edit source]

<?php if( $this->data['language_urls'] ) { ?>
	<div id="p-lang" class="portlet">
		<h5><?php $this->msg('otherlanguages') ?></h5>
		<div class="pBody">
			<ul>
<?php		foreach( $this->data['language_urls'] as $langlink ) { ?>
				<li class="<?php echo htmlspecialchars($langlink['class'])?>"><?php
				?><a href="<?php echo htmlspecialchars($langlink['href']) ?>"><?php echo $langlink['text'] ?></a></li>
<?php		} ?>
			</ul>
		</div>
	</div>
<?php } ?>

Footer[edit | edit source]

[iterative]

<div id="footer">
<?php
	if ( $this->data['poweredbyico'] ) { ?>
	<div id="f-poweredbyico"><?php $this->html('poweredbyico') ?></div>
<?php 	}
	if ( $this->data['copyrightico'] ) { ?>
	<div id="f-copyrightico"><?php $this->html('copyrightico') ?></div>
<?php	}
	// generate additional footer links
	$footerlinks = array(
		'lastmod', 'viewcount', 'numberofwatchingusers', 'credits', 'copyright',
		'privacy', 'about', 'disclaimer', 'tagline',
	);
?>
	<ul id="f-list">
<?php
	foreach ( $footerlinks as $aLink ) {
		if ( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {
?>		<li id="<?php echo $aLink ?>"><?php $this->html( $aLink ) ?></li>
<?php 		}
	}
?>
	</ul>
</div>

Closing Trail[edit | edit source]

This last section simply closes any sections from above and usually does not need to be altered.

<!-- scripts and debugging information -->
<?php $this->html('bottomscripts'); /* JS call to runBodyOnloadHook */ ?>
<?php $this->html('reporttime') ?>
<?php if ( $this->data['debug'] ): ?>
<!-- Debug output:
<?php $this->text( 'debug' ); ?>
 
-->
<?php endif; ?>
</body>
</html>
<?php
	wfRestoreWarnings();
	} // end of execute() method
} // end of class

Example changes[edit | edit source]

Category List Fix[edit | edit source]

This is a fix for returning category links as a proper UL element (instead of returning a mostly unordered string, which is the default behavior).

	/* hijack category functions to create a proper list */
 
	function getCategories() {
		$catlinks = $this->getCategoryLinks();
		if( !empty( $catlinks ) ) {
			return "<ul id='catlinks'>{$catlinks}</ul>";
		}
	}
 
	function getCategoryLinks() {
		global $wgOut, $wgUseCategoryBrowser;
		global $wgContLang;
 
		if( count( $wgOut->mCategoryLinks ) == 0 )
			return '';
 
		# separator
		$sep = '';
 
		// use Unicode bidi embedding override characters,
		// to make sure links don't smash each other up in ugly ways
		$dir = $wgContLang->isRTL() ? 'rtl' : 'ltr';
		$embed = "<li dir='$dir'>";
		$pop = '</li>';
		$t = $embed . implode( "{$pop} {$sep} {$embed}", $wgOut->mCategoryLinks ) . $pop;
 
		$msg = wfMsgExt( 'pagecategories', array( 'parsemag', 'escape' ), count( $wgOut->mCategoryLinks ) );
		$s = $this->makeLinkObj( Title::newFromText( wfMsgForContent( 'pagecategorieslink' ) ), $msg )
			. $t;
 
		# optional 'dmoz-like' category browser - will be shown under the list
		# of categories an article belongs to
		if( $wgUseCategoryBrowser ) {
			$s .= '<br /><hr />';
 
			# get a big array of the parents tree
			$parenttree = $this->getTitle()->getParentCategoryTree();
			# Skin object passed by reference because it can not be
			# accessed under the method subfunction drawCategoryBrowser
			$tempout = explode( "\n", $this->drawCategoryBrowser( $parenttree, $this ) );
			# clean out bogus first entry and sort them
			unset( $tempout[0] );
			asort( $tempout );
			# output one per line
			$s .= implode( "<br />\n", $tempout );
		}
 
		return $s;
	}

These functions need to be placed in the class that extends SkinTemplate in your template file. If you want to see the mediawiki versions of these functions, look for them in Skin.php.

See also[edit | edit source]

External[edit | edit source]

Language: English  • 日本語 • русский • 中文