<span class="mw-page-title-namespace">Blog</span><span class="mw-page-title-separator">:</span><span class="mw-page-title-main">Hacks/Big MediaWiki Upgrade (1.21 to 1.43)</span>
Elena & Fabrice's Web

Big MediaWiki Upgrade (1.21 to 1.43)

From laussy.org's Blog about Hacks.
Published: 09:42, 6 July 2025.

In JuneJuly (2025), I upgraded Mediawiki from 1.21.5, which is a 2013 version, to 1.43.2, the most recent one at the time of writing (13 years later).

I used to follow a bit the upgrades (I started with 1.15) but stopped because basic functionalities of the releases of the time were enough for me (in fact I really started with UseModWiki and its WeirdWayOfLinking, and also tried simpler alternative like MoinMoin and probably others, until I decided the leading trend was probably the safest bet). But the underlying tech, php and MySQL, evolved and my wiki started to have problems, even with fixes to keep it running. Cool things like Google map were not working anymore. In June (2025), it became untenable with repeated failures of services as I suffered problems of too many open connections, and even a few people start to complain about the web being down!

Database & wiki software

The database of over a decade ago was completely obsolete for modern mediawiki, so I had to do the upgrade incrementally, on my local machine (not on the server, of course). I had to install older versions to make the upgrade from my starting point 1.21.5 to, the first upgradeable one, i.e., 1.27.7. The basic process was as follows:

wget https://releases.wikimedia.org/mediawiki/1.27/mediawiki-1.27.7.tar.gz
sudo chown -R www-data:www-data /var/www/html/mediawiki-1.27.7
sudo chmod -R 755 /var/www/html/mediawiki-1.27.7

I had to use special repositories to install old versions of PHP (5.6) and MySQL (5.5):

sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install -y php5.6 php5.6-mysqlnd php5.6-mbstring php5.6-xml php5.6-gd php5.6-curl php5.6-cli

which worked and brought me back to obsolete times:

laussy@azag:/var/www/html$ php5.6 -v
PHP 5.6.40-81+ubuntu24.04.1+deb.sury.org+1 (cli) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

Instead of doing the same with MySQL, I relied on MariaDB's great backward compatibility

Then mediawiki-1.35.14 and then mediawiki-1.43.1. The process involved a lot of fiddling, adding missing tables, etc., but it was a matter of a few hours and by the first day (on 18 June (2025)), I had my database and content readable again:

Then I had to import everything else:

The wz extension

I started with my wz extension, so as to look a bit under the hood with something familiar. This was more painful than I thought. The first day, with the help of Grok, I could upgrade the obsolete 1.21.5 code to modern 1.43 practice, but the encapsulation into the wiki didn't work. It involved problems with the resource loader since it was working with:

$wgResourceLoaderDebug = true;

or by appending ?debug=true to the url. I thus went for a bit more handmade solution, closer to my initial hacking of the html by adding the script locations by hand:

#    $out->addScriptFile(wfExpandUrl('/laussywiki/extensions/wz/modules/wz_tooltip.js'));
#    $out->addScriptFile(wfExpandUrl('/laussywiki/extensions/wz/modules/tip_centerwindow.js'));
#    $out->addScriptFile(wfExpandUrl('/laussywiki/extensions/wz/modules/tip_followscroll.js'));
    $out->addModules(['ext.wz.tooltip']);

The commented # lines are those that work, but not top-practice, the last one is what it should be, but that doesn't work.

It appears that the problem is with wz itself, which is not encapsulated and robust enough to survive so-called minification. Either I'd have to rewrite bulk of Walter's code (which I tried without much success) or turn to modern tooltip, jquery-based apps, which is an option I decline for now for both reasons of efficiency (my wz works "the old way") and loyalty to a beloved extension!

The laussywiki skin

For this I had to migrate from the simple, straightforward and transparent css style to the less style sheet programming, with its mustaches. This was more or less straightforward for the basic things, and I could fairly quickly not only replicate but in some respects, improve the skinning, for instance regarding the TOC. There are so many things that laussywiki does, however, that some of them, to which I grew irremediably accustomed, were a pain in the ass and took me days to implement. At some point I had to turn to versionning to recover previous versions after hacking so much that I wrecked everything. This brought me to no less than v°2.7.47 (47 revisions of the 7th family of features for the 2nd version—this one—of the skin).

