Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Customizing MediaWiki

Creating and installing extensions

Chris Herborth (chrish@pobox.com), Freelance Writer, Author
Photo of Chris Herborth
Chris Herborth is an award-winning senior technical writer with more than 10 years of experience writing about operating systems and programming. When he's not playing with his son, Alex, or hanging out with his wife, Lynette, he spends his time designing, writing, and researching (that is, playing) video games.

Summary:  MediaWiki is the popular wiki engine behind sites like Wikipedia. Its power and flexibility makes it an excellent choice for a community-driven knowledge base. The ease of developing various extensions for MediaWiki is one of the sources of this flexibility. This article will show you how to create different types of extensions for MediaWiki: wiki variables, special pages, and new tags. You'll also get a quick overview of what you'll need to do to create skins for MediaWiki.

Date:  06 Jul 2010
Level:  Intermediate PDF:  A4 and Letter (251KB | 16 pages)Get Adobe® Reader®
Also available in:   Korean  Japanese  Portuguese

Activity:  22315 views
Comments:  

Introduction

The MediaWiki application is probably best known for being the engine behind Wikipedia. Many people are finding that MediaWiki provides a usable environment for sharing information within workgroups and even entire organizations, as well as online communities. MediaWiki allows users to share information via blogs, wikis, and files. It also allows you to secure uploaded files, tag files for easy locating, and locate experts using a tag cloud. For more information, see Resources.

What if you want to introduce custom information that you don't want to manually update and insert into your wiki pages? What if you want to provide custom output formatting for a particular type of information? It's situations like these where MediaWiki makes sense, since you can easily add these site-specific features through the use of extensions.

Let's take a look at how you can create MediaWiki extensions that cooperate with different information sources while providing the data through the familiar user interface of the wiki page.


MediaWiki extensions

