Changement de moteur de blog

Aprés des années à utiliser Wordpress, je suis passé à nikola.

Pourquoi ?

Beaucoup de pourquoi pas.

Une pincée d’écologie

Il est bien plus efficace pour un site web de servir des pages statiques, plutôt que de calculer dynamiquement ces pages à chaque fois qu’un visiteur passe dans le coin. Et c’est encore plus vrai avec mon site qui évolue très très peu.

Directement, ça va faire du bien aux machines de Free, même si ce n’est pas mes quelques centaines de pages visitées exclusivement par des bots qui vont faire une grosse différence. Quoique, si tout le monde s’y met…

Par contre, avec un système comme celui-ci, je peux envisager d’auto-héberger mon site sur de toutes petites machines comme les Raspberry Pi, Cubieboard et consor.

Je peux même envisager les deux, vu qu’il suffit de recopier les fichiers du site, aprés une éventuelle regénération pour fixer l’URL de destination.

Mais bon, danbs un premier temps, le site va rester chez Free.

Sans maîtrise, la puissance n’est rien

Un moteur de blog dynamique comme Wordpress a énormément d’avantages. Mais pour un geek comme moi, il a un inconvénient de taille : il s’occupe tout seul de certaines choses et me dépossède des moyens de maîtriser les données et comment elles sont traitées. Du coup, les tâches qui n’ont pas été prévues par les développeurs risquent de devenir très difficiles, voire laborieuses, voire impossibles à réaliser.

Avec un système comme nikola, les
articles sont de simples fichiers textes. Et quand je dis simple,
c’est loin d’être péjoratif. A mes yeux, c’est d’une valeur inestimable
je peux rédiger, fignoler mes articles avec l’éditeur de mon choix, je peux gérer ce contenu avec une grandes variétés d’outils allant du script de la ligne de commande à une gestion de version, et même je peux récupérer le contenu avec une puissance inégalité.

Et ce qu’on perd ?

Coté inconvénients, ce qu’on peut identifier de plus gros c’est l’absence de rédaction en ligne. Avec Wordpress, il suffisait d’avoir une connexion Internet et un navigateur pour rajouter un billet. Avec Nikola, il faut… une installation de nikola.

Pour contourner cette limitation, j’envisage une solution à base de Git et GitHub, ce dernier proposant un éditeur en ligne. Bien sûr, cela ne regénèrera pas mon blog, mais je serai en mesure de saisir les idées qui me passe par la tête en toute occasion. Et je fignolerai le tout une fois revenu à la maison.

Conversion Wordpress

Entrons dans le vif du sujet, ce qui m’a pris un long long moment : la conversion du blog.

Extraction des données

Première étape : extraire les données pour les mettre dans un format acceptable par nikola. Sur le site, il est indiqué une procédure pour convertir un blog Wordpress. Malheureusement, cette piste a tourné vite court. En effet, elle prend en entrée le résultat d’une extraction proposée par le moteur de Wordpress. Hélas, l’extraction ne va pas jusqu’au bout et avorte. J’imagine que, mon blog ayant un peu vécu, il contient pas mal d’articles et que le temps (et les ressources) nécessaire à convertir tout ça dans le format d’export n’est pas compatible avec les réglages de mon hébergeur (Free).

Du coup, il va falloir bidouiller.

Première idée : télécharger toutes les pages et bricoler. Télécharger fût simple à faire :

curl nathguil.free.fr/wordpress/?p=[1-600] -o "posts/#1.html"

Mais ensuite, il faut faire des scripts pour retirer tout ce qui ne sert pas (toutes les parties générées par Wordpress) et extraire le maximum d’information (tags, auteur, date…). Avant de m’aventurer trop loin dans cette voie, j’ai voulu en tester une autre.

Seconde idée : utiliser un export SQL. Pour l’export proprement dit, rien de bien sorcier, il suffit d’aller sur la page de Free. Là, je demande un export XML. Ensuite, c’est déjà moins simple : comprendre ce qu’on peut récupérer et comment. Mais dans un premier temps, je me limite à extraire le contenu. Une petite feuille XSL pour générer le contenu de chaque page dans un ficher .wordpress et les métadonnées dans un fichier .meta :

