From charlesreid1

General Information

Laying It Out

The basic idea behind skinning MediaWiki is to create PHP/HTML code that will serve as a header and footer for your wiki. You can imagine the page being split into several pieces:

Zone Description Tags
Page Head and Title This is defined by MediaWiki
<html>
<head>
<title>
</title>
</head>
<body>
Page Body: Body Header This is defined by your skin
Page Body: Wiki Page Content This is defined by MediaWiki (and inserted/abstracted by your skin)
<?php $this->html('bodytext') ?>
Page Body: Body Footer This is defined by your skin
Page End This is defined by MediaWiki
</body>
</html>

Instructions/Walkthrough

Create a New Skin

You can start creating your own skin by starting with an existing skin, such as Simple or Monobook. Starting with the Monobook skin can become kind of involved, but honestly skinning MW is not that involved to begin with.

First, create your copy of a skin. I'm going to name my skin CMR:

$ cd w/skins/

$ cp MonoBook.php CMR.php

$ cp -r monobook/ cmr/

Next, I can set my MW theme to be the new theme by editing w/LocalSettings.php and adding:

$wgDefaultSkin = 'cmr';

OK, so now you're using your own skin. But now you have to edit CMR.php - where to begin???

Navigating Your Skin's PHP File

The place to begin is with CMR.php (or, the php file for whatever your skin is called). Upon perusing the file, you'll see it's a PHP class that defines a PHP object, and that PHP object represents the MediaWiki skin.

The beginning of the class is important to edit - replace instances of "Monobook" with your skin's own name.

Next, look for a function called execute():

