Migration d'un blog WordPress vers Hexo : retour d'expérience
J’ai migré mon blog de WordPress vers Hexo il y a quelques mois. Voici pourquoi, comment, et ce que ça a changé.
Cet article n’est pas un procès contre WordPress, qui reste un excellent CMS pour bien des usages. Il s’agit plutôt d’un retour d’expérience: pour un blog technique, essentiellement composé de texte et de code, les avantages d’un générateur statique se sont avérés décisifs. Si vous hésitez à franchir le pas, voici le détail de ce qui m’a décidé et de la façon dont j’ai procédé.
Pourquoi quitter WordPress ?
| Critère | WordPress | Hexo |
|---|---|---|
| Temps de chargement | ~2.5 s | ~0.4 s |
| Sécurité | Mises à jour + plugins + firewall | Fichiers statiques |
| Hébergement | Serveur PHP + MySQL | Nginx ou S3 |
| Coût mensuel | ~15 € (VPS) | ~3 € (ou gratuit) |
| Sauvegardes | Base + fichiers | Un dépôt Git |
Le tableau résume l’essentiel. Un blog statique n’a rien à exécuter: pas de PHP, pas de base de données, pas de processus applicatif. Résultat, il se charge plus vite, il est plus simple à sécuriser (un fichier statique ne se fait pas pirater), et il coûte moins cher à héberger puisqu’un simple serveur de fichiers ou un bucket S3 suffit.
La goutte d’eau qui a mis le feu aux poudres : une nuit de 2025, une mise à jour automatique de plugin a cassé le site. Temps de résolution : 2h. Pour un blog technique, c’est inacceptable.
Ce n’était pourtant pas la première fois qu’un plugin me posait problème. Mais cette fois-là, le site est tombé en pleine nuit, sans intervention de ma part: la mise à jour automatique d’un plugin de sécurité avait provoqué un conflit qui a fait planter le serveur entier. Deux heures pour remonter, avec l’angoisse de possibles pertes de données. C’est à ce moment que j’ai décidé qu’un générateur statique ne m’exposerait jamais à ce genre de veillée.
La migration pas à pas
1. Exporter WordPress
J’ai utilisé le plugin officiel WordPress Exporter pour générer un fichier XML complet.
L’export Wordpress eXtended RSS (WXR) contient l’ensemble des articles, pages, commentaires, catégories et tags dans un seul fichier XML. C’est le format standard, reconnu par la plupart des outils d’import. Le générer prend quelques secondes et ne nécessite aucun accès au serveur : tout est fait depuis l’interface admin.
2. Convertir avec hexo-migrator-wordpress
npm install hexo-migrator-wordpress |
Les articles sont importés avec leur titre, date, contenu et tags. Mais le formatage Markdown est approximatif: beaucoup de balises HTML subsistent.
C’est l’étape la plus automatique mais aussi la plus imparfaite. WordPress stocke le contenu en HTML (avec le fameux wpautop qui ajoute des <p> et des <br> automatiquement), et le migrator fait de son mieux pour le convertir en Markdown. Le résultat est fonctionnel, mais truffé de restes de balises et d’espaces insécables ( ). C’est pourquoi l’étape suivante, le nettoyage, est indispensable.
3. Nettoyage automatisé
// scripts/clean-wordpress-import.js |
Plutôt que de nettoyer des dizaines d’articles à la main, un filtre Hexo passe sur le contenu de chaque article lors du rendu. Chaque regex transforme un reste de HTML en syntaxe Markdown équivalente. C’est le genre de micro-script qui transforme une migration fastidieuse en opération quasi automatique, en une vingtaine de lignes.
Ce filtre s’attache au moment after_post_render : il s’exécute après que Hexo a rendu l’article, donc il peut réécrire le contenu avant qu’il ne soit écrit dans le fichier statique final.
4. Migration des images
# Déplacer les uploads WordPress vers le répertoire source Hexo |
Puis remplacer les URLs :
// scripts/fix-image-paths.js |
Les images sont copiées, puis toutes les URLs absolues qui pointaient vers l’ancien site sont réécrites en chemins relatifs vers le nouveau répertoire source/images/. Là encore, une regex dans un filtre évite de toucher chaque article individuellement, et garantit que toutes les images, sans exception, pointent au bon endroit.
5. Migration des URLs
WordPress utilise /YYYY/MM/DD/slug/. Hexo par défaut aussi (:year/:month/:day/:title/). J’ai gardé la même structure pour ne pas casser les liens entrants :
# _config.yml |
Conserver la structure d’URL était une décision importante: toutes les redirections et les liens entrants (Google, autres sites) pointent vers les anciennes URLs. En gardant exactement le même schéma, aucun redirect n’est nécessaire et l’historique SEO est préservé sans effort supplémentaire.
Ce que j’ai perdu
- Commentaires: remplacés par un lien GitHub Discussions (moins de spam)
- Éditeur visuel: j’écris en Markdown dans VS Code (plus rapide)
- Plugins analytics: Umami auto-hébergé, plus léger et respectueux
La perte la plus significative en apparence est celle des commentaires. Mais je l’ai transformée en avantage: la modération et l’anti-spam inhérents aux commentaires WordPress demandaient du temps, alors qu’un lien vers GitHub Discussions me laisse le choix des conversations et élimine quasi totalement le spam automatisé.
Ce que j’ai gagné
Un git push et le blog est déployé. Plus de PHP, plus de MySQL, plus d’attaques par injection.
Le flux de travail s’est radicalement simplifié : j’écris un article en Markdown dans VS Code, je fais un git push, et une pipeline CI/CD construit le site statique et le déploie sur Nginx. L’absence de PHP et de MySQL supprime toute une classe d’attaques (injection SQL, exécution de code côté serveur), et le workflow Git me donne un historique complet de chaque changement.
Performances avant/après
| Métrique | WordPress | Hexo |
|---|---|---|
| Lighthouse Performance | 72 | 98 |
| First Contentful Paint | 1.8 s | 0.3 s |
| Requêtes HTTP | 45 | 8 |
| Taille page | 1.2 Mo | 180 Ko |
Les chiffres parlent d’eux-mêmes. La réduction drastique des requêtes HTTP (45 -> 8) et de la taille de page (1.2 Mo -> 180 Ko) vient surtout de l’absence de plugins qui injectaient des scripts et des styles inutiles sur chaque page. Un blog statique n’emporte que ce dont il a réellement besoin.
Mon conseil
Si votre blog est principalement du texte et du code, le statique est supérieur sur tous les plans. WordPress n’a d’intérêt que si vous avez besoin d’un CMS dynamique avec des utilisateurs non techniques.
C’est le critère décisif: avez-vous besoin d’utilisateurs non techniques qui éditeraient le contenu via une interface? Si la réponse est non (ce qui est le cas d’un blog technique dont l’auteur écrit du code), alors la complexité de WordPress n’apporte aucun bénéfice. Le Markdown et Git suffisent largement, et enlèvent toute la couche de maintenance.
La migration m’a pris un weekend. Depuis, je n’y pense plus et c’est le meilleur compliment qu’on puisse faire à un outil.
Si vous êtes convaincu, notez qu’un weekend suffit: un pour exporter et configurer, quelques heures pour nettoyer l’import. Ensuite, chaque article se rédige plus vite qu’avant, et le déploiement est un simple git push. Le coût permanent, lui, tombe à presque rien.