<xsl:template match="/">
    <xsl:apply-templates select="nathguil/wp_posts"/>
</xsl:template>

<xsl:template match="wp_posts">
    <xsl:variable name="dir">
        <xsl:choose>
            <xsl:when test="post_type/text() = 'post'"><xsl:text>posts</xsl:text></xsl:when>
            <xsl:when test="post_type/text() = 'page'"><xsl:text>stories</xsl:text></xsl:when>
        </xsl:choose>
    </xsl:variable>
    <xsl:variable name="filename" select="post_name/text()"/>
    <xsl:variable name="author" select="post_author/text()"/>
    <xsl:if test="post_type/text() = 'post' or post_type/text() = 'page'">
        <xsl:document href="{$dir}/{$filename}.wordpress" method="text">
            <xsl:value-of disable-output-escaping="yes" select="post_content/text()"/>
        </xsl:document>
        <xsl:document href="{$dir}/{$filename}.meta" method="text">
            <xsl:text></xsl:text><xsl:value-of select="post_title/text()"/>
            <xsl:text>
</xsl:text><xsl:value-of select="$filename"/>
            <xsl:text>
</xsl:text><xsl:value-of select="post_date/text()"/>
            <xsl:text>
</xsl:text><xsl:value-of select="$tags"/>
            <xsl:text>
</xsl:text>
        </xsl:document>
    </xsl:if>
</xsl:template>
Le format de Wordpress est une bouillie de syntaxe wiki et de code HTML
les paragraphes sont créés automatiquement et les balises HTML sont supportées. OK, mais comment transformer ça en MarkDown ou RestructuredText ? J’ai essayé quelques conversions avec PanDoc. Par exemple :
for file in *.wordpress; do pandoc -t html $file | pandoc -f html -t markdown - -o $file.md; done

Mais les résultats sont pour le moins perfectibles. En particulier sur la gestion des sections litérales (blocs <code>).

Puis vint l’éclair de génie (si l’on peut dire) : le format de Wordpress c’est presque du balisage léger et le format MarkDown tel que supporté par nikola autorise des balises HTML. Bref, et si on se passait de conversion ? Et ça marche presque : il faut juste corriger les hard-breaks (Wordpress converti les sauts de ligne en <br/>) et transformer les blocs de code (en MarkDown il faut rajouter des blancs en début de ligne). Du coup, un peu de script et hop mes fichiers .wordpress sont devenus des .md.

Encodage

Ensuite, j’ai réalisé que le contenu n’était pas correctement encodé. Après analyses, j’en ai déduis que le fichier était doublement encodé en UTF-8 :

  • une première fois, naturellement, UTF-8 étant visiblement l’encodage choisi par Wordpress,
  • une seconde fois, pour je ne sais quelle raison, un process a considéré le contenu en windows-1252 et l’a reconverti une seconde fois en UTF-8.

Du coup, rien de bien sorcier, y’a qu’à faire le chemin inverse pour retrouver notre UTF-8, aussi bien sur les fichier de contenu que sur les fichiers meta :

for file in */*.md; do iconv -f utf8 -t windows-1252 $file --output $file.new; mv $file.new $file; done
for file in */*.meta; do iconv -f utf8 -t windows-1252 $file --output $file.new; mv $file.new $file; done

Maintenant que le texte est restoré, reste à s’occuper des détails.

Images

Premier détail : les différentes images qui égayent mes articles.

Je les ai téléchargées, installées sous galleries et puis j’ai passé tous mes articles a une nième moulinette. Cette fois la moulinette va changer les liens, mais aussi s’occuper des certaines miniatures nommées image-300x255.jpg (par exemple).

sed -i "s;http://nathguil.free.fr/wordpress/wp-content;/galleries;g" */*.*
sed -i "s;\(galleries/[^/]*\)-.*x.*\.;\1.thumbnail.;p" */*.*