The media viewer

We previously used the beautiful and simple FancyBoxThumbs, now archived, and no longer supported. I naively thought there'd be a plethora of substitutes. Not only are there only a few gallery extensions, but none is remotely close to what was existing over a decade ago in terms of simplicity and efficiency. I spent a lot of time on Extension:PhotoSwipe, which however is not working on 1.43 (although it should). The best shot is the standard Extension:MultimediaViewer, which is so standard that it comes installed by default. It is, however, overly complex, riddled with useless features and informations (licensing of the image, downloading in various formats, etc.) which are not configurables. It also has the momentous bug that it removes the wiki attributes of the caption for images in a gallery (not single images), as you can see on the Wikipedia. This I couldn't figure out how to hack so I'll wait for a release or for time to free itself for this important feature (especially on our web which is heavily based on galleries). I removed the extra stuff either through the less files, e.g., the extra button in MultimediaViewer/resources/mmv/ui/mmv.ui.canvasButtons.less with:

.mw-mmv-reuse-button,
.mw-mmv-download-button{
    display: none;
}

or the setImageInfo in mmv.ui.metadataPanel.js:

setImageInfo(image, imageData) {
    if (image.caption) {
        // Set only the caption as the title
        this.title.set(image.caption);

        // Clear other content to avoid residuals
        this.description.empty();
        this.$imageMetadata.empty();
        this.$imageLinks.empty();
        this.$filenameLi.addClass('empty');
        this.$datetimeUpdatedLi.addClass('empty');
        this.$datetimeCreatedLi.addClass('empty');
        this.$licenseLi.addClass('empty');
        this.$locationLi.addClass('empty');
        this.$credit.addClass('empty');
        this.$restrictions.empty();
        this.$permissionLink.hide();

        // Ensure panel is visible
        if (this.$container) {
            this.$container.removeClass('empty').css('display', 'inline-block');
            console.log('Caption present, container class:', this.$container.attr('class'), 'Display:', this.$container.css('display'));
        }
        if (this.$aboveFold) {
            this.$aboveFold.removeClass('empty').css('display', 'block');
            console.log('AboveFold class:', this.$aboveFold.attr('class'), 'Display:', this.$aboveFold.css('display'));
        }
    } else {
        // Clear and hide all content and panel if no caption
        this.title.empty();
        this.description.empty();
        this.$imageMetadata.empty();
        this.$imageLinks.empty();
        this.$filenameLi.addClass('empty');
        this.$datetimeUpdatedLi.addClass('empty');
        this.$datetimeCreatedLi.addClass('empty');
        this.$licenseLi.addClass('empty');
        this.$locationLi.addClass('empty');
        this.$credit.addClass('empty');
        this.$restrictions.empty();
        this.$permissionLink.hide();
        if (this.$container) {
            this.$container.addClass('empty').css('display', 'none');
            console.log('No caption, container class:', this.$container.attr('class'), 'Display:', this.$container.css('display'));
        }
        if (this.$aboveFold) {
            this.$aboveFold.addClass('empty').css('display', 'none');
            console.log('No caption, aboveFold class:', this.$aboveFold.attr('class'), 'Display:', this.$aboveFold.css('display'));
        }
    }

    // Lock panel and disable scrolling
    this.scroller.freezeHeight();
    if (this.scroller.element) {
        this.scroller.element.style.overflow = 'hidden';
    }

    // Remove margin and borders to prevent line below title
    if (this.$titlePara) {
        this.$titlePara.style.marginBottom = '0';
        this.$titlePara.style.borderBottom = 'none';
        console.log('TitlePara styles - marginBottom:', this.$titlePara.style.marginBottom, 'borderBottom:', this.$titlePara.style.borderBottom);
    }
}

Page Counters

This has also been a frustrating experience. On 25 May (2015), for its v°1.25, mediawiki stopped counting page hits as part of the database. This is an information that I didn't want to lose, so I had to setup the Extension:HitCounters.

Google maps

I went for Maps, which is fairly standard although not the version used on Wikipedia and Mediawiki webs, which use Kartographer instead. I also checked this one but it didn't strike me as much better. One important feature of Maps is that it use Satellite data, which is a must for us. It requires requesting an API, though, which can be free up to some number of requests. I'll have to look into that in the future.

