Elementor aus WordPress entfernen | 114 Seiten an einem Tag zu Gutenberg konvertieren

8 min read

Eine Website von Elementor zu Gutenberg zu migrieren ist die Hölle. Es gibt keinen Zauberknopf. Jede Seite muss von Hand neu aufgebaut werden. Rechnen Sie mit mehreren Wochen. Kompletter Neuaufbau. Das ist der Konsens, steht überall, ich hab's bestimmt zehnmal gelesen, bevor ich tatsächlich angefangen habe.

Eine Kundenseite. 114 Inhalte zu migrieren. Hello Elementor Theme (eine leere Hülle ohne das Plugin), abgelaufene Pro-Lizenzen, Inhalte gefangen in Elementor JSON, die wie nichts aussehen, wenn man den Builder deaktiviert. Niemand will für eine wochenlange technische Migration bezahlen.

Ich auch nicht. Aber Sie dachten doch nicht ernsthaft, ich würde das von Hand machen, oder? 😏

TLDR: 114 Seiten an einem Tag migriert, null manueller Neuaufbau, alle URLs erhalten. Ich zeige Ihnen genau, wie Sie dasselbe bei jedem Elementor-Projekt machen.

Entwickler gebeugt über Tabelle mit 114 Seiten vs. Entwickler mit hochgelegten Füßen zeigt abgeschlossene Migration mit API-Script
Manuelle Migration vs. Automatisierung: eine Geschichte von Kaffeetassen und Reue.

Warum Elementor weg muss

Elementor war vor ein paar Jahren eine gute Wahl. WordPress Core war rau. Gutenberg war kaum brauchbar. Ein Drag-and-Drop-Builder machte Sinn für Leute, die keinen Code anfassen wollten. Das war damals.

WordPress ist weitergezogen. Gutenberg ist jetzt solide. Full Site Editing deckt das meiste ab, was Page Builder früher verkauft haben. Block Themes lassen Sie die ganze Website ohne ein einziges Plugin gestalten. Währenddessen ist Elementor zu totem Gewicht geworden: schwer, langsam, kostenpflichtig, und es sperrt Ihre Inhalte in einem proprietären Format ein, das sonst niemand lesen kann.

Das Hello Elementor Theme ist der schlimmste Übeltäter. Es ist eine leere Hülle, 100% abhängig vom Plugin. Schalten Sie Elementor aus und Ihre Seiten sind weg. Einfach weg.

Das echte Problem ist aber nicht technisch. Es ist wirtschaftlich. Niemand will für eine technische Migration bezahlen, die mehrere Wochen dauert. Der Kunde braucht eine funktionierende Website, kein Refactoring-Projekt. Und jeder Guide, den Sie über das Verlassen von Elementor lesen, sagt dasselbe. "Es gibt keinen Zauberknopf." "Mehrere Wochen dedizierte Arbeit." "Im Grunde muss die Website neu aufgebaut werden."

Dieser Konsens tötet Migrationen, bevor sie beginnen. Besitzer bleiben bei einem Plugin hängen, das sie nicht mögen, zahlen Lizenzen, die sie nicht nutzen, auf einer Website, die sie nicht bearbeiten können, ohne noch einmal Elementor zu öffnen.

Um fair zu sein, Elementor ist für manche Fälle immer noch ordentlich. Eine einmalige Landing Page. Eine temporäre Event-Website. Etwas, das der Besitzer zwei Jahre lang nicht anfassen wird. Das Problem ist nicht der Builder selbst. Es ist die langfristige Bindung an Inhalte, die Sie behalten wollen.

Das Setup: Ein App Password, ein Agent

Hier ist, was Ihnen jeder Migrations-Guide sagt. Staging-Site aufsetzen. Vollständiges Backup machen. "Elementor to Blocks" Plugin für partielle Konvertierung installieren. Jede Seite von Hand neu aufbauen, wo das Plugin versagt. Übrige Elementor-Klassen aufräumen. Alles testen. Auf Produktion pushen. Mehrere Wochen, Kalenderzeit.

Hier ist, was ich stattdessen gemacht habe. wp-admin auf der Live-Site geöffnet. Benutzer > Profil > Anwendungspasswörter. Namen eingegeben, Hinzufügen geklickt. Generiertes Passwort kopiert. Gesamte verstrichene Zeit: 30 Sekunden.

