Comment Supprimer Elementor de WordPress | Convertir 114 Pages vers Gutenberg en Une Journée
Migrer un site d'Elementor vers Gutenberg, c'est l'enfer. Il n'y a pas de bouton magique. Il faut reconstruire chaque page à la main. Comptez plusieurs semaines. Tout refaire de zéro. C'est le consensus général, on le lit partout, je l'ai vu peut-être dix fois avant de me lancer pour de bon.
Un site client. 114 contenus à migrer. Thème Hello Elementor (une coquille vide sans le plugin), licences Pro expirées, contenu enfermé dans du JSON Elementor qui ne ressemble à rien si on désactive le builder. Personne ne veut payer une migration technique de plusieurs semaines.
Moi non plus. Mais vous ne pensiez quand même pas que j'allais le faire à la main ? 😏
TLDR : 114 pages migrées en une journée, zéro reconstruction manuelle, toutes les URLs préservées. Je vais vous montrer exactement comment faire pareil sur n'importe quel projet Elementor.

Pourquoi Elementor doit disparaître
Elementor était un bon choix il y a quelques années. Le cœur de WordPress était rugueux. Gutenberg était à peine utilisable. Un builder drag-and-drop avait du sens pour ceux qui ne voulaient pas toucher au code. C'était avant.
WordPress a évolué. Gutenberg est solide maintenant. L'édition complète de site couvre la plupart de ce que vendaient les page builders. Les thèmes à blocs permettent de designer tout le site sans un seul plugin. Pendant ce temps, Elementor est devenu un boulet : lourd, lent, payant, et il verrouille votre contenu dans un format propriétaire que personne d'autre ne peut lire.
Le thème Hello Elementor est le pire. C'est une coquille vide, 100% dépendante du plugin. Désactivez Elementor et vos pages disparaissent. Purement et simplement.
Le vrai problème n'est pas technique. Il est économique. Personne ne veut payer une migration technique qui prend plusieurs semaines. Le client a besoin d'un site qui fonctionne, pas d'un projet de refactoring. Et tous les guides qu'on lit sur l'abandon d'Elementor disent la même chose. "Il n'y a pas de bouton magique." "Plusieurs semaines de travail dédié." "En gros, le site doit être reconstruit."
Ce consensus tue les migrations dans l'œuf. Les propriétaires restent coincés sur un plugin qu'ils n'aiment pas, payent des licences qu'ils n'utilisent pas, sur un site qu'ils ne peuvent pas éditer sans ouvrir Elementor une fois de plus.
Pour être honnête, Elementor reste correct dans certains cas. Une landing page ponctuelle. Un site d'événement temporaire. Quelque chose que le propriétaire ne touchera pas pendant deux ans. Le problème n'est pas le builder lui-même. C'est l'enfermement à long terme sur du contenu qu'on voudra garder.
La configuration : un mot de passe d'app, un agent
Voici ce que tous les guides de migration vous disent de faire. Monter un site de staging. Faire une sauvegarde complète. Installer le plugin "Elementor to Blocks" pour une conversion partielle. Reconstruire chaque page à la main là où le plugin échoue. Nettoyer les classes Elementor résiduelles. Tout tester. Pousser en production. Plusieurs semaines, temps calendaire.
Voici ce que j'ai fait à la place. Ouvert wp-admin sur le site en live. Utilisateurs > Profil > Mots de passe d'application. Tapé un nom, cliqué sur Ajouter. Copié le mot de passe généré. Temps total écoulé : 30 secondes.
C'est toute la configuration. Pas de flux OAuth, pas de webhook, pas de plugin à installer, pas d'environnement de staging. Le mot de passe d'app est un token bearer avec les mêmes permissions que l'utilisateur qui l'a généré. Vous le passez à Claude Code avec l'URL du site, et l'agent peut lire et écrire tout ce que l'API REST expose. Articles, pages, médias, utilisateurs, paramètres.
Si vous voulez le walkthrough complet de comment ça marche de bout en bout, j'ai écrit la configuration complète pour connecter Claude Code à n'importe quel site WordPress il y a quelques semaines.
Une phrase pour lancer : "Migre ce site d'Elementor vers des blocs Gutenberg natifs, voici l'URL et le mot de passe d'app, travaille depuis l'API REST." C'est tout. Pas d'ingénierie de prompt, pas d'instructions système, pas de liste d'outils. Claude Code a exploré l'API tout seul, compris la stack (version WordPress, thème actif, liste des plugins, types de posts), tiré une sauvegarde complète de chaque article et page dans un fichier JSON local, et commencé à écrire son premier script de conversion.
Timeline, chiffres réels. Lancé à 8h15 du matin. À midi il restait trois ajustements. Le soir, terminé. 114 contenus au total (94 articles et 20 pages). Tout le processus technique était 100% piloté par l'agent. La seule "intervention humaine" était moi relayant les messages du client sur ce qu'elle voulait garder ou supprimer.
Comment Claude Code convertit Elementor vers Gutenberg
Première décision technique, et c'est celle qui a fait que tout a marché. Claude Code n'a PAS parsé _elementor_data. C'est le JSON brut qu'Elementor stocke dans postmeta, profondément imbriqué, la structure varie entre les versions d'Elementor, les types de widgets changent de nom d'une release à l'autre. Parser ça aurait été une cible mouvante.
À la place, il a travaillé depuis le HTML rendu. L'API REST expose content.rendered pour chaque post, qui est le HTML final après qu'Elementor ait fait son travail. Plus simple, plus stable, portable entre les versions d'Elementor. Si le HTML a l'air correct en frontend, le parser a quelque chose à se mettre sous la dent.
Le premier script que Claude Code a écrit, convert-elementor.py. En gros ce qu'il fait :
import json, re
from bs4 import BeautifulSoup
ELEMENTOR_WRAPPERS = {
"elementor-section", "elementor-container", "elementor-column",
"elementor-widget-wrap", "elementor-widget", "e-con", "e-con-inner",
"e-child", "elementor-row", "elementor-element"
}
def process_element(el):
"""Parcourt l'arbre, supprime les wrappers Elementor, émet des blocs Gutenberg."""
if el.name is None:
return str(el)
classes = set(el.get("class", []))
if classes & ELEMENTOR_WRAPPERS:
# Ignore le wrapper, récurse dans les enfants
return "".join(process_element(c) for c in el.children)
# Mappe les widgets vers des blocs Gutenberg natifs
if "elementor-widget-heading" in classes:
return convert_heading(el)
if "elementor-widget-image" in classes:
return convert_image(el)
if "elementor-widget-text-editor" in classes:
return convert_paragraph(el)
# ... autres widgets
return "".join(process_element(c) for c in el.children)
La fonction récursive process_element est le cœur du système. Elle parcourt l'arbre DOM, et chaque fois qu'elle tombe sur un wrapper Elementor (une douzaine de noms de classes différents), elle ignore le wrapper et continue à descendre dans les enfants. Quand elle tombe sur un widget réel, elle route vers un convertisseur dédié. Les titres deviennent wp:heading, les images deviennent wp:image, les éditeurs de texte deviennent wp:paragraph, etc. Les classes CSS et attributs data-* sont supprimés par regex en sortie.
Deux exemples concrets.
Un titre Elementor ressemble à ça dans le HTML rendu :
<div class="elementor-widget elementor-widget-heading" data-id="a1b2c3">
<div class="elementor-widget-container">
<h2 class="elementor-heading-title elementor-size-default">
<span style="color: #333">Notre approche</span>
</h2>
</div>
</div>
Après conversion :
<!-- wp:heading -->
<h2>Notre approche</h2>
<!-- /wp:heading -->
Le span inline avec le style de couleur a disparu. Comme les classes Elementor, les divs wrapper, les attributs data. Bloc Gutenberg propre, prêt à s'afficher dans n'importe quel thème.
Une image Elementor, c'est pareil. Le builder enrobe l'<img> dans une figure qui vit à l'intérieur de deux ou trois divs avec des classes comme elementor-widget-image. Gutenberg attend une figure avec la classe wp-block-image et le bon commentaire de bloc autour :
<!-- wp:image -->
<figure class="wp-block-image">
<img src="..." alt="..."/>
</figure>
<!-- /wp:image -->
Même pattern. Supprimer les wrappers, reconstruire le markup proprement, enrober dans un commentaire de bloc Gutenberg.
Dernière pièce, repousser le contenu converti vers WordPress. C'est là que ça a déconné. Le site client est derrière Cloudflare, et Cloudflare bloquait toutes les librairies HTTP Python que j'ai essayées (requests, urllib, httpx). Le user-agent avait l'air assez suspect pour se prendre un 403 sur chaque POST. Claude Code a compris ça tout seul, après quelques appels ratés, et a basculé sur curl dans un subprocess. Le body JSON va dans un fichier temp, curl le lit avec @filename, Cloudflare voit un user-agent curl normal et laisse passer.
Pas propre. C'est un hack. Mais ça a marché pour toute la run, et sur une timeline assez longue, tous les "workarounds temporaires" deviennent de l'infrastructure critique de toute façon.
C'est la mise en garde que je vous dois : le workaround curl est lié à cet hébergeur spécifique. Sur un site sans Cloudflare, le client HTTP Python normal aurait marché nickel. Votre kilométrage peut varier selon la config CDN et hébergeur.
Ce qui a cassé (et comment ça s'est réparé tout seul)
Après le premier passage, le site était en ligne. Chaque page se chargeait. Pas de 500, pas d'écrans blancs. Mais le contenu était truffé de problèmes, trois saveurs différentes de cassé, et elles sont apparues dans cet ordre.
Le premier, c'était des espaceurs fantômes partout. Elementor utilise des paragraphes vides avec de la marge CSS comme séparateurs visuels, et quand on parse le HTML naïvement, ces paragraphes vides se convertissent en blocs wp:spacer. Multipliez ça sur 114 pages et vous obtenez des dizaines d'espaceurs empilés les uns sur les autres, créant des trous verticaux absurdes dans le contenu.
Des sections qui flottent seules au milieu de la page. Des footers à mi-hauteur du viewport. Toute la mise en page qui fait son meilleur cosplay d'un reset CSS qui a mal tourné. Claude Code l'a remarqué tout seul après que j'aie pointé une page en disant "ça a l'air foireux". Il a écrit un deuxième script, fix-spacers.py, qui a re-tiré chaque post, supprimé les blocs spacer par regex, et les a remplacés par des sauts de ligne normaux quand c'était approprié. 47 contenus nettoyés en un batch.
Puis sont venues les erreurs de blocs invalides. Gutenberg valide le markup des blocs strictement. Si un bloc wp:image a une figure sans la classe wp-block-image, Gutenberg lève "Ce bloc contient du contenu inattendu ou invalide." Pareil pour un wp:heading qui a encore des spans Elementor à l'intérieur. Le bloc se charge mais l'éditeur refuse de le modifier, ce qui est pire que s'il était juste cassé visuellement.
Le client voulait éditer ses propres pages, c'était tout l'intérêt. Troisième script, fix-blocks.py. Re-parser chaque bloc, reconstruire le HTML interne from scratch en utilisant le format que Gutenberg attend, le repousser. 81 contenus fixés, répartis en 4 batches parallèles pour accélérer. Claude Code a décidé du parallélisme tout seul. Je n'ai pas demandé.
Voici le point narratif qui m'importe. Les deux premiers problèmes, Claude Code les a résolus entièrement tout seul. Trois scripts au total, chacun écrit pour fixer les problèmes que le précédent avait créés. Boucle de feedback autonome, même session, pas de restart. J'ai pointé des symptômes. L'agent a écrit le diagnostic, écrit le fix, lancé le fix, vérifié le fix.
La troisième saveur de cassé, c'est la vraie limite. Elementor Pro livre des widgets qui n'ont pas d'équivalent dans Gutenberg natif. Le slider de homepage, disparu (pas de bloc slider dans le core). La popup Mailchimp, disparue. Le formulaire de contact Elementor Pro, disparu. Le widget d'icônes sociales, texte préservé mais les icônes visuelles supprimées. Ce ne sont pas des bugs de conversion. Ce sont des widgets propriétaires qui n'existent pas en dehors d'Elementor Pro, et aucun parser au monde ne va les inventer.
Le code, il peut le fixer. Le vendor lock-in, il ne peut pas.
Les derniers 5% que vous ferez vous-même
Petite anecdote d'abord. À un moment, Claude Code a eu besoin d'installer le thème Twenty Twenty-Five comme fallback. L'API REST WordPress n'expose pas l'installation de thèmes (pour de bonnes raisons, c'est une surface de sécurité). Donc l'agent a ouvert un navigateur via son outil MCP, s'est connecté à wp-admin, a navigué vers Apparence > Thèmes > Ajouter, a cherché, cliqué sur Installer, cliqué sur Activer. Il l'a fait tout seul. J'ai regardé ça se passer dans les logs.
Je mentionne ça parce que le cadrage "95% automatisé" a besoin d'une mise en garde. L'agent a géré presque tout ce que l'API REST permettait, et quand l'API ne permettait pas quelque chose, il a trouvé un autre canal. Ce qui reste à faire pour l'humain à la fin, ce n'est pas du travail technique que l'agent ne peut pas gérer. Ce sont des décisions business que l'agent ne devrait pas prendre seul.
Concrètement, ce que j'ai dû toucher manuellement à la fin :
- Quel plugin de formulaire installer pour remplacer les formulaires Elementor Pro. WPForms Lite, Contact Form 7, Fluent Forms, chacun a ses compromis. Pas un appel d'agent.
- Comment réintégrer l'inscription newsletter. Embed Mailchimp natif, plugin MC4WP, ou un nouveau flux d'inscription entièrement.
- Choisir une nouvelle image hero parce que l'ancienne avait du texte intégré dedans.
- Réviser les méta SEO Rank Math sur les pages d'atterrissage clés pour s'assurer que rien n'a régressé.
- Nettoyer les lignes
_elementor_*restantes danspostmeta(WP-CLI ou SQL direct, pour alléger la base). - Supprimer les fichiers du thème Hello Elementor (pas d'endpoint REST pour ça non plus).
95% automatisé, 5% manuel. Et ces 5% sont du travail de décision, pas du travail de reconstruction. Avant de pointer un agent de code sur un site de production, vous voulez définir exactement ce qu'il a le droit de toucher et ce qu'il doit escalader. C'est toute la raison pour laquelle j'ai construit la discipline de scope d'exécution que j'utilise avant de lancer un agent en production. Scope clair, règles d'escalade claires, conditions d'arrêt claires. Sans ça vous pariez sur un site live en espérant que l'agent se corrige avant de casser quelque chose.
L'API REST elle-même a des limites dures qu'il faut connaître. Pas de suppression de thème, pas d'accès au code des plugins, pas d'exécution PHP, pas de système de fichiers. Pour tout ce qui est en dehors de la surface API, vous avez besoin de SSH ou wp-admin. Définissez le périmètre avant de lancer.
Le bouton qui n'existait pas
114 contenus. Trois scripts. Une journée. Coquilles corrigées au passage, pages clés révisées, toutes les URLs préservées. Le client édite ses propres pages maintenant sans m'appeler.
Tous les guides ont raison. Il n'y a pas de bouton magique pour Elementor vers Gutenberg. Mais un agent qui écrit ses propres scripts de conversion et corrige ses propres bugs dans une session continue, ce n'est pas un bouton.
C'est mieux qu'un bouton 🚀
Sources
- WordPress REST API Handbook
- Guides consensus sur la migration Elementor vers Gutenberg : Blog Marketing Academy, Crocoblock, Ulement ("il n'y a pas de bouton magique", "plusieurs semaines de travail dédié")
(*) La couverture est générée par IA. Il s'avère que le seul vrai bouton magique dans toute cette histoire était celui qui a fait l'image d'en-tête.