Extensions can add new tags to the wiki markup used to write articles, add new reporting and administrative features by creating special pages, change the look and feel of the wiki through formatting skins, and even integrate with external authentication methods (although authentication won't be covered in this article).

Extensions are written in PHP and make use of MediaWiki's various internal hooks, classes, and methods to get their jobs done efficiently. While you can develop and deploy MediaWiki using any supported Web server and your favorite PHP development environment, you will be using the following in this article:

  • Eclipse V3.5.2 — Support for a wide range of programming languages and environments
  • PHP Development Tools (PDT) V2.2.0 — A PHP plug-in for Eclipse
  • MAMP Pro V1.9 — A handy package for Mac OS X, which provides Apache, MySQL, and PHP in an isolated environment with a helpful GUI front end. Even though OS X ships with Apache and PHP installed, I opted to use this because the version of PHP in OS X V10.6 Snow Leopard (V5.3.1) apparently has a bug that prevents MediaWiki from operating correctly.
  • MediaWiki V1.15.3 — The current stable version of MediaWiki

You can find all these in the Resources section.

Before you jump into looking at the different kinds of extensions, let's take a quick look at the folder and file layout used by most of them. After that, you'll have a high-level overview of skin extensions to change the look and feel of your MediaWiki site. Next you'll create a special-page extension that produces some administrative statistics. Finally, you'll see how to add custom XML tag markup support you can take advantage of while writing wiki pages.


Extension anatomy

MediaWiki extensions get installed in the extensions directory in the main MediaWiki path. Most modern extensions are installed in their own directory and consist of three files (extension is the name of the extension):

  • extension/extension.php
  • extension/extension.body.php
  • extension/extension.i18n.php

The first file performs initialization and any setup tasks. The second file is the body of the extension; this is the working code that implements the extension. Finally, the last file contains internationalization (i18n is a common short form) strings. By abstracting your extension's message strings into the i18n file, you can provide localized versions of your extension for any of MediaWiki's supported locales (assuming you can find some help translating the text).

As an example, I've created a sort of Hello World extension called CHTimeStamp (see Downloads for the source code for this example and the other examples in this article). CHTimeStamp will insert the current date/time stamp whenever someone inserts {{CHSTAMP}} on a wiki page. It consists of the following files:

  • CHTimeStamp/CHTimeStamp.php
  • CHTimeStamp/CHTimeStamp.body.php
  • CHTimeStamp/CHTimeStamp.i18n.php

Figure 1. CHTimeStamp layout in Eclipse
Screenshot of the CHTimeStamp file structure in Eclipse

The CHTimeStamp extension adds a {{CHSTAMP}} variable to MediaWiki's markup. Whenever you put {{CHSTAMP}} into a page, it's replaced by a timestamp. Trivial and easy to follow, right? If you're curious, please take a look at the code (see Download); I'm only describing it in broad strokes here to introduce you to the general layout and conventions of MediaWiki extensions.

My CHTimeStamp.php registers the internationalization messages file, tells the wiki engine that it can find the CHTimeStamp class in CHTimeStamp.body.php and adds the CHTimeStamp::registerHooks method to the array of extension functions.

In CHTimeStamp.body.php, you define the CHTimeStamp class. If you look at the code, this is made up entirely of static methods, so it could have also been written as a series of functions without changing the extension's behavior. CHTimeStamp's registerHooks method registers static methods to create the {{CHSTAMP}} variable and to handle pages that use it.

Finally, in CHTimeStamp.i18n.php, I've created translations for the only static string in the extension: its description. With the help of Google Translate, CHTimeStamp supports French, German, and Spanish locales. But I hope the automated translations didn't turn my English into awkward (or inappropriate) blurbs!

After you've created or downloaded an extension, you'll need to install it into MediaWiki and activate it.


Installing an extension

Once you have an interesting or useful extension ready for your MediaWiki site, you'll want to install and enable it:

  1. Copy or unpack the extension into MediaWiki's extensions directory.
  2. Edit LocalSettings.php in MediaWiki's root directory. Using your favorite text editor, add lines to configure the new extension, then activate it using PHP's require_once() statement.

For example, to install CHTimeStamp, I've copied its CHTimeStamp directory to the extensions directory and added the following to LocalSettings.php: require_once( "$IP/extensions/CHTimeStamp/CHTimeStamp.php" );.

Check to make sure your extension has been loaded by visiting the wiki's Special:Version page. In addition to information about the MediaWiki version you're running, the Special:Version page lists the extensions that have successfully loaded.


Figure 2. Special:Version page showing CHTimeStamp
Screenshot of the Version page in MediaWiki shows that the CHTimeStamp extension is installed


Customizing the look and feel

MediaWiki takes advantage of PHP's ability to mix code and HTML markup to give you control over the look and feel of your wiki through the use of skins. Besides the main PHP code, a skin can include various CSS files and supporting images or JavaScript.

A skin generally consists of two PHP files, and a directory for additional support files. For example, the famous default skin, MonoBook, is made up of:

  • MonoBook.php — Main MonoBook skin code
  • MonoBook.deps.php — A fix for a bug in the APC opcode cache of PHP V5
  • monobook/ — Supporting CSS and graphics

The naming convention for skins is very strict, requiring SkinName.php, SkinName.deps.php and skinname (lowercase) as the support folder name.

Inside the skinname folder will be main.css for the skin's styling. Browser-specific stylesheet fixes belong here, as well, so you'll often find FF2Fixes.css, IE6Fixes.css, Opera6Fixes.css, etc. there.

SkinName.php will start off with some helpful metadata.


Listing 1. MediaWiki skin metadata

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

Replace everything in square brackets with something suitable for your skin.

Next, you'll need to create a subclass of SkinTemplate and override the initPage method to indicate your skin's name, style, and template. Remember to replace SkinName and skinname with the name of your skin.


Listing 2. Extending SkinTemplate to provide a new skin

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

Your skin's workhorse will be your QuickTemplate subclass.


Listing 3. Most of the work is done in the template

class SkinNameTemplate 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 $wgUser, $wgSitename;
                $skin = $wgUser->getSkin();
 
                // retrieve site name
                $this->set( 'sitename', $wgSitename );
 
                // suppress warnings to prevent notices about missing indexes 
                // in $this->data
                wfSuppressWarnings();
 
                /* compose XHTML output */
 
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
...

Inside the QuickTemplate subclass, you'll override methods to format and style things like category listings and cross-references the way you want. This class's execute method lays out the entire page as an XHTML document, giving you complete control over page organization and styling.

You can't go into XHTML and CSS page layout and styling here, so take a look in your MediaWiki's skins folder for examples you can try out right away.


Adding special pages

Special pages in MediaWiki are generated on demand to do something specific and possibly useful for the wiki, such as letting you edit the system-wide message text, list the installed extensions, or get a list of external links.

Unless you specify otherwise, your special page will be available to anyone and show up in the Special:SpecialPages list of special pages. You can also set up your special page so it can be included inline on a page using {{Special:YourPageName}} syntax.

Like other extensions, special pages are installed as a directory into the extensions folder. They generally consist of four files:

  • specialpage/specialpage.php — The extension's setup file
  • specialpage/specialpage.aliases.php — Aliases for the special page's name
  • specialpage/specialpage.body.php — The main code for the special page
  • specialpage/specialpage.i18n.php — Internationalization strings for the special page

For example, if you're creating a special page named CHStats, its layout will look like Figure 3.


Figure 3. CHStats in Eclipse
Screenshot shows the CHStats file hierarchy in Eclipse

The code in CHStats.php adds credits for the extension, registers the aliases, body and i18n files, and tells the wiki engine to autoload the CHStats class when it's needed.


Listing 4. Setting up the CHStats special page

<?php
# This is not a valid entry point to MediaWiki.
if( !defined( 'MEDIAWIKI' ) ) {
    echo <<<EOT
To install CHStats, put the following line in LocalSettings.php:
require_once( "\$IP/extensions/CHStats/CHStats.php" );
EOT;
    exit( 1 );
}

# Take credit for this extension.
$wgExtensionCredits['specialpage'][] = array(
    'name' => 'CHStats',
    'author' => 'Chris Herborth (chrish@pobox.com)',
    'url' => 'http://www.pobox.com/~chrish/CHStats/',
    'description' => 'A simple special page demonstration, showing some DB stats.',
    'descriptionmsg' => 'chstats-desc',
    'version' => '1.0.0',
);
 
$dir = dirname( __FILE__ ) . '/';

# Register the extension's main code/class.
$wgAutoloadClasses['CHStats'] = $dir . 'CHStats.body.php';

# Register our internationalization files.
$wgExtensionMessagesFiles['CHStats'] = $dir . 'CHStats.i18n.php';
$wgExtensionAliasesFiles['CHStats'] = $dir . 'CHStats.aliases.php';

# Let MediaWiki know about the new special page.
$wgSpecialPages['CHStats'] = 'CHStats';

?>

In CHStats.body.php, you create a new class, CHStats, which extends the SpecialPage class. In the constructor, you initialize the parent class, then load your internationalization messages by calling wfLoadExtensionMessages. Check the Special Pages developer's guide page (see Resources) for more information about the SpecialPage class constructor, which will let you restrict access, hide the page, etc.

The override for the execute method does the work of generating the page.


Listing 5. Generating the CHStats special page

# This is where the special page's output is created.
function execute( $par ) {
    global $wgOut;

    # Initialize the output page.
    $this->setHeaders();

    # Do stuff.
    $wgOut->addWikiText( "Some stats about this '''Wiki''':" );

    $db = wfGetDB( DB_SLAVE );
    // SELECT ... FROM site_stats
    $result = $db->select( 'site_stats', 
                           array( 'ss_total_views', 'ss_total_edits', 
'ss_total_pages', 'ss_users' ) );
    $statList = array();
    foreach( $result as $row ) {
        $statList[] = '* Total page views: ' . $row->ss_total_views;
        $statList[] = '* Total page edits: ' . $row->ss_total_edits;
        $statList[] = '* Total # of users: ' . $row->ss_users;
    }

    $wgOut->addWikiText( implode( "\n", $statList ) );

    $wgOut->addWikiText( "That's it." );
}

In the execute method, the $par argument is the sub-page. For example, if you loaded Special:CHStats/foo, $par would be set to foo (its name is apparently a historical oddity).

First you use the setHeaders method to set up the page header, then call $wgOut->addWikiText to write some markup to the output stream. You can also use $wgOut->addHTML to write formatted HTML directly, but I'm using wiki markup in the output. Refer to the Special Pages developer's guide for more information about these (see Resources), and how to properly add wiki markup and/or HTML to special pages that can be included inline in other pages.

The CHStats page uses the wfGetDB function to get a reference to the database (use DB_SLAVE for read-only operations, and DB_MASTER for write operations). Then you select several fields from the site_stats database and format the results as a bulleted list using wiki markup.

You can see what the output of this special page looks like in Figure 4.


Figure 4. CHStats in action
Screenshot shows the CHStats listing lf statistics, including page views, page edits and total users

The internationalization strings found in CHStats.i18n.php consist of an array, with one entry per supported language (English, French, German, and Spanish, in this case). In each entry is an array mapping string IDs to what is hopefully their localized text. Google Translate was used for the French, German, and Spanish bits.

CHStats.aliases.php has a similar array containing the localized versions of the CHStats page name itself. This lets French users (for example) access the page as Spécial:StatsCH.


Adding tags

Another popular way to extend MediaWiki is by adding support for new XML tags to the markup. These tags can produce different output based on the tag attributes or the content and are useful for inserting inline HTML or even large blocks of formatted output.

Tag extensions are installed in their own directory under the extensions folder and use the three-file convention described at the start of this article. Let's look at a simple one I've cooked up named CHUser:

  • CHUser/CHUser.php — Extension setup
  • CHUser/CHUser.body.php — Main extension code
  • CHUser/CHUser.i18n.php — Internationalization data

The extension setup going on in CHUser.php is similar to what you've already seen, although it uses the $wgHooks array to add the extension's init method to the ParserFirstCallInit list. CHUser::init will be called the first time it's used.


Listing 6. Setting up the tag extension

# Let MediaWiki know about the new tag.
$wgHooks['ParserFirstCallInit'][] = 'CHUser::init';

Inside CHUser.body.php, the init method registers two tags: <chuser> and <bz> (see Listing 7). This extension provides two different tags in just one extension. You could easily combine all of the extensions discussed in this article if you wanted to, there's no requirement (other than your own sanity) to split things up.


Listing 7. Registering the <chuser> and <bz> tags

public static function init( &$parser ) {
    # Add our <chuser> tag handler, the continue.
    $parser->setHook( 'chuser', 'CHUser::render' );
    $parser->setHook( 'bz', 'CHUser::renderBugzilla' );
    return true;
}

Whenever the wiki markup engine encounters a <chuser> tag, it will call the CHUser::render method, and <bz> tags will call CHUser::renderBugzilla.

The <chuser> rendering method selects the specified user's full name and e-mail address, and formats it as a mailto: link wrapped around the user's full name (if there is one). You can see from Listing 8 that most of the logic is simply handling cases where the full name or e-mail address isn't present in the database (such as for the Admin account on my wiki).


Listing 8. Handling <chuser>UserName</chuser>

public static function render( $input, $args, $parser, $frame ) {
    $user = mysql_escape_string( $input );

    $db = wfGetDB( DB_SLAVE );
    // SELECT ... FROM user
    $result = $db->select( 'user', 
                           array( 'user_real_name', 'user_email' ),
                           'user_name = \'' . $user . '\'' );
    $mailtos = array();
    foreach( $result as $row ) {
        $thisUser = '<span class="user">';

        if( $row->user_email ) {
            $thisUser = $thisUser . '<a href="mailto:' 
. htmlspecialchars( $row->user_email ) . '">';
        }

        if( $row->user_real_name ) {
            $thisUser = $thisUser . htmlspecialchars( $row->user_real_name ); 
        } else {
            $thisUser = $thisUser . htmlspecialchars( $input );
        }

        if( $row->user_email ) {
            $thisUser = $thisUser . '</a>';
        }
        
        $thisUser = $thisUser . '</span>';

        $mailtos[] = $thisUser;
    }

    return implode( ", ", $mailtos );
}

Listing 9 shows you how the <bz> tag uses its ID attribute to link to a specified bug report in the MediaWiki Bugzilla database. This shows how easy it is to work with external data sources. If you wanted to get fancy you could use Ajax to load the bug report instead of linking to it, and display some of its data instead of the link.


Listing 9. <bz id="number" /> links to the MediaWiki Bugzilla

public static function renderBugzilla( $input, $args, $parser, $frame ) {
    $retval = '';
    if( $args['id'] ) {
        $bzId = htmlspecialchars( $args['id'] );
        
        $retval = '<a href="https://bugzilla.wikimedia.org/show_bug.cgi?id=' 
. $bzId . '">MediaWiki Bug #' . $bzId . '</a>';
    } else {
        $retval = '<span class="error">No bug ID specified</span>';
    }
    
    return $retval;
}

You can see these two tags in action in Figure 5.


Figure 5. Your extensions in action
Screenshot of the CHUser extension showing the screen name and real names and real names of the users

Listing 10 shows you what the wiki markup looks like for that section of the page.


Listing 10. The wiki markup demonstrating these extensions

== Extension testing ==

If this is working, we should see a timestamp: {{CHSTAMP}}

CHUser info:

* '''Admin''': <chuser>Admin</chuser>
* '''Chrish''': <chuser>Chrish</chuser>

<bz id="1024" />

As you can see from the CHUser extension, adding support for custom XML tags is easy and lets you do almost anything. All PHP features and MediaWiki services are available to you, so you can pull data from (or send data to) external systems, change your behavior based on the current user's credentials and permissions or insert JavaScript to run tasks directly in the viewer's browser. The possibilities and endless and limited only by your specific needs and requirements.


Summary

In this article, you were introduced to several extension techniques supported by MediaWiki, an open source wiki system similar to commercial wiki software like Lotus® Connections.

You were shown MediaWiki's extension conventions and shown how to create a simple wiki variable extension as an introduction to writing MediaWiki extensions. An overview of MediaWiki's skinning features help you get started creating your own customized site layout.

Special pages are often used to generate information, whether retrieved from a database or other source, so you made one that displays some of the system's statistics. You then created a couple of custom XML tags that could be included in wiki markup on any page.



Download

DescriptionNameSizeDownload method
Article source codeos-mediawiki-CH.Examples.zip7KBHTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Photo of Chris Herborth

Chris Herborth is an award-winning senior technical writer with more than 10 years of experience writing about operating systems and programming. When he's not playing with his son, Alex, or hanging out with his wife, Lynette, he spends his time designing, writing, and researching (that is, playing) video games.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=498779
ArticleTitle=Customizing MediaWiki
publish-date=07062010
author1-email=chrish@pobox.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers