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:

Planning

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…

Designing

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…

Layout

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 browsershots.org to do this yourself (its awesome).

Code

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 (http://allaboutchris.co.uk / me@allaboutchris.co.uk)
* @license http://creativecommons.org/licenses/by-nc/3.0/ 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
#require_once('includes/SkinTemplate.php');

// 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
wfSuppressWarnings();

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" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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') ?>">
<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>
<?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'] ?>";
/*]]>*/</style>
<?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">
Cufon.replace('h1');
</script>
</head>

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!

Leave a Reply

Your e-mail address will not be published. Required fields are marked *