Porting the data was fairly straightforward, except that it didn't parse some content, which was difficult to identify. From Gregynog till New Delhi, that worked fine, covering all 20032008. From Qutb complex (on 1 December (2009)) till Belfort (on 28 December (2011)), however, this didn't work, indicating the mistake was there. I narrowed it down first to the year 2011, then to a few lines. The culprit was a ? in a url of some service which was, nevertheless, no longer available (twitgoo) that was capturing images at a time when, maybe, Twitter was not able to:

48.296936,11.621349~Eching~{{thisday|1|May|2011}} [http://twitgoo.com/28qdeq].;
48.289838,11.631281~Echinger See~{{thisday|1|May|2011}} [http://twitgoo.com/28qfmd].;
48.129896,11.583384~Deutsches museum~{{thisday|9|May|2011}} [http://twitgoo.com/29ev81].;
48.125927,11.368958~Germering~{{thisday|15|May|2011}} [http://twitgoo.com/29zo2b].;
48.169757,11.617055~Isar~{{thisday|19|May|2011}} [http://twitgoo.com/2af3pe].;
48.158157,11.501394~Nymphenburg~{{thisday|28|May|2011}} [http://twitgoo.com/2b4780?cx=u].;
48.163322,11.497526~Botanischer Garten München-Nymphenburg~{{thisday|28|May|2011}} [http://twitgoo.com/2b47r8?cx=u].;

Wiki editor

It can actually be configured quite a lot from the LocalSettings.php, e.g.,

wfLoadExtension( 'MsWikiEditor' );
$wgMSWE_add['strike'] = [ 'Strike', '<s>', 'Text', '</s>', '/laussywiki/extensions/MsWikiEditor/images/strike.png' ];

so you might not have to go for the User:Laussy/common.js, which is how I add a straight wikifying of the text (without having to click 20 options before it gets done):

console.log('WikiEditor button code loaded');
mw.hook('wikiEditor.toolbarReady').add(function ($textarea) {
    console.log('WikiEditor toolbar is ready, adding button');
    $textarea.wikiEditor('addToToolbar', {
        section: 'main',
        group: 'insert',
        tools: {
            wikilinkButton: {
                label: 'Insert Wikilink',
                type: 'button',
                icon: '/laussywiki/icons/square-brackets.png',
                action: {
                    type: 'encapsulate',
                    options: {
                        pre: '[[',
                        peri: 'Link',
                        post: ']]'
                    }
                }
            }
        }
    });
});

Blogs

This has been one of the big challenges. Since I started to go the Bliki way, I used the Extension:Wikilog to manage my blog posts; this got discontinued and forked and abandoned again, to the point where this is no longer supported. I had to write from scratch my own version to recover the content. The other option was to port them by hand to something new, but: i) there's nothing new that I really like, and the risk is that this will go obsolete at some point again and ii) I still have to port my old WordPress blog, so it is is clear that this wouldn't be done, or at least, not done comprehensively (I would have for sure gave up on my Blog:Polyphasic or my cookding blogs). Therefore I went up for a simple extension, which I called BlogTitles, because it basically list the content of the various blogs as a list of titles.

Everything else

I also had to revive services to display mp3 and youTube inserts. This was tedious but do-able. More importantly, I took opportunity of this big burden to implement features I always wanted to, but did not for lack of time. So I took the time to do it then. This includes, for instance, Template:CustomHeader to replace our Plaza Mayor header with something more fit for a given page, e.g., see Trapped in the Province of Jaén (December 2017-January 2018).

Still to do

There are other things that I did not yet implement but will or at least should. This includes a better editor for the blog, which currently I could not make invoke the wikieditor (not for lack of trying!), or a commenting section, which I'd like to put on Blog posts but also on my what the paper says pages. I did play a bit with the Extension:Comments which should work for me, but this will require careful implementation to avoid spam, so I've postponed it to a later upgrade. Hopefully, I will do more of them now, not waiting 13 years, with all the huge steps this requires from one technology to the other. This took me almost a month of, sometimes day-full work, to complete this transition. On 11 July (2025), the new laussy.org is made public!