Das ist das ganze Setup. Kein OAuth-Flow, kein Webhook, kein Plugin zu installieren, keine Staging-Umgebung. Das App Password ist ein Bearer Token mit denselben Berechtigungen wie der Benutzer, der es generiert hat. Sie geben es an Claude Code weiter zusammen mit der Website-URL, und der Agent kann alles lesen und schreiben, was die REST API freigibt. Posts, Seiten, Medien, Benutzer, Einstellungen.

Wenn Sie die vollständige Anleitung wollen, wie das Ende-zu-Ende funktioniert, habe ich das komplette Setup für die Verbindung von Claude Code mit jeder WordPress-Website vor ein paar Wochen geschrieben.

Ein Satz zum Start: "Migriere diese Website von Elementor zu nativen Gutenberg-Blöcken, hier ist die URL und das App Password, arbeite über die REST API." Das war's. Kein Prompt Engineering, keine System-Anweisungen, keine Tool-Liste. Claude Code erkundete die API selbst, fand den Stack heraus (WordPress-Version, aktives Theme, Plugin-Liste, Post Types), zog ein vollständiges Backup jedes Posts und jeder Seite in eine lokale JSON-Datei und begann mit dem ersten Konvertierungsskript.

Timeline, echte Zahlen. Gestartet um 8:15 morgens. Bis Mittag waren drei Anpassungen übrig. Bis zum Abend, fertig. 114 Inhalte insgesamt (94 Posts und 20 Seiten). Der ganze technische Prozess war 100% Agent-gesteuert. Die einzige "menschliche Intervention" war, dass ich die Nachrichten der Kundin weitergeleitet habe über das, was sie behalten oder löschen wollte.

Wie Claude Code Elementor zu Gutenberg konvertiert

Erste technische Entscheidung, und sie war die, die das Ganze funktionieren ließ. Claude Code hat NICHT _elementor_data geparst. Das ist das rohe JSON, das Elementor in postmeta speichert, tief verschachtelt, Struktur variiert zwischen Elementor-Versionen, Widget-Typen ändern Namen zwischen Releases. Das zu parsen wäre ein bewegliches Ziel gewesen.

Stattdessen arbeitete es vom gerenderten HTML. Die REST API gibt content.rendered für jeden Post frei, was das finale HTML ist, nachdem Elementor seine Arbeit getan hat. Einfacher, stabiler, portabel zwischen Elementor-Versionen. Wenn das HTML auf dem Frontend richtig aussieht, hat der Parser etwas zum Kauen.

Das erste Skript, das Claude Code schrieb, convert-elementor.py. Ungefähr was es macht:

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):
    """Walk the tree, strip Elementor wrappers, emit Gutenberg blocks."""
    if el.name is None:
        return str(el)
    classes = set(el.get("class", []))
    if classes & ELEMENTOR_WRAPPERS:
        # Skip the wrapper, recurse into children
        return "".join(process_element(c) for c in el.children)
    # Map widgets to native Gutenberg blocks
    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)
    # ... other widgets
    return "".join(process_element(c) for c in el.children)

Die rekursive process_element-Funktion ist das Herzstück. Sie läuft durch den DOM-Baum, und wann immer sie auf einen Elementor-Wrapper trifft (etwa ein Dutzend verschiedene Klassennamen), überspringt sie den Wrapper und läuft weiter in die Kinder. Wenn sie auf ein echtes Widget trifft, leitet sie zu einem dedizierten Konverter weiter. Überschriften werden zu wp:heading, Bilder werden zu wp:image, Text-Editoren werden zu wp:paragraph, und so weiter. CSS-Klassen und data-*-Attribute werden auf dem Weg raus per Regex entfernt.

Zwei konkrete Beispiele.

Eine Elementor-Überschrift sieht im gerenderten HTML so aus:

<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">Unser Ansatz</span>
    </h2>
  </div>
</div>

Nach der Konvertierung:

<!-- wp:heading -->
<h2>Unser Ansatz</h2>
<!-- /wp:heading -->

Der Inline-Span mit dem Farbstil ist weg. Genauso die Elementor-Klassen, die Wrapper-Divs, die Data-Attribute. Sauberer Gutenberg-Block, bereit zum Rendern in jedem Theme.

Ein Elementor-Bild ist ähnlich. Der Builder umhüllt das <img> in eine Figur, die in zwei oder drei Divs mit Klassen wie elementor-widget-image lebt. Gutenberg erwartet eine Figur mit der Klasse wp-block-image und dem richtigen Block-Kommentar drumherum:

<!-- wp:image -->
<figure class="wp-block-image">
  <img src="..." alt="..."/>
