Der Umzug einer WordPress-Website von der Entwicklungsumgebung auf die Produktionsdomain, ein Markenwechsel oder die Einführung eines SSL-Zertifikats (Wechsel von HTTP auf HTTPS) gehören zum Alltag jedes Administrators und Entwicklers. Auf den ersten Blick wirkt die Aufgabe trivial: Datenbank als .sql-Datei exportieren, im Code-Editor “Suchen und Ersetzen” ausführen und die Datei wieder importieren. Oder schnell eine SQL-Abfrage in phpMyAdmin absetzen.
Auf einer produktiven WordPress-Datenbank endet genau das mit einem sofortigen Ausfall. Widgets in Footer und Seitenleisten verschwinden, Farb- und Typografie-Einstellungen des Themes werden zurückgesetzt, erweiterte Felder (ACF) liefern leere Werte, und die Konfiguration von E-Commerce-Plugins ist plötzlich leer.
Der Grund liegt in der Art, wie WordPress und Plugins komplexe Datenstrukturen in der relationalen Datenbank MySQL und MariaDB ablegen. Die WordPress-Dokumentation warnt ausdrücklich: Ein einfaches Suchen und Ersetzen über die gesamte Datenbank kann die Serialisierung beschädigen, weil manche Themes und Widgets eine Adresse zusammen mit ihrer Länge speichern (Migrating WordPress, developer.wordpress.org). Wer die PHP-Serialisierung versteht und die richtigen Werkzeuge beherrscht, allen voran die Kommandozeile WP-CLI, hat die Grundlage für eine sichere Verwaltung von WordPress-Websites.
Was serialisierte Daten in der WordPress-Datenbank sind
Relationale SQL-Datenbanken sind für skalare Werte gebaut: Zahlen, kurze Zeichenketten, Datumswerte. WordPress muss aber oft eine komplexe, mehrdimensionale Struktur in einer einzigen Tabellenzeile speichern, zum Beispiel ein Array mit der Liste aktiver Widgets, ihrer Reihenfolge, zugeordneten Icons und Konfigurationsparametern.
Statt für jedes Plugin Dutzende normalisierte Zusatztabellen anzulegen, nutzt WordPress eine native PHP-Funktion: serialize().
// Beispiel: Konfigurations-Array eines Themes in PHP
$theme_settings = array(
'site_name' => 'Mein WordPress Shop',
'logo_url' => 'https://alte-domain.de/logo.png',
'contact_mail' => '[email protected]'
);
// Ergebnis von serialize($theme_settings)
// Wird direkt in der Spalte option_value der Tabelle wp_options gespeichert:
a:3:{s:9:"site_name";s:19:"Mein WordPress Shop";s:8:"logo_url";s:31:"https://alte-domain.de/logo.png";s:12:"contact_mail";s:20:"[email protected]";}Wie man einen serialisierten String liest
Sehen wir uns den Teil mit der Logo-Adresse genauer an:
s:31:"https://alte-domain.de/logo.png";Jedes Element im serialisierten PHP-Format hat eine feste Struktur:
ssteht für den Datentyp: string (Zeichenkette).31ist die deklarierte Länge der Zeichenkette (genaue Anzahl Bytes)."https://alte-domain.de/logo.png"ist der eigentliche Wert in Anführungszeichen.
Der entscheidende Teil ist die Zahl 31. Beim Lesen aus der Datenbank ruft PHP die Funktion unserialize() auf. Der Parser sucht das schließende Anführungszeichen nicht blind, sondern zählt genau 31 Bytes ab der angegebenen Stelle ab.
Warum SQL REPLACE serialisierte Daten beschädigt
Angenommen, die Website zieht auf eine neue, längere Domain um: https://neue-deutlich-laengere-firmendomain.de. Die neue Logo-Adresse https://neue-deutlich-laengere-firmendomain.de/logo.png ist 55 Zeichen lang.
Führen wir die klassische SQL-Abfrage aus:
-- KRITISCHER FEHLER: Diese Abfrage zerstört die Serialisierung!
UPDATE wp_options
SET option_value = REPLACE(option_value, 'https://alte-domain.de', 'https://neue-deutlich-laengere-firmendomain.de');In der Datenbank entsteht dann diese Zeichenkette:
s:31:"https://neue-deutlich-laengere-firmendomain.de/logo.png";Was passiert, wenn ein Besucher die Seite aufruft?
- WordPress holt die Zeile aus der Datenbank und übergibt sie an
unserialize(). - Die Funktion liest den Kopf
s:31und erwartet genau 31 Zeichen. - PHP schneidet die ersten 31 Zeichen der neuen Adresse ab und trifft mitten im String auf beliebige Buchstaben statt auf das erwartete schließende Anführungszeichen mit Semikolon.
- Der Parser meldet
PHP Notice: unserialize(): Error at offset...und gibtfalsezurück. - Theme oder Plugin erhalten statt des erwarteten Options-Arrays den Wert
false. - WordPress geht davon aus, dass keine Daten existieren, stellt die Standardeinstellungen des Themes wieder her oder entfernt die Widgets.
Wo WordPress URLs in der Datenbank speichert
URLs liegen in einer WordPress-Installation nicht an einer Stelle. Sie sind über viele Systemtabellen und über Tabellen externer Module verteilt:
graph TD
A["WordPress-Datenbank"] --> B["wp_options"]
A --> C["wp_posts"]
A --> D["wp_postmeta"]
A --> E["wp_comments / wp_commentmeta"]
A --> F["wp_usermeta"]
A --> G["Plugin-Tabellen (WooCommerce, Formulare, SEO)"]
B --> B1["siteurl und home (Hauptadressen)"]
B --> B2["sidebars_widgets (serialisiert)"]
B --> B3["theme_mods (serialisiert)"]
C --> C1["post_content (Links, Bilder)"]
C --> C2["post_excerpt"]
C --> C3["guid (bei veröffentlichten Beiträgen NICHT ändern!)"]
D --> D1["_elementor_data (JSON / escaped)"]
D --> D2["_wp_attached_file (Medienpfade)"]
D --> D3["ACF-Felder (serialisiert)"]1. Tabelle wp_options
Die wichtigste Konfigurationstabelle. Sie enthält zwei kritische Einträge, die über das Funktionieren der Website entscheiden:
siteurl: zeigt, wo die WordPress-Dateien physisch liegen (Pfad zum Core).home: die Hauptadresse der Website, die Besucher im Browser eingeben.
Daneben speichert die Tabelle in serialisierter Form:
sidebars_widgets: die Anordnung der Widgets in Seitenleisten und Footern.theme_mods_[themename]: Farben, Header-Layout, Typografie und Logo aus dem Customizer.- Einstellungen von SEO-Plugins (Rank Math, Yoast), Sicherheits- und Cache-Plugins.
2. Tabelle wp_posts
Speichert den Inhalt von Beiträgen, Seiten, WooCommerce-Produkten und Mediathek-Elementen.
- Spalte
post_content: enthält absolute Links auf andere Unterseiten, eingebetteteimg-Tags, Links auf PDF-Dateien und die Blockkommentare von Gutenberg. - Spalte
guid(Globally Unique Identifier): die eindeutige Kennung eines Beitrags. Wichtige Regel: Die WordPress-Dokumentation sagt: “Ändern Sie niemals, unter keinen Umständen, den Inhalt der GUID-Spalte” (Migrating WordPress, developer.wordpress.org, eigene Übersetzung). Die Spalteguiddarf nicht geändert werden, weil RSS-Reader sie nutzen, um neue Artikel zu erkennen. Eine Änderung führt dazu, dass Feedreader alle älteren Beiträge als neu behandeln und Abonnenten erneut benachrichtigen.
3. Tabelle wp_postmeta
Enthält zusätzliche Attribute von Beiträgen und Seiten. Hier landen die serialisierten Arrays der Felder aus Advanced Custom Fields (ACF), die Metadaten von Anhängen (_wp_attachment_metadata) und die Konfiguration von Page Buildern wie Elementor oder Divi.
4. Tabellen wp_usermeta und wp_comments
Enthalten die Website-Adressen von Kommentarautoren und Metadaten der Benutzerprofile.
Domain in WordPress mit WP-CLI search-replace ändern
Die WordPress-Kommandozeile (WP-CLI) ist das schnellste, zuverlässigste und vollständig automatisierbare Werkzeug für den URL-Umzug. Sie läuft per SSH direkt auf dem Server und arbeitet mit den PHP-Strukturen im Arbeitsspeicher.
Falls WP-CLI auf dem Server noch fehlt, beschreibt wp-cli.org die Installation über die Phar-Datei:
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
wp --infoSchritt 1: Backup erstellen
Bevor Sie irgendetwas an der Produktionsdatenbank ändern, erstellen Sie einen Dump als SQL-Datei:
# Datenbank-Dump mit DROP-TABLE-Anweisungen
wp db export backup-vor-migration-$(date +%Y%m%d_%H%M%S).sql --add-drop-tableGeht etwas schief, stellen Sie den ursprünglichen Zustand in Sekunden wieder her:
wp db import backup-vor-migration-*.sqlSchritt 2: Testlauf mit —dry-run
Mit dem Flag --dry-run sehen Sie, wie viele Zeilen in welchen Tabellen geändert würden, ohne dass sich an der Datenbank etwas ändert:
wp search-replace 'https://alte-domain.de' 'https://neue-domain.de' --all-tables --dry-runDas Ergebnis ist eine Tabelle mit den Spalten Table, Column, Replacements und Type sowie einer Zusammenfassung mit der Gesamtzahl der Ersetzungen. Die Spalte Type zeigt, ob eine Spalte in SQL oder in PHP verarbeitet wurde. Ist die Zahl der Ersetzungen null, unterscheidet sich die alte Adresse meist im Protokoll, im Präfix www oder im abschließenden Schrägstrich von dem, was in der Datenbank steht.
Schritt 3: Die eigentliche Ersetzung ausführen
Für die endgültige Ersetzung empfehlen wir diese Kombination von Flags:
wp search-replace 'https://alte-domain.de' 'https://neue-domain.de' \
--all-tables \
--precise \
--recurse-objects \
--skip-columns=guid \
--report-changed-onlyDie Parameter im Einzelnen:
--all-tables: durchsucht alle Tabellen der Datenbank, einschließlich eigener Tabellen von Shop-, Formular- und Log-Plugins.--precise: erzwingt PHP statt SQL für alle Spalten. Die WP-CLI-Dokumentation beschreibt das als langsamer, aber zuverlässiger bei komplexen serialisierten Daten.--recurse-objects: geht rekursiv in serialisierte Objekte. Das ist standardmäßig aktiv und lässt sich mit--no-recurse-objectsabschalten, die explizite Angabe dokumentiert also nur die Absicht.--skip-columns=guid: überspringt die Spalteguidinwp_postsund schützt RSS-Reader vor doppelten Einträgen.--report-changed-only: zeigt in der Zusammenfassung nur Tabellen, in denen tatsächlich etwas geändert wurde.
Für Groß- und Kleinschreibung gilt: wp search-replace unterscheidet sie. Eine Suche ohne Beachtung der Schreibweise geht nur mit --regex und --regex-flags='i', und laut Dokumentation ist der Regex-Modus deutlich langsamer.
Domain in einem WordPress-Multisite-Netzwerk ändern
In Multisite-Installationen (Netzwerk mehrerer Websites) haben die Systemtabellen eigene Präfixe (z. B. wp_2_posts, wp_3_options), und die Domains der einzelnen Unterseiten stehen in den Tabellen wp_blogs und wp_site.
Hier verwenden Sie das Flag --network, das alle in $wpdb registrierten Tabellen des ganzen Netzwerks erfasst, oder --all-tables-with-prefix, das zusätzlich Tabellen mit dem Präfix einbezieht, die nicht in $wpdb registriert sind:
wp search-replace 'https://altes-netz.de' 'https://neues-netz.de' --network --all-tables-with-prefixDie WordPress-Dokumentation räumt ein, dass sich dieser Schritt beim Domainwechsel eines Multisite-Netzwerks “noch nicht einfach automatisieren lässt” (Migrating WordPress, developer.wordpress.org, eigene Übersetzung). Prüfen Sie nach der Ersetzung von Hand:
- die Tabellen
wp_siteundwp_blogs, in denen Domain und Pfad des Netzwerks und jeder Unterseite gespeichert sind, - die Optionen
home,siteurlundfileupload_urlin der Optionstabelle jeder Website (wp_options,wp_2_optionsund so weiter), - beim Wechsel von Subdomains auf Unterverzeichnisse oder umgekehrt: die Datei
.htaccessund die KonstanteSUBDOMAIN_INSTALLinwp-config.php.
Datenbank mit neuen URLs als SQL-Datei exportieren
Wenn Sie eine Datenbankmigration für einen Kunden lokal vorbereiten und eine fertige SQL-Datei mit ersetzten Domains erzeugen möchten, ohne die lokale Arbeitsdatenbank anzufassen:
wp search-replace 'https://localhost/projekt' 'https://kundendomain.de' \
--all-tables \
--export=datenbank-bereit-zum-import.sqlVon www auf die Domain ohne www wechseln
Ändert sich nur das Präfix, ersetzen Sie die vollständige Adresse mit Protokoll, damit keine fremden Zeichenketten getroffen werden:
wp search-replace 'https://www.beispiel.de' 'https://beispiel.de' --all-tables --precise --skip-columns=guid --dry-runURLs mit dem Plugin Better Search Replace ändern
Wenn Sie eine Website auf Shared Hosting ohne SSH-Zugang betreuen oder lieber im WordPress-Dashboard arbeiten, ist das Plugin Better Search Replace von WP Engine (früher Delicious Brains) die sicherste Lösung.
Schritt für Schritt im WordPress-Dashboard:
1. Plugins > Plugin hinzufügen öffnen und nach "Better Search Replace" suchen.
2. Plugin installieren und aktivieren.
3. Werkzeuge > Better Search Replace öffnen.
4. Im Feld "Search for" die alte URL eintragen (z. B. https://alte-domain.de).
5. Im Feld "Replace with" die neue URL eintragen (z. B. https://neue-domain.de).
6. Alle Tabellen in der Liste markieren (Strg+A unter Windows, Cmd+A unter macOS).
7. Sicherstellen, dass "Run as dry run?" AKTIVIERT ist.
8. "Run Search/Replace" klicken und den Bericht prüfen.
9. "Run as dry run?" deaktivieren und den Vorgang erneut starten, um die Änderungen zu speichern.Fehler in Better Search Replace beheben
- Fehler 504 Gateway Timeout oder überschrittenes Skript-Zeitlimit (
max_execution_time): Bei großen Datenbanken kann der Webserver die HTTP-Anfrage abbrechen. Verringern Sie im Tab Settings des Plugins den Wert Max Page Size. Der Standardwert liegt bei 20000 Zeilen pro Durchgang, wie der Quellcode des Plugins zeigt (class-bsr-admin.php); ein kleinerer Wert bedeutet mehr, aber kürzere Anfragen.
siteurl und home in WordPress ändern
Zwei Optionen aus der Tabelle wp_options entscheiden, ob Sie sich unter der neuen Adresse überhaupt anmelden können. Die WordPress-Dokumentation (Changing The Site URL) unterscheidet sie so: home ist die “Website-Adresse (URL)”, also die Adresse, die Besucher im Browser eingeben, und siteurl ist die “WordPress-Adresse (URL)”, also der Ort, an dem die Core-Dateien liegen. Beide Felder unter Einstellungen > Allgemein sollten https:// enthalten und nicht mit einem Schrägstrich enden.
Die Dokumentation beschreibt mehrere Wege, diese Werte zu ändern. Jeder passt zu einer anderen Situation:
| Methode | Wann sinnvoll | Worauf achten |
|---|---|---|
wp option update in WP-CLI | SSH vorhanden, Dashboard funktioniert nicht | Ändert nur zwei Optionen, den Rest erledigt wp search-replace |
Konstanten WP_HOME und WP_SITEURL in wp-config.php | Website muss schnell wieder laufen | Werte sind fest eingetragen, die Felder unter Einstellungen > Allgemein lassen sich nicht bearbeiten |
update_option() in der functions.php des Themes | Nur FTP-Zugang | Code direkt nach dem ersten Laden des Dashboards entfernen |
Konstante RELOCATE | Website in ein anderes Verzeichnis oder auf einen anderen Server verschoben | Korrigiert nur die Adressen des Admin-Bereichs und ist unsicher, wenn sie in der Datei bleibt |
wp_options in phpMyAdmin bearbeiten | Nur Zugang zum Hosting-Panel | Zuerst Backup; das Tabellenpräfix muss nicht wp_ sein |
siteurl und home mit WP-CLI ändern
Die Dokumentation nennt zwei Befehle und danach die Ersetzung der Adressen im Inhalt unter Auslassung der Spalte guid:
wp option update home 'https://neue-domain.de'
wp option update siteurl 'https://neue-domain.de'
wp search-replace 'https://alte-domain.de' 'https://neue-domain.de' --skip-columns=guidAdresse über functions.php ändern
Wenn Sie nur per FTP zugreifen können, empfiehlt die Dokumentation, in der functions.php des aktiven Themes direkt nach dem öffnenden <?php zwei Zeilen einzufügen:
update_option( 'siteurl', 'https://neue-domain.de' );
update_option( 'home', 'https://neue-domain.de' );Laden Sie nach dem Hochladen der Datei den Login-Bildschirm oder das Dashboard einige Male und entfernen Sie die Zeilen dann wieder. Die Dokumentation schreibt unmissverständlich: “Lassen Sie diesen Code nicht in der Datei functions.php” (Migrating WordPress, developer.wordpress.org, eigene Übersetzung). Der Code würde bei jeder Anfrage laufen und Optionen überschreiben, die Sie später im Dashboard ändern möchten.
Konstante RELOCATE nach dem Verschieben des Verzeichnisses
Die Konstante define( 'RELOCATE', true );, in wp-config.php vor dem Kommentar That's all, stop editing! eingetragen, sorgt dafür, dass WordPress nach dem Login über wp-login.php auf dem neuen Server die aktuelle Adresse übernimmt. Laut Dokumentation korrigiert sie nur die Adressen des Admin-Bereichs, nicht den Rest der Konfiguration, und es ist unsicher, sie stehen zu lassen: “Entfernen Sie die RELOCATE-Zeile immer aus wp-config.php, wenn Sie fertig sind” (Migrating WordPress, developer.wordpress.org, eigene Übersetzung).
Transients in der umgezogenen Datenbank
Die Dokumentation weist auf Transients hin, also temporäre Werte in wp_options. Sie können alte Adressen enthalten, und weil WordPress sie selbst neu erzeugt, lassen sie sich in der umgezogenen Kopie der Datenbank gefahrlos löschen. Mit WP-CLI erledigt das wp transient delete --all, die Dokumentation nennt außerdem eine Abfrage für phpMyAdmin, ebenfalls erst nach einem Backup:
DELETE FROM `wp_options` WHERE `option_name` LIKE '%\_transient\_%';URLs ändern, wenn das WordPress-Dashboard nicht funktioniert
Für Notfälle, wenn kein SSH-Zugang besteht und das Dashboard wegen einer Weiterleitungsschleife oder beschädigter Dateien nicht lädt, ist seit über einem Jahrzehnt das Skript Search-Replace-DB (kurz SRDB) der Agentur Interconnect/it bewährt.
Vorgehen mit dem SRDB-Skript:
1. Das offizielle ZIP-Archiv von interconnectit.com herunterladen.
2. Dateien entpacken und den Ordner in eine eindeutige, schwer zu erratende Zeichenkette umbenennen (z. B. srdb-sec-8f7a9d/).
3. Den Ordner per FTP / SFTP in das Hauptverzeichnis der WordPress-Installation hochladen (dorthin, wo wp-config.php liegt).
4. Im Browser die Adresse https://ihre-domain.de/srdb-sec-8f7a9d/ öffnen.
5. Das Skript liest die Datenbank-Zugangsdaten automatisch aus wp-config.php.
6. Die Felder "replace" (alter Wert) und "with" (neuer Wert) ausfüllen.
7. "dry run" klicken und nach der Prüfung "live run".
8. KRITISCH: Nach Abschluss den roten Button "delete me" klicken, damit sich das Skript vom Server löscht.[!CAUTION] Ein auf einem laufenden Server zurückgelassenes
Search-Replace-DBist eine kritische Sicherheitslücke. Wer den Pfad errät, kann die Datenbank ohne Passwort lesen und verändern. Prüfen Sie nach der Arbeit immer, ob der Ordner wirklich gelöscht ist!
URLs in Elementor, Divi und Gutenberg ändern
Moderne Page Builder und der Blockeditor Gutenberg bringen zusätzliche Kodierungsebenen mit, an die Sie beim Aktualisieren der URLs denken müssen.
graph LR
subgraph WP_CLI_Execution["Schritt 1: Datenbank"]
A["wp search-replace"] --> B["Tabellen wp_posts, wp_postmeta, wp_options"]
end
subgraph Builder_Sync["Schritt 2: Page Builder"]
B --> C["Elementor: Tools > Replace URL"]
B --> D["Elementor: CSS-Dateien neu erzeugen"]
end
subgraph Edge_Purge["Schritt 3: Cache und Edge"]
C & D --> F["wp cache flush (Redis/Memcached)"]
F --> G["CDN leeren (Cloudflare)"]
end1. URLs in den JSON-Daten von Elementor
Elementor speichert das Seitenlayout im Metafeld _elementor_data als JSON, in dem die Schrägstriche in URLs oft maskiert sind (escaped slashes):
{\"url\":\"https:\/\/alte-domain.de\/wp-content\/uploads\/2026\/08\/banner.jpg\"}Eine normale Suche nach https://alte-domain.de findet die maskierte Form https:\/\/alte-domain.de unter Umständen nicht. Außerdem kompiliert Elementor Stilregeln in statische CSS-Dateien im Verzeichnis wp-content/uploads/elementor/css/.
Richtiges Vorgehen nach dem Umzug einer Elementor-Website:
- Führen Sie das normale
wp search-replacein der Datenbank aus. - Melden Sie sich im WordPress-Dashboard an und öffnen Sie Elementor > Tools > Replace URL.
- Tragen Sie alte und neue URL ein und klicken Sie auf Replace URL.
- Klicken Sie im Tab General auf Regenerate Files & Data.
2. URLs in Gutenberg-Blöcken
Gutenberg-Blöcke speichern Medienattribute direkt in HTML-Kommentaren innerhalb von post_content:
<!-- wp:image {"id":412,"sizeSlug":"full","linkDestination":"custom"} -->
<figure class="wp-block-image size-full"><a href="https://alte-domain.de/angebot/"><img src="https://alte-domain.de/wp-content/uploads/2026/08/grafik.png" alt="Angebot"/></a></figure>
<!-- /wp:image -->Sowohl wp search-replace als auch Better Search Replace kommen damit problemlos zurecht, solange die Spalte post_content der Tabelle wp_posts durchsucht wird.
3. Fest eingetragene URLs in Theme-Dateien
Manche Themes und Plugins enthalten Adressen direkt in PHP-, CSS- oder JavaScript-Dateien. Diese erreicht keine Datenbank-Ersetzung, sie lassen sich aber auf dem Server finden:
grep -rn "alte-domain.de" wp-content/themes/ihr-theme/Domainwechsel in einem WooCommerce-Shop
Beim Domainwechsel eines WooCommerce-Shops verdienen die Module besondere Aufmerksamkeit, die mit externen Zahlungs-, Versand- und ERP-Systemen kommunizieren:
- Payment-Gateways:
- Die meisten Zahlungsanbieter hinterlegen in ihrem Entwicklerbereich Adressen für Rückmeldungen (Webhooks / IPN). Wechseln Sie von
alt.deaufneu.de, landen Meldungen über bezahlte Bestellungen weiter auf der alten Adresse und erzeugen Transaktionsfehler. - Nach
wp search-replacemüssen Sie sich bei jedem Zahlungsanbieter anmelden und die Webhook-Adresse aktualisieren.
- Die meisten Zahlungsanbieter hinterlegen in ihrem Entwicklerbereich Adressen für Rückmeldungen (Webhooks / IPN). Wechseln Sie von
- Schlüssel und Webhooks der WooCommerce REST API:
- Prüfen Sie unter WooCommerce > Settings > Advanced > Webhooks, ob die Zieladressen (Delivery URL) aktualisiert wurden. Synchronisieren Webhooks Lagerbestände mit einem ERP-System, aktualisieren Sie die Endpunkte auch in der Integrationssoftware.
- Sitzungen und Warenkörbe der Kunden:
- Die Tabelle
wp_woocommerce_sessionsenthält temporäre Warenkorbdaten. Nach dem Domainwechsel lohnt es sich, unter WooCommerce > Status > Tools die FunktionClear customer sessionsauszuführen, um Fehler mit Sitzungstokens nach dem Wechsel der Domain-Cookies zu vermeiden.
- Die Tabelle
Search-replace auf einer großen Datenbank und einem MySQL-Cluster
Bei sehr großen Datenbanken dauert ein einzelner Durchlauf von wp search-replace über alle Tabellen lange und schreibt die ganze Zeit in Tabellen, die die laufende Website nutzt. Die WP-CLI-Dokumentation nennt zwei wichtige Einschränkungen: Tabellen ohne Primärschlüssel werden übersprungen, und die Optionen --regex und --log verlangsamen die Arbeit deutlich.
1. Search-replace in kleinere Teile aufteilen
Der Befehl wp search-replace hat weder --batch-size noch --limit; die Optionsliste in der WP-CLI-Dokumentation enthält sie nicht, und Anleitungen, die sie nennen, funktionieren nicht. Die Arbeit wird anders aufgeteilt: indem man Tabellennamen als Argumente übergibt (Platzhalter sind erlaubt) oder Tabellen mit --skip-tables ausschließt:
# Erst Inhalte, dann Metadaten, in getrennten Durchläufen
wp search-replace 'https://alt.de' 'https://neu.de' wp_posts --precise --skip-columns=guid
wp search-replace 'https://alt.de' 'https://neu.de' wp_postmeta --precise
# Alles außer einer großen Log-Tabelle eines Plugins
wp search-replace 'https://alt.de' 'https://neu.de' --all-tables --skip-tables='wp_*_log' --precise --skip-columns=guidDie Option --include-columns beschränkt die Ersetzung auf bestimmte Spalten, und bei --export legt --export_insert_size fest, wie viele Zeilen in einer INSERT-Anweisung stehen (Standard 50).
2. Search-replace bei Replikation (Amazon Aurora, MySQL Galera)
Läuft die Datenbank in einer Master-Slave-Architektur oder einem Galera-Cluster, erzeugt das massenhafte Ändern von Datensätzen einen großen Datenstrom im Binärlog (binlog). Das kann zu deutlicher Replikationsverzögerung (Replication Lag) auf den Leseknoten führen.
Empfohlene Strategie für Hochverfügbarkeitsumgebungen:
- Den Vorgang in einem Wartungsfenster mit möglichst wenig Traffic ausführen.
- Replikationsknoten für die Dauer des Massenschreibens vorübergehend abkoppeln.
- Mit
--exporteine verarbeitete SQL-Datei auf einer separaten Arbeitsmaschine erzeugen und im Wartungsfenster importieren.
3. Wartungsmodus während der Migration
WP-CLI kann den Wartungsmodus von WordPress direkt steuern, sodass Besucher während der Ersetzung keine halb umgestellte Website sehen:
wp maintenance-mode activate
wp search-replace 'https://alt.de' 'https://neu.de' --all-tables --precise --skip-columns=guid
wp maintenance-mode deactivateVon HTTP auf HTTPS wechseln und Webserver konfigurieren
Wenn Sie nicht die Domain ändern, sondern ein SSL-Zertifikat einführen und vom unverschlüsselten auf das verschlüsselte Protokoll wechseln:
wp search-replace 'http://ihredomain.de' 'https://ihredomain.de' \
--all-tables \
--precise \
--skip-columns=guidErsetzen Sie dabei immer die vollständige Adresse Ihrer eigenen Domain und nie nur http://, sonst ändern Sie auch Links auf fremde Websites, die gar kein HTTPS anbieten. So beseitigen Sie das Problem Mixed Content (gemischte Inhalte), bei dem der Browser Skripte, Schriften oder Bilder blockiert, die noch über das alte http:// ausgeliefert werden.
301-Weiterleitungen auf Server-Ebene in Nginx und Apache
Nach dem Domainwechsel in der Datenbank ist aus SEO-Sicht die Weiterleitung des gesamten Traffics von der alten auf die neue Adresse mit HTTP-Statuscode 301 (Moved Permanently) entscheidend.
Nginx-Konfiguration (/etc/nginx/sites-available/alte-domain.conf):
server {
listen 80;
listen 443 ssl http2;
server_name alte-domain.de www.alte-domain.de;
ssl_certificate /etc/letsencrypt/live/alte-domain.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/alte-domain.de/privkey.pem;
return 301 https://neue-domain.de$request_uri;
}Apache-Konfiguration (.htaccess auf dem alten Server):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(?:www\.)?alte-domain\.de$ [NC]
RewriteRule ^(.*)$ https://neue-domain.de/$1 [L,R=301]
</IfModule>Ob die Weiterleitung greift, zeigt der Statuscode der alten Adresse:
curl -s -o /dev/null -w "%{http_code}\n" https://alte-domain.de/Konstanten in wp-config.php und Werte in der Datenbank
Im Notfall werden URLs oft in wp-config.php erzwungen:
define('WP_HOME', 'https://neue-domain.de');
define('WP_SITEURL', 'https://neue-domain.de');So wirken diese Konstanten in der Praxis:
- In
wp-config.phpdefinierte Konstanten überschreiben die von WordPress gelesenen Wertesiteurlundhome, ändern aber nicht die Einträge in der Datenbank. Die Dokumentation nennt das ausdrücklich ein festes Eintragen der Werte und betont, dass es nicht unbedingt die beste Lösung ist. - Die Adressfelder unter Einstellungen > Allgemein lassen sich dann nicht bearbeiten.
- Links in Beitragsinhalten, Anhängen und Widgets zeigen weiterhin auf die alte Adresse.
- Betrachten Sie die Konstanten in
wp-config.phpals Übergangslösung; dauerhaft sollte die Datenbank immer mitwp search-replaceaktualisiert werden.
Checkliste für den Domainwechsel in WordPress
Arbeiten Sie vor dem Start nach einem festen Plan:
| Phase | Aufgabe | Werkzeug / Befehl |
|---|---|---|
| Vor der Migration | Vollständiger Datenbank-Dump | wp db export backup-$(date +%s).sql --add-drop-table |
| Vor der Migration | Kopie von wp-content/uploads und .htaccess | rsync / tar -czf uploads.tar.gz |
| Vor der Migration | Cache- und Minify-Plugins deaktivieren | Dashboard / wp plugin deactivate |
| Während | Testlauf der Ersetzungsparameter | wp search-replace 'old' 'new' --all-tables --dry-run |
| Während | Eigentliche Ersetzung in der Datenbank | wp search-replace 'old' 'new' --all-tables --precise --skip-columns=guid |
| Während | Domains in Page Buildern ersetzen (Elementor) | Dashboard > Elementor > Tools > Replace URL |
| Nach der Migration | Object Cache und Transients leeren | wp cache flush und wp transient delete --all |
| Nach der Migration | Permalinks neu schreiben | wp rewrite flush --hard |
Bash-Skript zum Synchronisieren der WordPress-Datenbank zwischen Umgebungen
In modernen Workflows mit Docker-Containern oder Staging-Umgebungen (DDEV, Lando, LocalWP) ist das manuelle Eintippen von Befehlen zeitaufwendig und fehleranfällig. In Entwicklerteams ist ein Bash-Skript üblich, das die Produktionsdatenbank holt, lokal importiert und die Domains ersetzt.
#!/usr/bin/env bash
# Skript zur automatischen Datenbank-Synchronisierung: sync-db.sh
set -eo pipefail
PROD_HOST="ihr-produktionsserver.de"
PROD_USER="deploy"
PROD_PATH="/var/www/html"
PROD_URL="https://ihrefirma.de"
LOCAL_URL="https://projekt.local"
BACKUP_DIR="./backups"
mkdir -p "${BACKUP_DIR}"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
DUMP_FILE="${BACKUP_DIR}/dump_prod_${TIMESTAMP}.sql"
echo "==> 1/4 Produktionsdatenbank per SSH holen..."
ssh "${PROD_USER}@${PROD_HOST}" "cd ${PROD_PATH} && wp db export - --add-drop-table" > "${DUMP_FILE}"
echo "==> 2/4 Datenbank in die lokale Umgebung importieren..."
wp db import "${DUMP_FILE}"
echo "==> 3/4 Domains sicher und serialisierungsfest ersetzen..."
wp search-replace "${PROD_URL}" "${LOCAL_URL}" \
--all-tables \
--precise \
--recurse-objects \
--skip-columns=guid \
--report-changed-only
echo "==> 4/4 Cache leeren und Permalinks neu schreiben..."
wp cache flush
wp rewrite flush --hard
echo "==> Fertig! Die lokale Umgebung ist unter ${LOCAL_URL} synchronisiert."Serialisierung nach der Arbeit prüfen
Wenn Sie sicher sein wollen, dass während der Migration kein Feld beschädigt wurde, prüft dieses kurze PHP-Skript in WP-CLI alle serialisierten Einträge der Tabelle wp_options:
wp eval '
global $wpdb;
$options = $wpdb->get_results("SELECT option_name, option_value FROM {$wpdb->options} WHERE option_value LIKE \"a:%\" OR option_value LIKE \"O:%\"");
$broken = 0;
foreach ($options as $opt) {
if (is_serialized($opt->option_value) && @unserialize($opt->option_value) === false) {
echo "Beschaedigte Option: " . $opt->option_name . PHP_EOL;
$broken++;
}
}
if ($broken === 0) {
echo "Alle serialisierten Optionen in wp_options sind korrekt." . PHP_EOL;
} else {
echo $broken . " beschaedigte Eintraege gefunden!" . PHP_EOL;
}
'Ob noch alte Adressen übrig sind, zeigt ein Testlauf mit der alten Domain: Meldet wp search-replace 'alte-domain.de' 'neue-domain.de' --all-tables --dry-run null Ersetzungen, ist die Datenbank sauber.
Fehler nach dem Domainwechsel in WordPress beheben
1. Weiterleitungsschleife nach dem Domainwechsel (ERR_TOO_MANY_REDIRECTS)
Wenn die Website nach dem Domainwechsel in einer endlosen Weiterleitungsschleife hängt:
- Prüfen Sie, ob
siteurlundhomeinwp_optionsgenau dasselbe Protokoll (https://) und Präfix (wwwoder ohne) haben wie auf dem Webserver oder in Cloudflare konfiguriert. - Prüfen Sie die SSL-Konfiguration in Cloudflare (der SSL/TLS-Modus sollte Full (Strict) sein, nicht Flexible).
- Setzen Sie die Datei
.htaccessmit diesem Befehl auf die WordPress-Standardform zurück:wp rewrite flush --hard
2. CSS-Stile und Icons fehlen nach der Migration
- Lädt die Website als roher Text ohne Stile, sind die häufigsten Ursachen Stylesheets und Skripte, die noch auf die alte Adresse zeigen, gemischte Inhalte (Mixed Content) beim Wechsel auf HTTPS oder eine Blockade durch die CORS-Richtlinie.
- Öffnen Sie die Entwicklerkonsole des Browsers (F12 > Tab Console), um Dateien zu finden, die noch über das alte
http://geladen werden.
3. Beschädigte Widgets oder ACF-Felder
- Wurden die Regeln der Serialisierung ignoriert und ein rohes SQL
REPLACEausgeführt, ist der einzige sichere Weg, die Datenbank aus dem vorher erstellten Dump wiederherzustellen (wp db import backup.sql) und den Vorgang mitwp search-replace --precisezu wiederholen.
4. Fehler Allowed memory size exhausted in WP-CLI
Bei search-replace auf Tabellen mit sehr vielen Textdaten (etwa umfangreiche Log-Tabellen oder Beitragsrevisionen) kann der PHP-Prozess im Terminal sein Speicherlimit ausschöpfen:
- Um das Speicherlimit für einen einzelnen WP-CLI-Befehl vorübergehend zu erhöhen, starten Sie ihn mit einer PHP-Einstellung:
php -d memory_limit=1024M /usr/local/bin/wp search-replace 'https://alt.de' 'https://neu.de' --all-tables - Löschen Sie vor der Migration außerdem überflüssige Revisionen und abgelaufene Transients:
wp transient delete --all && wp post delete $(wp post list --post_type='revision' --format=ids) --force
5. Abweichende Zeichensätze und Kollation (Collation)
Wenn Sie einen Datenbank-Dump auf einen älteren oder anderen Datenbankserver übertragen, kennt der Zielserver die im Dump verwendete Kollation unter Umständen nicht, zum Beispiel utf8mb4_unicode_520_ci:
- Erscheint beim Import der
.sql-Datei der Fehler#1273 - Unknown collation: 'utf8mb4_unicode_520_ci', ersetzen Sie die Zeichenkette vor dem Import in der SQL-Datei:sed -i 's/utf8mb4_unicode_520_ci/utf8mb4_unicode_ci/g' backup.sql - Beide Kollationen speichern
utf8mb4, Umlaute und ß bleiben also erhalten; es ändert sich nur die Regel für Sortieren und Vergleichen von Text.
Zusammenfassung
Die korrekte Aktualisierung von URLs in der WordPress-Datenbank setzt Verständnis dafür voraus, wie PHP und relationale Datenbanken arbeiten. Rohe SQL-Abfragen oder das Bearbeiten von Dumps im Texteditor sind der kürzeste Weg zu einer instabilen Website und verlorenen Einstellungen.
WP-CLI mit den Flags --all-tables --precise --skip-columns=guid, vorher abgesichert durch ein Backup und einen Durchlauf mit --dry-run, lässt serialisierte Daten und die Spalte guid unversehrt.
Planen Sie eine umfassende Modernisierung, eine Headless-Architektur oder den Umstieg auf eine Plattform der nächsten Generation? Sehen Sie sich unsere Leistungen zur Migration von WordPress zu Astro und Next.js und das Core-Web-Vitals-Audit an.