function execute() {

This will define the behavior of the skin when someone on the website requests a new page. MediaWiki parses the request, determines what content the user is interested in viewing, retrieves that content from a database, package the content in HTML code, then calls this execute() method to create the HTML code for the very final version of the page - the version that the user will see in their browser when they request a new page.

Creating a Title

The first thing that the execute() function should do is create a title. MediaWiki already has a large amount of functionality operating behind the scenes, and by the time operation reaches the execute() function, a header has already been created.

The header function can be created/inserted by making a call to create the head element:

$this->html( 'headelement' );

This should create content that looks something like this (this is using my website's current skin, called "Dash"):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" dir="ltr">
<head>
<title>Editing Skinning MediaWiki - Charles Martin Reid</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="MediaWiki 1.16.0" />
<meta name="robots" content="noindex,nofollow" />
<link rel="alternate" type="application/x-wiki" title="Edit" href="/w/index.php?title=Skinning_MediaWiki&action=edit" />
<link rel="edit" title="Edit" href="/w/index.php?title=Skinning_MediaWiki&action=edit" />
<link rel="shortcut icon" href="/w/favicon.ico" />
<link rel="search" type="application/opensearchdescription+xml" href="/w/opensearch_desc.php" title="Charles Martin Reid (en)" />
<link title="Creative Commons" type="application/rdf+xml" href="/w/index.php?title=Skinning_MediaWiki&action=creativecommons" rel="meta" />
<link rel="copyright" href="http://creativecommons.org/licenses/by-nc-nd/3.0/us/" />
<link rel="alternate" type="application/atom+xml" title="Charles Martin Reid Atom feed" href="/w/index.php?title=Special:RecentChanges&feed=atom" />
<link rel="stylesheet" href="/w/index.php?title=MediaWiki:Common.css&usemsgcache=yes&ctype=text%2Fcss&smaxage=18000&action=raw&maxage=18000" />
<link rel="stylesheet" href="/w/index.php?title=MediaWiki:Print.css&usemsgcache=yes&ctype=text%2Fcss&smaxage=18000&action=raw&maxage=18000" media="print" />
<link rel="stylesheet" href="/w/index.php?title=MediaWiki:Dash.css&usemsgcache=yes&ctype=text%2Fcss&smaxage=18000&action=raw&maxage=18000" />
<link rel="stylesheet" href="/w/index.php?title=-&action=raw&maxage=18000&smaxage=0&ts=20120525033749&gen=css" />
<script>
var skin="dash",
stylepath="/w/skins",
wgUrlProtocols="http\\:\\/\\/|https\\:\\/\\/|ftp\\:\\/\\/|irc\\:\\/\\/|gopher\\:\\/\\/|telnet\\:\\/\\/|nntp\\:\\/\\/|worldwind\\:\\/\\/|mailto\\:|news\\:|svn\\:\\/\\/",
wgArticlePath="/wiki/$1",wgScriptPath="/w",
wgScriptExtension=".php",wgScript="/w/index.php",
wgVariantArticlePath=false,wgActionPaths={},
wgServer="http://charlesmartinreid.com",wgCanonicalNamespace="",
wgCanonicalSpecialPageName=false,wgNamespaceNumber=0,
wgPageName="Skinning_MediaWiki",wgTitle="Skinning MediaWiki",
wgAction="edit",wgArticleId=802,wgIsArticle=false,
wgUserName="Admin",wgUserGroups=["bureaucrat", "cmr", "economist", "journal", "sysop", "writing", "*", "user", "autoconfirmed"],wgUserLanguage="en",wgContentLanguage="en",wgBreakFrames=false,
wgCurRevisionId=3674,wgVersion="1.16.0",wgEnableAPI=true,
wgEnableWriteAPI=true,wgSeparatorTransformTable=["", ""],wgDigitTransformTable=["", ""],wgMainPageTitle="Main Page",
wgFormattedNamespaces={"-2": "Media", "-1": "Special", "0": "", "1": "Talk", "2": "User", "3": "User talk", "4": "Charles Martin Reid", "5": "Charles Martin Reid talk", "6": "File", "7": "File talk", "8": "MediaWiki", "9": "MediaWiki talk", "10": "Template", "11": "Template talk", "12": "Help", "13": "Help talk", "14": "Category", "15": "Category talk", "200": "Writing", "274": "Widget", "275": "Widget talk"},
wgNamespaceIds={"media": -2, "special": -1, "": 0, "talk": 1, "user": 2, "user_talk": 3, "charles_martin_reid": 4, "charles_martin_reid_talk": 5, "file": 6, "file_talk": 7, "mediawiki": 8, "mediawiki_talk": 9, "template": 10, "template_talk": 11, "help": 12, "help_talk": 13, "category": 14, "category_talk": 15, "writing": 200, "widget": 274, "widget_talk": 275, "image": 6, "image_talk": 7},
wgSiteName="Charles Martin Reid",
wgCategories=[],wgRestrictionEdit=[],wgRestrictionMove=[],
wgAjaxWatch={"watchMsg": "Watch", "unwatchMsg": "Unwatch", "watchingMsg": "Watching...", "unwatchingMsg": "Unwatching...", "tooltip-ca-watchMsg": "Add this page to your watchlist", "tooltip-ca-unwatchMsg": "Remove this page from your watchlist"};
</script><script src="/w/skins/common/wikibits.js?270"></script>
<script src="/w/skins/common/edit.js?270"></script>
<script src="/w/skins/common/ajax.js?270"></script>
<script src="/w/skins/common/ajaxwatch.js?270"></script>
<script src="/w/index.php?title=-&action=raw&smaxage=0&gen=js&useskin=dash&270"></script>

</head>
<body class="mediawiki ltr ns-0 ns-subject page-Skinning_MediaWiki skin-dash">

Any HTML code generated by the execute() function begins after the <body> tag.

Modifying Your Skin's PHP File

From here, you just edit the execute() function to do what you want. However, there are a couple of tricks that will be helpful in figuring out how exactly that should be best done.

Let us look at the MonoBook layout to identify some elements we'll want to arrange when creating our own skin.

ScreenShotWithBoxes.jpg

There are four elements of interest here:

1. MediaWiki links (e.g. "Main Page", "Random Page", "Special Pages", "Featured Content", etc...) - left side of page

2. MediaWiki action links (e.g. search, log in) - top right corner of page

3. Page action links (e.g. "Edit", "History", etc...) - top edge of page

4. Website logo - top left corner of page

I will cover how each of these is controlled.

MediaWiki Links

And this code covers the MediaWiki links on the left side:

<?php
        $sidebar = $this->data['sidebar'];
        if ( !isset( $sidebar['SEARCH'] ) ) $sidebar['SEARCH'] = true;
        if ( !isset( $sidebar['TOOLBOX'] ) ) $sidebar['TOOLBOX'] = true;
        if ( !isset( $sidebar['LANGUAGES'] ) ) $sidebar['LANGUAGES'] = true;
        foreach ($sidebar as $boxName => $cont) {
            if ( $boxName == 'SEARCH' ) {
                $this->searchBox();
            } elseif ( $boxName == 'TOOLBOX' ) {
                $this->toolbox();
            } elseif ( $boxName == 'LANGUAGES' ) {
                $this->languageBox();
            } else {
                $this->customBox( $boxName, $cont );
            }
        }
?>

This works by looking at each sidebar element (search, toolbox, and navigation) and putting it in a separate box on the left side. These boxes are stacked together by the above "foreach" loop.

MediaWiki Action Links

This is the portion that MediaWiki calls your "Personal Tools". It is controlled in MonoBook with the following code:

<div id="footer"<?php $this->html('userlangattributes') ?>>                              
<?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',                                 
        );
        $validFooterLinks = array();
        foreach( $footerlinks as $aLink ) {
            if( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {                  
                $validFooterLinks[] = $aLink;                                            
            }                                                                            
        }
        if ( count( $validFooterLinks ) > 0 ) {                                          
?>  <ul id="f-list">                                                                     
<?php       
            foreach( $validFooterLinks as $aLink ) {
                if( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {              
?>      <li id="<?php echo $aLink ?>"><?php $this->html($aLink) ?></li>                  
<?php           }                                                                        
            }                                                                            
?>  
    </ul>                                                                                
<?php   }                                                                                
?>
</div>                                                                                   

Page Action Links

Page actions are located in the p-caction div tag:

    <div id="p-cactions" class="portlet">                                                
        <h5><?php $this->msg('views') ?></h5>                                            
        <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']).'"';                
                    # We don't want to give the watch tab an accesskey if the            
                    # page is being edited, because that conflicts with the              
                    # accesskey on the watch checkbox.  We also don't want to            
                    # give the edit tab an accesskey, because that's fairly su-          
                    # perfluous and conflicts with an accesskey (Ctrl-E) often           
                    # used for editing in Safari.                                        
                    if( in_array( $action, array( 'edit', 'submit' ) )                   
                    && in_array( $key, array( 'edit', 'watch', 'unwatch' ))) {           
                        echo $skin->tooltip( "ca-$key" );                                
                    } else {                                                             
                        echo $skin->tooltipAndAccesskey( "ca-$key" );                    
                    }                                                                    
                    echo '>'.htmlspecialchars($tab['text']).'</a></li>';                 
                } ?>                                                                     
                                                                                         
            </ul>                                                                        
        </div>                                                                           
    </div> 

This code covers the logo in the top left corner:

    <div class="portlet" id="p-logo">
        <a style="background-image: url(<?php $this->text('logopath') ?>);" <?php
            ?>href="<?php echo htmlspecialchars($this->data['nav_urls']['mainpage']['href'])?>"<?php
            echo $skin->tooltipAndAccesskey('p-logo') ?>></a>
    </div>

Useful Footer Information

MediaWiki also makes available some useful information that you can put into your footer. In MonoBook, this information is controlled with this code:

<div id="footer"<?php $this->html('userlangattributes') ?>>                              
<?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',                                 
        );
        $validFooterLinks = array();
        foreach( $footerlinks as $aLink ) {
            if( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {                  
                $validFooterLinks[] = $aLink;                                            
            }                                                                            
        }
        if ( count( $validFooterLinks ) > 0 ) {                                          
?>  <ul id="f-list">                                                                     
<?php       
            foreach( $validFooterLinks as $aLink ) {
                if( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {              
?>      <li id="<?php echo $aLink ?>"><?php $this->html($aLink) ?></li>                  
<?php           }                                                                        
            }                                                                            
?>  
    </ul>                                                                                
<?php   }                                                                                
?>
</div>                                                                                   

You can mix and match stuff to get the footer to suit your tastes.

An Example Of How To Customize Page Elements

I'll demonstrate how I used the above information to create a skin (this site's former skin, called CMR or CharlesMartinReid) that shuffled a lot of links and page elements around.

ScreenshotMWSkinCMR.jpg

This screenshot shows my CMR skin, containing the same four elements, but modified to be more brief, and to be placed in a more convenient way.

The four elements are:

  • MediaWiki links - left side
  • MediaWiki action links - top right corner
  • Page action links - top edge of page
  • Banner image - top left corner

The code used for each of them will be described here. The CMR skin is described in greater detail at the CMR MediaWiki Skin page.

Customized MediaWiki Links

This is significantly cleaner and easier to understand than the corresponding portion in MonoBook.php. This section loops through the different sidebars and determines which ones are turned on and which ones are turned off. The order in which this occurs is:

  • Main Page
  • Help
  • Search
  • (What links here, upload file, list all files, etc...)

This is the logic behind the layout.


<?php
        /*
        $sidebar = $this->data['sidebar'];
        if ( !isset( $sidebar['SEARCH'] ) ) $sidebar['SEARCH'] = true;
        if ( !isset( $sidebar['TOOLBOX'] ) ) $sidebar['TOOLBOX'] = true;
        */
        $sidebar = $this->data['sidebar'];

        // 0 - Main Page *
        // 1 - Community Portal
        // 2 - Current events
        // 3 - Recent changes
        // 4 - Random page
        // 5 - Help *
        unset($sidebar['navigation'][1]);
        unset($sidebar['navigation'][2]);
        unset($sidebar['navigation'][3]);
        unset($sidebar['navigation'][4]);

        if ( !isset( $sidebar['SEARCH'] ) )  $sidebar['SEARCH'] = true;
        if ( !isset( $sidebar['TOOLBOX'] ) ) $sidebar['TOOLBOX'] = true;
        foreach ($sidebar as $boxName => $cont) {
            if ( $boxName == 'SEARCH' ) {
                $this->searchBox();
            } elseif ( $boxName == 'TOOLBOX' ) {
                $this->toolbox();
            } elseif ( $boxName == 'LANGUAGES' ) {
                $this->languageBox();
            } else {
                $this->customBox( $boxName, $cont );
            }
        }
?>

Customized MediaWiki Action Links

The MediaWiki links here were not significantly modified from MonoBook.php.


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

Customized Page Action Links

Again, not significantly modified from MonoBook.php:


<!-- These create the Page/Discussion/Edit buttons
     See the p-cactions attributes in main.css -->
<div id="column-one"<?php $this->html('userlangattributes')  ?>>
    <div id="p-cactions" class="portlet">
        <h5><?php $this->msg('views') ?></h5>
        <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']).'"';
                    # We don't want to give the watch tab an accesskey if the
                    # page is being edited, because that conflicts with the
                    # accesskey on the watch checkbox.  We also don't want to
                    # give the edit tab an accesskey, because that's fairly su-
                    # perfluous and conflicts with an accesskey (Ctrl-E) often
                    # used for editing in Safari.
                    if( in_array( $action, array( 'edit', 'submit' ) )
                    && in_array( $key, array( 'edit', 'watch', 'unwatch' ))) {
                        echo $skin->tooltip( "ca-$key" );
                    } else {
                        echo $skin->tooltipAndAccesskey( "ca-$key" );
                    }
                    echo '>'.htmlspecialchars($tab['text']).'</a></li>';
                } ?>

            </ul>
        </div>
    </div>

</div>

<div id="content" <?php $this->html("specialpageattributes") ?>>
<h1 id="firstHeading" class="firstHeading"><?php $this->html('title') ?></h1>

<div id="bodyContent">
<h3 id="siteSub"><?php $this->msg('tagline') ?></h3>
<div id="contentSub"<?php $this->html('userlangattributes') ?>><?php $this->html('subtitle') ?></div>
<?php
if($this->data['undelete']) { ?>
    <div id="contentSub2"><?php $this->html('undelete') ?></div>
<?php
}
if($this->data['newtalk'] ) { ?>
    <div class="usermessage"><?php $this->html('newtalk')  ?></div>
<?php
}
?>


Note that, as with the MediaWiki navigation links, the array for Page action links can also be customized, simply by inserting this block of code right before the preceding block of code:

<?php
/*
var_dump( $this->data['content_actions'] ); 
array(4) { 
    ["nstab-main"]=>  array(3) { 
        ["class"]=>  string(8) "selected" 
        ["text"]=>  string(4) "Page" 
        ["href"]=>  string(25) "/wiki/index.php/Main_Page" 
    } 
    ["talk"]=>  array(3) { 
        ["class"]=>  string(3) "new" 
        ["text"]=>  string(10) "Discussion" 
        ["href"]=>  string(58) "/wiki/index.php?title=Talk:Main_Page&action=edit&redlink=1" 
    } 
    ["edit"]=>  array(3) { 
        ["class"]=>  string(0) "" 
        ["text"]=>  string(4) "Edit" 
        ["href"]=>  string(43) "/wiki/index.php?title=Main_Page&action=edit" 
    } 
    ["history"]=>  array(4) { 
        ["class"]=>  bool(false) 
        ["text"]=>  string(7) "History" 
        ["href"]=>  string(46) "/wiki/index.php?title=Main_Page&action=history" 
        ["rel"]=>  string(8) "archives" 
    } 
} 
*/
?>
<!-- These create the Page/Discussion/Edit buttons
     See the p-cactions attributes in main.css -->

<!-- etc... --->

Customized Banner/Logo Image

This did not use anything MediaWiki specific.

I made the header consist of seven images, one for each letter of my name, and made each image, when clicked, redirect the user to the Main Page.


<!--
<h1>C H A R L E S</h1>
-->

<img
src="/w/skins/charlesmartinreid/01_C.JPG"
alt="C"
style="text-decoration:none; border:none;width:110px;height:auto;">

<img
src="/w/skins/charlesmartinreid/02_H.JPG"
alt="H"
style="text-decoration:none; border:none;width:110px;height:auto;">

<img
src="/w/skins/charlesmartinreid/03_A.JPG"
alt="A"
style="text-decoration:none; border:none;width:110px;height:auto;">

<img
src="/w/skins/charlesmartinreid/04_R.JPG"
alt="R"
style="text-decoration:none; border:none;width:110px;height:auto;">

<img
src="/w/skins/charlesmartinreid/05_L.JPG"
alt="L"
style="text-decoration:none; border:none;width:110px;height:auto;">

<img
src="/w/skins/charlesmartinreid/06_E.JPG"
alt="E"
style="text-decoration:none; border:none;width:110px;height:auto;">

<img
src="/w/skins/charlesmartinreid/07_S.JPG"
alt="S"
style="text-decoration:none; border:none;width:110px;height:auto;">

The Style Sheet

In addition to the layout of each element, a stylesheet that corresponds to the skin must be made. For this example, the CMR skin, the stylesheet is located in:

w/skins/cmr/main.css

Remember that cmr is just a copy of the monobook directory. Modifying the CSS stylesheet is probably the most time-consuming part of creating a MediaWiki skin, and my advice is to keep it as simple as possible but to check all contingencies to make sure your stylesheet doesn't screw things up.

The best way to start out on this is to see how the MonoBook style sheet looks, and start fixing the things that look weird to you. I can't provide much guidance beyond that, as it is entirely skin-specific.

You can download the stylesheet for the CMR skin at the CMR MediaWiki Skin page.

This is the basis of the stylesheet used in my Dash MediaWiki Skin.