</figure>
<!-- /wp:image -->

Gleiches Muster. Wrapper entfernen, Markup sauber neu aufbauen, in einen Gutenberg-Block-Kommentar einpacken.

Letztes Stück, den konvertierten Inhalt zurück zu WordPress pushen. Hier wurde es seltsam. Die Kundenseite ist hinter Cloudflare, und Cloudflare blockierte jede Python HTTP-Bibliothek, die ich probierte (requests, urllib, httpx). Der User-Agent sah verdächtig genug aus, um bei jedem POST einen 403er zu bekommen. Claude Code fand das selbst heraus, nach ein paar fehlgeschlagenen Aufrufen, und wechselte zu curl in einem Subprocess. Der JSON-Body geht in eine Temp-Datei, curl liest sie mit @filename, Cloudflare sieht einen normalen curl User-Agent und lässt es durch.

Nicht sauber. Es ist ein Hack. Aber es funktionierte für den ganzen Lauf, und auf lange Sicht wird jeder "temporäre Workaround" sowieso zu tragender Infrastruktur.

Das ist der Vorbehalt, den ich Ihnen schulde: der curl-Workaround ist an diesen spezifischen Host gebunden. Auf einer Website ohne Cloudflare hätte der normale Python HTTP-Client gut funktioniert. Ihre Laufleistung wird je nach CDN und Host-Konfiguration variieren.

Was kaputt ging (und wie es sich selbst reparierte)

Nach dem ersten Durchgang war die Website online. Jede Seite lud. Keine 500er, keine weißen Bildschirme. Aber der Inhalt war voller Probleme, drei verschiedene Arten von kaputt, und sie tauchten ungefähr in dieser Reihenfolge auf.

Das erste waren Geister-Spacer überall. Elementor verwendet leere Absätze mit CSS-Margin als visuelle Trenner, und wenn Sie das HTML naiv parsen, konvertieren diese leeren Absätze zu wp:spacer-Blöcken. Multiplizieren Sie das über 114 Seiten und Sie bekommen Dutzende von Spacern aufeinander gestapelt, die absurde vertikale Löcher im Inhalt schaffen.

Abschnitte, die allein in der Mitte der Seite schweben. Footer auf halber Höhe des Viewports. Das ganze Layout macht sein Bestes, um einen CSS-Reset zu imitieren, der schief gelaufen ist. Claude Code bemerkte es selbst, nachdem ich auf eine Seite gezeigt und gesagt hatte "das sieht falsch aus". Es schrieb ein zweites Skript, fix-spacers.py, das jeden Post neu zog, die Spacer-Blöcke per Regex entfernte und sie durch reguläre Zeilenumbrüche ersetzte, wo angemessen. 47 Inhalte in einem Batch gereinigt.

Dann kamen die ungültigen Block-Fehler. Gutenberg validiert Block-Markup streng. Wenn ein wp:image-Block eine Figur ohne die wp-block-image-Klasse hat, wirft Gutenberg "Dieser Block enthält unerwarteten oder ungültigen Inhalt." Gleiches für ein wp:heading, das noch übrige Elementor-Spans drin hat. Der Block lädt, aber der Editor weigert sich, ihn zu modifizieren, was schlimmer ist, als wenn er nur visuell kaputt wäre.

Die Kundin wollte ihre eigenen Seiten bearbeiten, das war der ganze Punkt. Drittes Skript, fix-blocks.py. Jeden Block neu parsen, das innere HTML von Grund auf im Format rekonstruieren, das Gutenberg erwartet, zurück pushen. 81 Inhalte repariert, aufgeteilt in 4 parallele Batches zur Beschleunigung. Claude Code entschied selbst über die Parallelisierung. Ich habe nicht gefragt.

Hier ist der narrative Punkt, der mir wichtig ist. Die ersten beiden Probleme löste Claude Code völlig selbständig. Drei Skripte insgesamt, jedes geschrieben, um die Probleme zu beheben, die das vorherige geschaffen hatte. Autonome Feedback-Schleife, gleiche Session, kein Neustart. Ich zeigte auf Symptome. Der Agent schrieb die Diagnose, schrieb die Lösung, führte die Lösung aus, verifizierte die Lösung.

Die dritte Art von kaputt ist das eigentliche Limit. Elementor Pro liefert Widgets, die keine Entsprechung im nativen Gutenberg haben. Der Homepage-Slider, weg (kein Slider-Block im Core). Das Mailchimp-Popup, weg. Das Elementor Pro Kontaktformular, weg. Das Social Icons Widget, Text erhalten, aber die visuellen Icons fallen weg. Das sind keine Konvertierungsfehler. Das sind proprietäre Widgets, die außerhalb von Elementor Pro nicht existieren, und kein Parser der Welt wird sie erfinden.