Liens internes

Deuxième détail : les liens entre les articles.

Dans mon Wordpress, les liens se référencent entre eux avec des URL du genre .../wordpress/?p=28. Or, avec Nikola, il faut utiliser des noms (et pas des numéros). Du coup, il faut construire une table de correspondance.

Et là, c’est assez simple, il suffit de retourner à notre dump SQL en XML et de demander l’extraction de ces infos sous forme d’un tableau :

extract-corres.xsl

<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">

<xsl:template match="/">
	<xsl:apply-templates select="nathguil/wp_posts"/>
</xsl:template>

<xsl:template match="wp_posts">
	<xsl:variable name="dir">
		<xsl:choose>
			<xsl:when test="post_type/text() = 'post'"><xsl:text>posts</xsl:text></xsl:when>
			<xsl:when test="post_type/text() = 'page'"><xsl:text>pages</xsl:text></xsl:when>
		</xsl:choose>
	</xsl:variable>
	<xsl:variable name="filename" select="post_name/text()"/>
	<xsl:variable name="author" select="post_author/text()"/>
	<xsl:variable name="id" select="ID/text()"/>
	<xsl:if test="post_type/text() = 'post' or post_type/text() = 'page'">
		<xsl:value-of select="$id"/><xsl:text> </xsl:text><xsl:value-of select="$dir"/><xsl:text> </xsl:text><xsl:value-of select="$filename"/><xsl:text> </xsl:text><xsl:value-of select="post_title/text()"/><xsl:text>
</xsl:text>
	</xsl:if>
</xsl:template>

</xsl:stylesheet>

Une fois fait, reste à transformer tout ça en directives pour notre meilleur ami sed :

xsltproc extract-corres.xsl nathguil.xml | awk '{printf "s;http://nathguil.free.fr/wordpress/?p=%s\";/%s/%s.html\";g\n", $1, $2, $3}' > convert_links.sed
sed -i -f convert_links.sed */*.*

Redirections

Une fois le nouveau site en place, il serait utile de pas perdre les utilisateurs de mon Wordpress. Heureusement, l’interface de Wordpress se limite à un fichier index.php. Du coup, on peut facilement rajouter une redirection depuis les URL pointant vers Wordpress vers celles de Nikola.

php-redirect.xsl

<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">

<xsl:output method="text"/>

<xsl:template match="/">
	<xsl:text>&lt;?php
</xsl:text>
	<xsl:apply-templates select="nathguil/wp_posts"/>
	<xsl:text>
$id = $_REQUEST["p"] ;
$filename = $filenames[$id] ;
header( 'Location: http://nathguil.free.fr/nikola/' . $filename ) ;
?&gt;
</xsl:text>
</xsl:template>

<xsl:template match="wp_posts">
	<xsl:variable name="dir">
		<xsl:choose>
			<xsl:when test="post_type/text() = 'post'"><xsl:text>posts</xsl:text></xsl:when>
			<xsl:when test="post_type/text() = 'page'"><xsl:text>pages</xsl:text></xsl:when>
		</xsl:choose>
	</xsl:variable>
	<xsl:variable name="filename" select="post_name/text()"/>
	<xsl:variable name="id" select="ID/text()"/>
	<xsl:if test="post_type/text() = 'post' or post_type/text() = 'page'">
		<xsl:text>$filenames[</xsl:text><xsl:value-of select="$id"/><xsl:text>] = "</xsl:text><xsl:value-of select="$dir"/><xsl:text>/</xsl:text><xsl:value-of select="$filename"/><xsl:text>.html" ;
</xsl:text>
	</xsl:if>
</xsl:template>

</xsl:stylesheet>
xsltproc php-redirect.xsl nathguil.xml > index.php

Conversion MediaWiki

Conjointement à Wordpress, j’avais installé un MediaWiki. Il me faut donc récupérer ce contenu et l’importer dans Nikola.

Mais ça, ce sera pour une autre fois.