Customizing MediaWiki
From ThemesWiki
| Official Page |
| Project Documentation |
| Download |
|
Contents |
[edit] Writing a New Skin
Usually we use existing skins in MediaWiki, and many times you might have had the question, "Can we add our own skin in the wiki?" The answer is very straightforward. Yes, we can make our own skin from scratch and add it to the directory for the skins. In this tutorial, we will discuss in detail how to add new skins, and how to build skins from scratch. We will follow a step-by-step procedure to build a skin. Here are the steps we need to follow when we create a new skin:
- Design the layout for the new skin.
- Create HTML, style properties, and integrate MediaWiki skin code.
Now let's get into the details of creating a new skin for our wiki.
[edit] Design the Layout for the New Skin
The first step in designing a skin is to visualize the skin, putting content at places of your choice. For this, it is always better to make a mental sketch of your design and then put it into place. You have to think about where to put which content, and also address what the content will look like. So let's design a new skin layout, where we will have a new type of header section where the logo, search, and general page-related links (such as edit, discussions, etc.) will be shown. The navigation, toolbar, and personal links (such as login, create account, preference, etc.) will be shown in the left sidebar. The layout will be similar to the following drawing:
As you can see from the drawing, we have divided our page into a few blocks to show different links and content. In the current web design scenario, a designer uses more fluid design tactics such as div-based design rather than rigid approaches such as table-based design. Div-based design gives more flexibility for designers, and for this reason, we will use div-based design to implement our layout. Let's now start implementing the HTML and style properties for the layout.
[edit] Creating HTML and Style Properties, and Integrating MediaWiki Skin Code
Before getting started with HTML and PHP code, we have to have a clear idea of the basic things that are required for a skin file. Here are few facts that we must remember:
- Every skin must have one file the skin file, with the skin's name as the file name with a
.phpextension and must also have a folder with the same name as the skin, for the CSS and image files. Suppose we want to create a new skin named haunting. Skin names are usually written as lowercase. But you have can write it in uppercase too. For our haunting skin we have to create a file namedhaunting.php, and a folder namedhaunting. Both the file and the folder must reside underskinsfolder of the MediaWiki installation. - If the skin file includes or requires any file, then we have to make a separate file named
skin_name.deps.php. The purpose of this file is to ensure that base classes are preloaded before compiling the skin file.
So let us create a file named haunting.php, and a folder named haunting for our new skin. In the haunting.php file, we have to include the following code:
<?php
if( !defined( 'MEDIAWIKI' ) )
die(-1);
require_once('includes/SkinTemplate.php');
class Skinhaunting extends SkinTemplate
{
function initPage( &$out )
{
SkinTemplate::initPage( $out );
$this->skinname = 'haunting';
$this->stylename = 'haunting';
$this->template = 'hauntingTemplate';
}
}
class hauntingTemplate extends QuickTemplate
{
function execute()
{
// Suppress warnings to prevent notices about missing indexes in
// $this->data
wfSuppressWarnings();
}
}
?>
This code extends the SkinTemplate.php class to make our new haunting skin class. The code if( !defined( 'MEDIAWIKI' )) first checks if the call is from MediaWiki. This is for security reasons, and if the file is not called locally, the code execution will stop at this point.
In the next code block, we declare a new skin class Skinhaunting, which extends the SkinTemplate.php class. For initializing the class, we set three properties from the parent class SkinTemplate: skin name, style name, and template name.
The template name defines the template file to be used for generating the output (we have declared a new template named hauntingTemplate, which we have defined at the end). This hauntingTemplate class extends the parent class QuickTemplate and overrides the execute() function, which is called during the skin's generation. Inside the execute() function, we have to put our design and contents so that we have the desired output generated when users view the skin. Now, let us put our HTML and CSS code together, and view the results in the browser before inserting it in the execute() function:
<html> <head> <link rel="stylesheet" type="text/css" media="screen" href="/haunted/skins/haunting/haunting.css" /> </head> <body> <div id="container"> <div id="header"> <!-- start of HEADER div --> </div> <!-- end of HEADER div --> <div id="mBody"> <!-- start of MBODY div --> <div id="side"> <!-- start of SIDE div --> </div> <!-- end of SIDE div --> <div id="mainContent"> <!-- start of MAINCONTENT div --> </div> <!-- end of MAINCONTENT div --> </div> <!-- end of MBODY div --> <div id="footer"> <!-- start of FOOTER div --> </div> <!-- end of FOOTER div --> </div> <!-- end of the CONTAINER div --> </body> </head> </html>
As you can see from the code, we have added a CSS file that actually defines our style properties for the HTML tags that have been used in our design. First we built a container div, which holds all the bits and pieces together. Inside the container, we have added a header section, a main body section, and a footer section.
The main body section is further divided into two parts. The left part is designated as the sidebar. The right section is wider than the sidebar and is marked as the main content section. In order to define the width and height of the <div> tags and the overall layout, we have to look at the CSS file to find out the properties of the file. Here is the CSS file that we have defined for the template:
body {
min-width: 610px;
margin: 20px;
}
#container
{
max-width: 70em;
margin: 0 auto;
}
#mBody
{
clear: both;
padding: 0 0 1em 0;
}
#side
{
float: left;
width: 23%;
margin-bottom: 1em;
border: 1px solid #000;
height:40px;
}
#mainContent
{
float: right;
width: 75%;
margin-bottom: 1em;
border: 1px solid #000;
height:40px;
}
#header
{
margin-bottom: 1em;
border: 1px solid #000;
height:40px;
}
#footer
{
clear: both;
margin-top: 1em;
border: 1px solid #000;
height:40px;
}
You can see that we have defined the width of the <div> tags and their margins, and alignments, as well as a default height with a border to show on the screen. For this code, we will get an image like the following:
We have built the skeleton for our new skin. Now let's insert some content into it so that it looks much better than this. The hauntingTemplate class takes an associative array of data set from a SkinTemplate class and a wrapper for MediaWiki's localization database to output a formatted page. So we have to use that associative array to retrieve the required data.
Let's populate the header section:
function execute()
{
wfSuppressWarnings();
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php $this
>text('lang') ?>" lang="<?php $this->text('lang') ?>" dir="<?php
$this->text('dir') ?>">
<head>
<meta http-equiv="Content-Type" content="<?php $this->text('mimetype') ?>;
charset=<?php $this->text('charset') ?>" />
<?php $this->html('headlinks') ?>
<title><?php $this->text('pagetitle') ?></title>
<style type="text/css" media="screen,projection">
/*<![CDATA[*/ @import "<?php $this->text('stylepath') ?>/
<?php $this->text('stylename') ?>/main.css"; /*]]>*/
</style>
<link rel="stylesheet" type="text/css" media="print"
href="<?php $this->text('stylepath') ?>/common/commonPrint.css" />
<?php if($this->data['jsvarurl' ])
{ ?>
<script type="text/javascript" src="<?php $this->text('jsvarurl' )
?>"></script><?php } ?>
<script type="text/javascript" src="<?php $this->text('stylepath' ) ?>
/common/wikibits.js"></script>
<?php if($this->data['usercss' ]) { ?><style type="text/css">
<?php $this->html('usercss' ) ?></style><?php } ?>
<?php if($this->data['userjs' ]) { ?><script type="text/ javascript"
src="<?php $this->text('userjs' ) ?>"></script><?php } ?>
<?php if($this->data['userjsprev']) { ?><script type="text/ javascript">
<?php $this->html('userjsprev') ?></script><?php } ?>
</head>
This code section defines the header for our new skin. It includes the main.css file from our haunted folder. We will see how to define the main.css file just a little bit later. The code section also includes a few common files such as the printing CSS file from the common folder in the skin directory as well as the common JavaScript file wikibits.js. These files are loaded if user CSS and user JavaScript is enabled. Now let's start adding the content to the body. As we already know we have to use the associative array from the SkinTemplate class, we will use the convention $this->data for the rest of the code section. We will first replace the header section code with new code and then explain what is actually going on.
<?php if($this->data['sitenotice']) { ?><div id="siteNotice"><?php
$this->html('sitenotice') ?></div><?php } ?>
<div id="header">
<a name="top" id="contentTop"></a>
<h1><a href="<?php echo htmlspecialchars
($this->data['nav_urls']['mainpage']['href'])?>"
title="<?php $this->msg('mainpage') ?>">
<?php $this->text('title') ?></a></h1>
<ul>
<?php foreach($this->data['content_actions'] as $key => $action) { ?>
<li <?php if($action['class']) { ?>class="<?php echo
htmlspecialchars($action['class']) ?>"<?php } ?> >
<a href="<?php echo htmlspecialchars($action['href']) ?>">
<?php echo htmlspecialchars($action['text']) ?></a></li>
<?php } ?>
</ul>
<form name="searchform" action="<?php $this->text( 'searchaction') ?>"
id="search">
<div>
<label for="q"><?php $this->msg('search') ?></label>
<input id="q" name="search" type="text"
<?php if($this->haveMsg('accesskey-search')) {?>
accesskey="<?php $this->msg('accesskey-search') ?>"
<?php } if( isset( $this->data['search'] ) ) { ?>
value="<?php $this->text('search') ?>"
<?php } ?> />
<input type="submit" name="go" class="searchButton"
id="searchGoButton" value="<?php $this->msg('go') ?>" />
<input type="submit" name="fulltext" class="searchButton"
value="<?php $this->msg('search') ?>" />
</div>
</form>
</div>
Let's have a deeper look inside the code we've just seen. The first line checks if the site notice is enabled. If site notice is enabled then the notice will be shown at the top of the page. After that we define the header section, where we are defining an anchor for the page so that whenever you scroll down the page and click the link named Top, it will take you to the top of the page. The <h1> tag is actually defining the logo for the site with a link to the main page of the site. The logo property is defined in main.css file.
After the logo is set, we set the links for the page operation, such as edit, discussion, history, etc. $this->data['content_actions'] holds all the actions defined for a particular page. After that we put the search box in the header section. Although it seems that we are putting things together and creating a code mess, the reality is different. The positioning and look of the different content will be decided by the CSS, which we will see later.
Now we will populate data in the sidebar section. The following code block loads the navigation links in the side bar. We already know the content of the navigation bar. As you can see, the navigation bar's contents are kept in the sidebar index of the associative array from the following code. Using the sidebar values we are creating links for all the available links in the sidebar.
<div id="side">
<?php foreach ($this->data['sidebar'] as $bar => $cont)
{ ?>
<ul id="nav">
<li><span><?php $out = wfMsg( $bar ); if (wfEmptyMsg($bar, $out)) echo $bar; else echo $out; ?></span>
<?php foreach($cont as $key => $val)
{ ?>
<li id="<?php echo htmlspecialchars($val['id']) ?>"<?php
if ( $val['active'] ) { ?> class="active" <?php }
?>><a href="<?php echo htmlspecialchars($val['href']) ?>"><?php echo htmlspecialchars($val['text']) ?></a></li>
<?php } ?>
</ul>
<?php } ?>
The following code populates the personal URL section links, such as create an account/login, logout, my preferences, my watchlist, my talk, etc.
<ul id="nav">
<li><span><?php $this->msg('personaltools') ?></span>
<?php foreach($this->data['personal_urls'] as $key => $item)
{
?><li id="pt-<?php echo htmlspecialchars($key) ?>"><a href="<?php
echo htmlspecialchars($item['href']) ?>"<?php
if(!empty($item['class']))
{ ?>
class="<?php
echo htmlspecialchars($item['class']) ?>"<?php } ?>><?php
echo htmlspecialchars($item['text']) ?></a></li><?php
} ?>
</ul>
The following code populates the toolbox section of the sidebar. The common links in the toolbox section such as recent changes, what links here, upload files, special pages, etc. are loaded.
<ul id="nav">
<li><span><?php $this->msg('toolbox') ?></span>
<?php if($this->data['notspecialpage']) { foreach( array( 'whatlinkshere', 'recentchangeslinked' ) as $special )
{ ?>
<li id="t-<?php echo $special?>"><a href="<?php
echo htmlspecialchars($this->data['nav_urls'][$special]['href'])
?>"><?php echo $this->msg($special) ?></a></li>
<?php }
} ?>
<?php if($this->data['feeds'])
{ ?><li id="feedlinks"><?php foreach($this->data['feeds'] as $key => $feed)
{
?><span id="feed-<?php echo htmlspecialchars($key) ?>"><a href="<?php
echo htmlspecialchars($feed['href']) ?>"><?php echo htmlspecialchars($feed['text'])?></a> </span>
<?php } ?></li><?php } ?>
<?php foreach( array('contributions', 'emailuser', 'upload', 'specialpages') as $special )
{ ?>
<?php if($this->data['nav_urls'][$special])
{?><li id="t-<?php echo $special ?>"><a href="<?php
echo htmlspecialchars($this->data['nav_urls'][$special]['href'])
?>"><?php $this->msg($special) ?></a></li><?php } ?>
<?php } ?>
</ul>
The last addition to the sidebar is the language URLs. If multiple languages are supported on the site, then this code will show the supported languages' links in the sidebar just below the toolbox section.
<?php if( $this->data['language_urls'] )
{ ?>
<ul id="nav">
<li><span><?php $this->msg('otherlanguages') ?></span>
<?php foreach($this->data['language_urls'] as $langlink)
{ ?>
<li>
<a href="<?php echo htmlspecialchars($langlink['href'])
?>"><?php echo $langlink['text'] ?></a>
</li>
<?php } ?>
</ul>
<?php } ?>
</div><!-- end of SIDE div -->
Next we will populate the main content section of the page, which can be done using the following code:
<div id="mainContent">
<h1><?php $this->text('title') ?></h1>
<h3 id="siteSub"><?php $this->msg('tagline') ?></h3>
<div id="contentSub"><?php $this->html('subtitle') ?></div>
<?php if($this->data['undelete']) { ?><div id="contentSub">
<?php $this->html('undelete') ?></div><?php } ?>
<?php if($this->data['newtalk'] ) { ?><div class="usermessage">
<?php $this->html('newtalk') ?></div><?php } ?>
<!-- start content -->
<?php $this->html('bodytext') ?>
<?php if($this->data['catlinks']) { ?><div id="catlinks">
<?php $this->html('catlinks') ?></div><?php } ?>
<!-- end content -->
</div><!-- end of MAINCONTENT div -->
The code is pretty straightforward and also similar to what we have seen when we modified the MonoBook.php file. The basic difference will be made by the layout of the divs and the style that we apply to them. Now let's finish the code for haunting.php by adding the code for the footer section. Here it is:
<div id="footer">
<table><tr>
<td align="left" width="1%" nowrap="nowrap">
<?php if($this->data['copyrightico']) { ?><div id="f-copyrightico">
<?php $this->html('copyrightico') ?></div><?php } ?></td>
<td align="center">
<?php if($this->data['lastmod' ]) { ?><span id="f-lastmod">
<?php $this->html('lastmod') ?></span><?php } ?>
<?php if($this->data['viewcount' ]) { ?><span id="f-viewcount">
<?php $this->html('viewcount') ?> </span><?php } ?>
<ul id="f-list">
<?php if($this->data['credits' ]) { ?><li id="f-credits">
<?php $this->html('credits') ?></li><?php } ?>
<?php if($this->data['copyright' ]) { ?><li id="f-copyright">
<?php $this->html('copyright') ?></li><?php } ?>
<?php if($this->data['about' ]) { ?><li id="f-about">
<?php $this->html('about') ?></li><?php } ?>
<?php if($this->data['disclaimer']) { ?><li id="f-disclaimer">
<?php $this->html('disclaimer') ?></li><?php } ?>
</ul>
</td>
<td align="right" width="1%" nowrap="nowrap">
<?php if($this->data['poweredbyico']) { ?>
<div id="f-poweredbyico"><?php $this->html('poweredbyico') ?>
</div><?php } ?></td>
</tr></table>
</div>
We are now done with structuring the layout with new code based on the skin template data. However, we haven't seen the CSS for this defined structure. The CSS for this skin will be so huge that it would take pages to describe each of the CSS files.
Instead of doing so, we will see a few of the CSS properties. The complete CSS files will be available for download from http://www.packtpub.com as a complete skin download. So here are a few CSS properties defined for the skin's header section:
/* Header */
#header
{
background: #455372 url("header_bl.png") bottom left repeat-x;
position: relative;
min-height: 39px;
height: 5em;
padding: 0;
height: 3em;
padding: 15px 0;
}
#header h1
{
position: absolute;
top: 0;
left: 0;
margin: 0;
font-size: 2px;
background: url("header_tl.gif") no-repeat;
height: 8px;
z-index: 100; /* above the UL */
}
#header h1 a
{
display: block;
width: 268px;
height: 64px;
background: transparent url("header_logo.gif") no-repeat;
text-indent: -700em;
text-decoration: none;
}
#header ul
{
width: auto;
position: absolute;
bottom: 0;
right: -1;
margin: 0;
padding: 0 15px 0 0;
list-style: none;
background: url("header_br.gif") no-repeat bottom right;
z-index: 90; /* below the H1 */
}
#header li
{
float: right;
background: transparent url("header_tab.gif") 100% -600px no-repeat;
padding: 0 6px 0 0;
margin: 0 1px 0 0;
border-bottom: 1px solid #515358;
}
#header ul a
{
float: left;
display: block;
padding: 4px 4px 4px 10px;
background: transparent url("header_tab.gif") 0% -600px no-repeat;
font-weight: bold;
color: #fff;
text-decoration: none;
}
#header ul li:hover a
{
background-position: 0% -400px;
}
#header ul li:hover
{
background-position: 100% -400px;
}
/* Search Field */
#header form
{
width:auto;
position: absolute;
top: 0;
right: -1;
padding: 12px 20px 0 0;
background: url("header_tr.gif") no-repeat top right;
margin: 0; /* need for IE Mac */
text-align: right; /* need for IE Mac */
white-space: nowrap; /* for Opera */
}
#header form label { color: #fff; font-size: 85%; }
#header form input { font-size: 85%; }
#header form #submit
{
font-size: 85%;
background: #6A7389;
color: #fff;
padding: 1px 4px;
border-right: 1px solid #283043;
border-bottom: 1px solid #283043;
border-top: 1px solid #9097A2;
border-left: 1px solid #9097A2;
}
#header form #q
{
width: 170px;
font-size: 85%;
border: 1px solid #9097A2;
background: #D9DBE1;
padding: 2px;
}
#header form #q:hover, #header form #q:focus
{
background: #fff;
}
The final result of the skin can be seen in the following screenshot. You just need to enable the skin from your user preference or make it the default for your site for it to take effect.
We have changed the look of our wiki site by making a new layout and defining new style properties for the tags we have used. By applying this knowledge, you can create any type of skin you want.
[edit] Additional References
For instructions on installing MediaWiki, click here
[edit] Source
The source of this content is Chapter 8: Customizing MediaWiki of MediaWiki Administrators’ Tutorial by Mizanur Rahman (Packt Publishing, 2007).
