Making a MediaWiki Theme

I love MediaWiki. I’ve been using it for MedRevise since 2007.

After 3 years of using a hacked up version of someone else’s theme, I decided to make my own theme. It was a big learning process, and I decided to share my knowledge… Unfortunately, 5 years ago, I stopped writing this how-to halfway through. It was for MediaWiki version 1.17.

Since then, there have been like 7 new major versions, and everything in “Code” I’ve written is hopelessly out of date. But the first three sections still have some value: Planning, Designing and Layout – so I thought I would publish it anyway.

Make your own Mediawiki theme

Ever thought it would be nice/useful to have your own wiki? There are lots of different bits of software out there for running a wiki, but the big one is MediaWiki – the same one used by Wikipedia. Now, your problem is that there are only so many ready made themes for MediaWiki. And there aren’t many good tutorials on doing it yourself. The tutorials out there are sparse at least.

So I’m going to give it a go, and I’ll explain it to you as I go. I warn you, this is aimed at an intermediate level. I am not going to explain how a div works, how to use CSS or much of that. Go to the amazing w3schools website for tutorials on these basics.

First things first.

There are four key stages to making any website:


You need to ask yourself some questions:

  • What is your website for? If there is a lot of information, you need to give prevalence to the content section, if there are lots of sections, maybe the menu needs extra prominence.
  • Who will use it? Is it going to be aimed at people new to the web, in which case it needs to be very clear and understandable. If its aimed at geeks, you maybe can play with the appearance more.
  • What will code put in? Database driven sites such as a wiki will need to import information. This information is usually of different sizes and lengths, in which case you will need to have an expandable or scrolling area for this information. Examples are menus, footer tags and content divs. Once you have really thought it out, get a piece of paper, and start sketching out some ideas, taking into account all your stuff above. Once you have a good idea, you can start…


Get yourself a good web graphics program. Photoshop isn’t really ideal here, lacking many of the measurement, image optimisation and slicing options that Fireworks has. But yeh, that’s my plug over. Get designing, and put in all the elements you think you need. Put in text and everything, and try to have all the text on a separate layer, so you can show the layout later without it. (If you don’t understand this, you’ll get it in the next step). Here is my first design for the new MedRevise:

Mockup of the design for the site.

Now, that is really very lovely. At least I think so, and its my site, so blah! And while I’m on the subject of accepting criticism, now is the time to get friends, families and geeks to look at this and give you feedback, before you spend hours putting it in code and everyone hates it. If you need a geek to ask, feel free to contact me.

Once your mum has finished telling you to add more flowers, and you are happy with your design, you can move onto…


You now need to turn your image into a web page. The first step is getting rid of all your text. Simple click the “eye” symbol next to your text layer, and you should end up with something like the image on the right:

Now, this step is complex, time consuming and laborious. It involves making all your divs and everything. I have chosen a very complicated design here, and I will not explain how to do everything. I will upload a tutorial at some point explaining how I got my middle div working, because I’m quite proud of that.

But basically, you want to end up with a site where you have your template design set up, with text tags saying “Insert Menu Code Here”, and “Insert Content Code Here”. In my case, I have decided to have a difficult left hand menu, so I will have to manually code changes to it, rather than having the option of mediawiki manually inserting the code for you.

Either way, you should end up with somewhat that looks like this… Screenshot of the finished template You might notice that I have moved my footer bar into the middle, as I realised it will work better there. Aside from this, I have kept it relatively close to my original design. I have also tested in in Firefox, Chrome, IE6, IE7 and IE8, to ensure that the majority of people accessing the site get to see it correctly. Use to do this yourself (its awesome).


The final stage is making your theme do the things you want it to do. This can often take you as long, if not longer than everything else put together.

First off, go and read the MediaWiki manual on skinning.

Then start working through the article, changing it as you go through. I began by tackling the preheader. I used the following code:

* MedRevise skin
* @version 4.0.0
* @author Chris Lowry ( /
* @license Attribution-Noncommercial 3.0 Unported

// initialize
if( !defined( 'MEDIAWIKI' ) ){
die( "This skin file is not a valid entry point.\n" );

#Only needed for older MediaWiki instances

// inherit main code from SkinTemplate, set the CSS and template filter
class SkinMedRevise extends SkinTemplate {
function initPage( OutputPage $out ) {
parent::initPage( $out );
$this->skinname = 'medrevise';
$this->stylename = 'medrevise';
$this->template = 'MedReviseTemplate';

class MedReviseTemplate extends QuickTemplate {
/* 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, $wgUser, $wgTitle, $wgUseCategoryBrowser;
global $wgContLang;

if( count( $wgOut->mCategoryLinks ) == 0 )
return '';

$skin = $wgUser->getSkin();

# 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 = $skin->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 = $wgTitle->getParentCategoryTree();
# Skin object passed by reference because it can not be
# accessed under the method subfunction drawCategoryBrowser
$tempout = explode( "\n", Skin::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;

* 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 $wgUser, $wgSitename, <span style="color: #ff0000;">$wgTitle</span>;
$skin = $wgUser->getSkin();

// retrieve site name
$this->set( 'sitename', $wgSitename );

// suppress warnings to prevent notices about missing indexes in $this->data

Now, I’ll be honest, I didn’t understand most of that. However, the Mediawiki walkthrough explained it nicely, and pretty much all I did was change the FooBar and foobar tags to MedRevise and medrevise. I also added $wgTitle to the execute function. I needed that for my login menu later. That done, it was time to chuck in the HTML header:

/* compose XHTML output */
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
<html xmlns="<?php $this->text('xhtmldefaultnamespace') ?>" <?php
foreach( $this->data['xhtmlnamespaces'] as $tag => $ns ) {
?>xmlns:<?php echo "{$tag}=\"{$ns}\" ";
} ?>xml:lang="<?php $this->text('lang') ?>" lang="<?php $this->text('lang') ?>" dir="<?php $this->text('dir') ?>">
<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>
<?php /*** general style sheets ***/ ?>
<style type="text/css" media="screen,projection">/*<![CDATA[*/
@import "<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/main.css?<?php echo $GLOBALS['wgStyleVersion'] ?>";
@import "<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/contents.css?<?php echo $GLOBALS['wgStyleVersion'] ?>";
<?php /*** media-specific style sheets ***/ ?>
<link rel="stylesheet" type="text/css" <?php if(empty($this->data['printable']) ) { ?>media="print"<?php } ?> href="<?php $this->text('stylepath') ?>/common/commonPrint.css?<?php echo $GLOBALS['wgStyleVersion'] ?>" />
<link rel="stylesheet" type="text/css" media="handheld" href="<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/handheld.css?<?php echo $GLOBALS['wgStyleVersion'] ?>" />
<?php print Skin::makeGlobalVariablesScript($this->data); ?>
<?php /*** various MediaWiki-related scripts and styles ***/ ?>
<script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('stylepath') ?>/common/wikibits.js?<?php echo $GLOBALS['wgStyleVersion'] ?>"><!-- wikibits js --></script>
<?php if($this->data['jsvarurl']) { ?>
<script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('jsvarurl') ?>"><!-- site js --></script>
<?php } ?>
<?php if($this->data['pagecss']) { ?>
<style type="text/css"><?php $this->html('pagecss') ?></style>
<?php }
if($this->data['usercss']) { ?>
<style type="text/css"><?php $this->html('usercss') ?></style>
<?php }
if($this->data['userjs']) { ?>
<script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('userjs' ) ?>"></script>
<?php }
if($this->data['userjsprev']) { ?>
<script type="<?php $this->text('jsmimetype') ?>"><?php $this->html('userjsprev') ?></script>
<?php }
if($this->data['trackbackhtml']) print $this->data['trackbackhtml']; ?>
<!-- Head Scripts -->
<?php $this->html('headscripts') ?>
<!-- Cufon Scripts -->
<script src="<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/js/cufon-yui.js" type="text/javascript"></script>
<script src="<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/js/Blippo.font.js" type="text/javascript"></script>
<script type="text/javascript">

I will be the first to admit that looks pretty awful. All you need to know is that you leave it basically untouched, simply adding the correct path to your style sheet, if necessary (I just had to rename mine to main.css), then add any scripts you want to add yourself at the end. I use cufon for font replacement, so I chucked that in at the end.

Next comes the nitty gritty, making individual bits and pieces appear exactly where you want them. I first decided to tackle the search bar, altering the code in the tutorial, and simplifying it because I only want one search button, not two.

I then worked out my login details section, and wrote some conditional code to do one thing when logged in, and another when logged out.

Thanks for reading, I hope its helpful to anyone who needs some (rather dated) hackery!

Blog redesign

Why Not Actually Finish Something You Have Started?I’ve been planning on a blog redesign for at least 6 months now: probably more.

Not much has happened.

A kick up the bum

I got all excited, I made a design, and then I did about a day’s work on the CSS. And then nothing. In order to nag myself into getting more done, I have decided to launch the unfinished theme. This is it. As you can see, its a little rough round the edges.

Shamed into action

The hope is that I will actually want to have a working site, and will thus push on with, well, finishing it.

“Productivity is never an accident. It is always the result of a commitment to excellence, intelligent planning, and focused effort.”

Paul J Meyer

Multiple header sizes…

Are an important part of website design

Even though I never…

…use ones this small!

Things I could do

As you may realise, I’m also using this post to throw a variety of elements into the blog, so I can check I have styling for them all. I also need to display some numbered and bulleted lists, but I can’t think of a relevant list to write. So, instead…

My favourite colours:

  • Blue
  • Purple
  • Golden Yellow
  • Black

Least favourite books ever:

  1. Granddad with Snails
  2. The Go Between
  3. Not really got any others.

The end of the post

Thanks for reading! Keep nagging me to finish this!

Five places to waste your time

Have you got a list of a million items on your to do list? Welcome to my world…

The internet is a wonderful invention, but it can be used for good or evil. In the midst of trying to get stuff done, I’m constantly distracted by other things to click on, to read, to learn about.

“It’s a job that’s never started that takes the longest to finish.”
~J. R. R. Tolkien

Twitter is my absolute No 1 stop for distraction, but its such an amazing/terrible invention that I’ll give it a post all its own at some another time. For now (and as a further piece of procrastination) here is a list of five of my favourite sites for wasting my time:


Lifehacker is a fantastic place to read interesting articles about becoming more productive. It’s hacking your life: literally trying to reset how we function, and find more efficient ways of living life. Of course, if you mostly just read Lifehacker when you should be working, its going to be, rather depressingly ironically, totally counterproductive.

Favourite bits:  Why Coffee May Not Be HelpingWallpaper WednesdaysAlways Up To Date Guide For Rooting Any Android Phone, The Headphone Cable Hack


Slashdot logo

Slashdot was named specifically to be annoying to pronounce. Try saying ” HTTP colon slash slash WWW dot SLASH DOT dot ORG” – fun, eh? That’s pretty geeky, and a perfect introduction to the site, which gives news about tech, web and geekdom, with a slant towards open source. I find it a great place to fantasise about having the tech chops to be a true sysadmin – even if I suspect I’ll never get further than running my own home server.  The comments are also always detailed, informative and entertaining.

Favourite bits: Ask Slashdot – users post their own technical challenges for community help, Slashdot Polls – see large scale responses to tech questions that relate to life. Also, check out the Quotes right at the bottom of each page.


Engadget logo

A lot more polished than Slashdot, Engadget is my place to learn about all the exciting new shiny gadgets that are coming to the world over the next few months. Despite the fact I never buy any of them, and generally have no desire to own one, I still read in depth reviews of new phones, laptops and gizmos frequently, when I could be better spending my time.

Favourite bits: Generally just enjoying reading the latest articles, but the Reviews are my favourite, regardless of the item. Engadget is also my preferred source of Liveblog when there’s a new Apple/Google/Palm/etc launch event.

BBC News & Timeslive

BBC & Times live logosAs a little bit of a news addict, I tend to visit two main sites: BBC News for my UK hit, and Timeslive for South African snippets. The BBC are blatantly the best news organisation in the world, and their site is a testament to that – its currently the fifth most visited site in the UK. Whilst less well written, I enjoy visiting the SA Times website to get an inside flavour of how things are going in South Africa: since we are planning to move there, its good to know when a government department can’t account for £100 million of its budget.

Favourite bits: The front page of each is my main port of call, but I also rather enjoy the BBC’s Science & Environment section, and Times Live coverage of SA Politics. When I want to feel especially low, BBC Sport are always there for me with the latest Orient scores


Of all the sites mentioned here, Reddit is the only one I’m slightly ashamed of. The self styled “front page of the internet”, it is a community, much like Slashdot, where articles and links are upvoted to gain precedence on the site. However, it has a much more puerile mix of images, links and comments. I’m a recent convert from Digg to Reddit, and whilst I spend less time on reddit than on the others above, it’s definitely a good destination if you urgently need to put off doing something. I refuse to register an account or I’ll never get anything done again!

Favourite bits: The never ending stream of irrelevance that is the front page, but also AskReddit, where people present their real world problems and are *generally* supported, encouraged and helped, with a sprinkling of sarcasm and trolling.


So, there we go. I hope this list helps you to not achieve something in your life quite soon. Just reading this post has probably been a good start!

New page: MarketPress Grid Plugin

I‘ve been hanging out over at the WPMU-DEV forums quite a lot over the last few months, and I decided to contribute to the community with an update of one of the plugins for MarketPress.

MarketPress is a pretty good, simple e-commerce plugin for WordPress, but it lacks a grid layout option. This plugin adds that feature.

Anyway check out the new page, where you can download version 0.3 of the MarketPress Grid Plugin.

Maintenance page with .htaccess

Photo of a diversion signIn keeping with my post about hiding simple changes to a site in php, I thought I would share my method for hiding bigger changes using .htaccess.

My other method is great if you are just changing one file, but tonight I am upgrading the MediaWiki installation over at MedRevise, so I want to hide the whole site until I’m done.

I didn’t just want a blank space, so I sent my visitors to the MedRevise blog, where I put a “Sorry, I’m updating!” message, whilst keeping it so that I could still access the site myself.

How did I manage this magic? I simply changed .htaccess file to the following:

RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^123\.123\.123\.123$
RewriteRule 302 [^/]*$ /blog/

I’ll take you through it:

  1. First off, RewriteEngine On turns on the Rewriting system in Apache.
  2. Then RewriteCond %{REMOTE_ADDR} !^123\.123\.123\.123$ tells Apache “For all ip addresses except, do the next line“.
  3. Finally  RewriteRule 302 [^/]*$ /blog/ sets up a temporary rewrite of any files from root to the blog directory. The 302 redirect tells search engines that this is just a temporary redirect.


Image by Ian Britton. Thanks!