Code kann es reparieren. Vendor Lock-in kann es nicht.

Die letzten 5%, die Sie selbst machen

Kurze Anekdote zuerst. An einem Punkt musste Claude Code das Twenty Twenty-Five Theme als Fallback installieren. Die WordPress REST API gibt Theme-Installation nicht frei (aus guten Gründen, es ist eine Sicherheitsoberfläche). Also öffnete der Agent einen Browser über sein MCP-Tool, loggte sich in wp-admin ein, navigierte zu Design > Themes > Neu hinzufügen, suchte, klickte Installieren, klickte Aktivieren. Machte es selbst. Ich sah es in den Logs passieren.

Ich bringe das auf, weil die "95% automatisiert"-Rahmung einen Vorbehalt braucht. Der Agent handhabte fast alles, was die REST API erlaubte, und wenn die API etwas nicht erlaubte, fand er einen anderen Kanal. Was für den Menschen zu tun übrig bleibt, ist nicht technische Arbeit, die der Agent nicht bewältigen kann. Es sind Geschäftsentscheidungen, die der Agent nicht allein treffen sollte.

Konkret, was ich am Ende manuell anfassen musste:

  • Welches Formular-Plugin zu installieren, um die Elementor Pro Formulare zu ersetzen. WPForms Lite, Contact Form 7, Fluent Forms, jedes hat Kompromisse. Nicht eine Agent-Entscheidung.
  • Wie die Newsletter-Anmeldung zu reintegrieren. Nativer Mailchimp-Embed, MC4WP-Plugin oder ein völlig neuer Anmelde-Flow.
  • Ein neues Hero-Bild auswählen, weil das alte Text eingebacken hatte.
  • Rank Math SEO Meta auf den wichtigen Landing Pages überprüfen, um sicherzustellen, dass nichts rückläufig war.
  • Übrige _elementor_*-Zeilen in postmeta aufräumen (WP-CLI oder direktes SQL, um die Datenbank zu erleichtern).
  • Die Hello Elementor Theme-Dateien entfernen (dafür gibt es auch keinen REST-Endpunkt).

95% automatisiert, 5% manuell. Und diese 5% sind Entscheidungsarbeit, nicht Rekonstruktionsarbeit. Bevor Sie einen Coding-Agent auf eine Produktionsseite loslassen, wollen Sie genau definieren, was er anfassen darf und was er eskalieren muss. Das ist der ganze Grund, warum ich die Execution Scope Disziplin aufgebaut habe, die ich verwende, bevor ich einen Agent auf Produktion loslasse. Klarer Scope, klare Eskalationsregeln, klare Stopp-Bedingungen. Ohne das spielen Sie auf einer Live-Site Glücksspiel und hoffen, dass der Agent sich selbst korrigiert, bevor er etwas zerstört.

Die REST API selbst hat harte Grenzen, die es wert sind, sie zu kennen. Keine Theme-Löschung, kein Plugin-Code-Zugriff, keine PHP-Ausführung, kein Dateisystem. Für alles außerhalb der API-Oberfläche brauchen Sie SSH oder wp-admin. Definieren Sie den Perimeter, bevor Sie starten.

Der Knopf, der nicht da war

114 Inhalte. Drei Skripte. Ein Tag. Tippfehler unterwegs behoben, wichtige Seiten überprüft, alle URLs erhalten. Die Kundin bearbeitet jetzt ihre eigenen Seiten, ohne mich anzurufen.

Jeder Guide hat recht. Es gibt keinen Zauberknopf für Elementor zu Gutenberg. Aber ein Agent, der seine eigenen Konvertierungsskripte schreibt und seine eigenen Bugs in einer kontinuierlichen Session behebt, das ist kein Knopf.

Es ist besser als ein Knopf 🚀

Quellen

  • WordPress REST API Handbook
  • Konsens-Guides zur Elementor zu Gutenberg Migration: Blog Marketing Academy, Crocoblock, Ulement ("es gibt keinen Zauberknopf", "mehrere Wochen dedizierte Arbeit")

(*) Das Cover ist KI-generiert. Stellt sich heraus, der einzige echte Zauberknopf in dieser ganzen Geschichte war der, der das Header-Bild gemacht hat.