12k
All articles

WP-CLI für alle, die im Terminal leben

WP-CLI-Befehle für WordPress-Migrationen, Backups, Sperren, Plugin- und Core-Updates, Remote-SSH-Aufgaben und sicheres Search-Replace.

OpenReplay Team
OpenReplay Team
WP-CLI für alle, die im Terminal leben

WP-CLI ist die Kommandozeilen-Schnittstelle zu einer WordPress-Installation. Sie spart Klicks, aber der eigentliche Grund, sie zu lernen, sind jene Aufgaben, für die das Dashboard schlicht keinen Bildschirm vorsieht: das Umschreiben serialisierter Options-Daten bei einem Domainwechsel, das Ausführen beliebigen PHP-Codes gegen eine Live-Site und das Aktualisieren von zehn Installationen aus einem einzigen Prompt heraus.

Die meisten lernen WP-CLI im Notfall kennen. Ein Plugin-Update legt den Admin-Bereich lahm, das Dashboard lädt nicht mehr, und plötzlich sind FTP plus phpMyAdmin der einzige Weg zurück. Dieser Weg funktioniert, aber er ist langsam und erfordert gute Nerven.

Dieser Artikel ist nach Aufgaben gegliedert, nicht nach Namespaces. Jeder Abschnitt beschreibt eine Aufgabe, die im Dashboard mühsam oder unmöglich ist, gefolgt von dem Befehl, der sie erledigt, und den Flags, die sie sicher machen.

Die wichtigsten Erkenntnisse

  • wp search-replace deserialisiert PHP-Daten, wendet die Ersetzung an und serialisiert sie erneut. Genau deshalb kann der Befehl Widget-Einstellungen und Plugin-Optionen umschreiben, die ein reines SQL-REPLACE() beschädigen würde.
  • Führe jede Ersetzung zuerst mit --dry-run aus und danach denselben Befehl ohne das Flag.
  • Schließe die Spalte guid mit --skip-columns=guid aus, denn Feed-Reader nutzen die guid eines Beitrags, um festzustellen, ob sie ihn bereits angezeigt haben.
  • --ssh=[<scheme>:][<user>@]<host>[:<port>][<path>] leitet einen Befehl an eine entfernte Installation weiter; die entfernte Maschine benötigt dafür eine eigene WP-CLI-Installation, die auf wp hört.
  • Keiner dieser Befehle fragt nach einer Bestätigung und keiner lässt sich rückgängig machen – deshalb steht wp db export am Anfang.

Diese Befehle werden sofort ausgeführt

Es gibt keinen Bestätigungsdialog, keine Vorschau und kein Undo. wp search-replace schreibt in jede passende Zeile, sobald du Return drückst. wp plugin deactivate --all deaktiviert auf einer Produktivsite genauso bereitwillig alles wie auf einem Laptop. Dein einziges Rollback ist der Datenbank-Export, den du vorher angelegt hast – also lege einen an.

Wie wechselt man die Domain, ohne serialisierte Daten zu zerstören?

wp search-replace ist das richtige Werkzeug für einen Domainwechsel: Der Befehl liest serialisiertes PHP korrekt und lässt Primärschlüssel unangetastet – beides schafft ein einfaches SQL-Suchen-und-Ersetzen nicht. Der Grund liegt im Speicherformat: PHPs serialize() speichert einen String als dessen Bytelänge, gefolgt vom String selbst.

a:1:{s:3:"url";s:27:"https://staging.example.com";}

Ein blindes SQL-UPDATE ... REPLACE() schreibt die URL auf https://example.com um und lässt die 27 unverändert. Die deklarierte Länge passt nicht mehr zum Inhalt, PHP kann den Wert nicht mehr deserialisieren, und das Widget bzw. die Plugin-Option, die darin steckte, fällt stillschweigend auf nichts zurück. WP-CLI deserialisiert die Struktur, ersetzt innerhalb davon und serialisiert wieder mit korrekten Längenangaben.

Geh in drei Stufen vor:

# 1. report what would change; writes nothing
wp search-replace 'https://staging.example.com' 'https://example.com' \
  --skip-columns=guid --dry-run

# 2. optional: write the result to a SQL file instead of the database
wp search-replace 'https://staging.example.com' 'https://example.com' \
  --skip-columns=guid --export=migration.sql

# 3. apply it
wp search-replace 'https://staging.example.com' 'https://example.com' \
  --skip-columns=guid

--dry-run führt den kompletten Durchlauf aus und gibt den Bericht aus, verwirft die Änderungen aber anschließend. --export schreibt das Ergebnis in eine SQL-Datei und lässt die Live-Datenbank unberührt, sodass du das Diff lesen oder es anderswo einspielen kannst. Überspringe die Spalte guid, denn WordPress behandelt die guid eines Beitrags als über dessen gesamte Lebensdauer unveränderlich: Änderst du sie, zeigen Feed-Reader womöglich dein komplettes Archiv als neu an.

Bei sperrigen verschachtelten Daten hilft --precise. Standardmäßig nutzt der Befehl schnelle SQL-Abfragen und schaltet bei Spalten mit serialisierten Daten automatisch auf PHP um; --precise erzwingt PHP für jede Spalte – langsamer, aber zuverlässiger bei komplexen serialisierten Strukturen. Auch der Regex-Modus ist deutlich langsamer, greife also nur dann darauf zurück, wenn ein literaler String nicht ausreicht.

Wie aktualisiert man Plugins und Core über mehrere Sites hinweg?

Ein einziger Befehl aktualisiert alles, wofür ein Update verfügbar ist – ohne Dashboard-Paginierung und ohne Checkbox pro Plugin:

wp plugin update --all
wp core update
wp core update-db

wp core update-db führt die Datenbank-Update-Routine von WordPress aus – also den Schritt, den das Dashboard nach einem Core-Update auf dem Upgrade-Bildschirm für dich übernimmt. Führe ihn nach wp core update aus, damit das Upgrade vollständig abgeschlossen wird und nicht auf halbem Weg stehen bleibt.

In Kombination mit den weiter unten beschriebenen Aliassen wird aus derselben Zeile wp @all plugin update --all, und der Befehl läuft nacheinander gegen jede Installation, die du betreust.

Vorher exportieren, nachher importieren

wp db export ruft mysqldump auf und holt sich Datenbank-Host, -Name, -Benutzer und -Passwort aus der wp-config.php, sodass du nie Verbindungsdaten eintippen musst. Gib einen expliziten Dateinamen an; lässt du ihn weg, schreibt der Befehl {dbname}-{Y-m-d}-{random-hash}.sql.

wp db export backup-$(date +%Y%m%d-%H%M%S).sql

Das Wiederherstellen ist das Spiegelbild:

wp db import backup-20250413-141055.sql

wp db import akzeptiert entweder einen Dateinamen oder Eingaben per Pipe, sodass du einen Export direkt von einem Host über ssh zu einem anderen schicken kannst. Für eine längerfristige Strategie als einen einzelnen Dump vor einer riskanten Änderung behandeln die WordPress-Backup-Artikel von OpenReplay Zeitplanung und externe Speicherung.

Wie kommt man wieder in eine Site hinein, aus der man ausgesperrt ist?

Drei Befehle decken nahezu jede Aussperrung ab – in der Reihenfolge, in der du sie unter Druck ausführen würdest. Lege einen frischen Administrator an, setze das Passwort eines bestehenden Benutzers zurück oder nimm die Plugins komplett aus dem Spiel:

wp user create ops ops@example.com --role=administrator
wp user reset-password admin --show-password --skip-email
wp plugin deactivate --all

wp user reset-password erzeugt ein neues Passwort; --show-password gibt es im Terminal aus, und --skip-email verhindert, dass die Benachrichtigung in einem Postfach landet, über das du vielleicht keine Kontrolle hast. wp plugin deactivate akzeptiert --all, um alles zu deaktivieren, sowie --exclude=<name>, um eine kommagetrennte Liste aktiv zu lassen.

Wenn ein fataler Fehler in einem Plugin den Admin-Bereich lahmgelegt hat, kann WP-CLI aus demselben Grund beim Bootstrap scheitern wie die Site selbst. Der globale Parameter --skip-plugins verhindert für die Dauer des Befehls, dass alle Plugins – oder eine benannte Liste – geladen werden:

wp plugin deactivate broken-plugin --skip-plugins

Das Überspringen verändert den gespeicherten Zustand nicht; ein auf diese Weise übersprungenes Plugin meldet sich weiterhin als aktiv. Es verschafft dir lediglich einen funktionierenden Bootstrap, damit die Deaktivierung durchlaufen kann. Es hilft außerdem nicht, wenn der fatale Code in einem mu-plugin steckt, denn mu-plugins lädt WP-CLI in jedem Fall. Das ist der Moment, in dem die meisten Maintainer WP-CLI zum ersten Mal wirklich brauchen – und es geht schneller, als einen FTP-Client zu öffnen und Plugin-Verzeichnisse umzubenennen. Sobald der Admin-Bereich wieder läuft, deckt der OpenReplay-Artikel zum White Screen of Death bei WordPress die diagnostische Hälfte der Aufgabe ab.

Einmaliges PHP mit wp eval ausführen

wp eval führt beliebigen PHP-Code gegen eine vollständig geladene WordPress-Installation aus. Es gibt kein Dashboard-Äquivalent, und genau das ist der Punkt: Jede Funktion, die ein Plugin registriert, jede Option, jede Query wird zum Einzeiler.

wp eval 'echo get_option( "siteurl" );'
wp eval 'echo count( get_users( [ "role" => "administrator" ] ) );'

Alles Längere gehört in eine Datei. wp eval-file nimmt den Pfad zu einer PHP-Datei entgegen, übergibt alle zusätzlichen Positionsargumente als $args an das Skript und überspringt den WordPress-Bootstrap vollständig, wenn du --skip-wordpress angibst. Dein Code läuft innerhalb einer Methode, jede globale Variable, die du anfasst, braucht also eine eigene global-Zeile.

Für wp eval gibt es keinen Trockenlauf. Was das Skript schreibt, das schreibt es. Das ist das deutlichste Argument für den Export.

Wie führt man WP-CLI gegen einen entfernten Host aus?

Hier hört das Werkzeug auf, bloß bequem zu sein. WP-CLIs globaler Parameter --ssh hat die Form --ssh=[<scheme>:][<user>@]<host>[:<port>][<path>] und funktioniert, indem er deinen Befehl an die ssh-Binary übergibt, die ihn wiederum an das WP-CLI auf der Gegenseite weiterreicht.

wp --ssh=dev_user@example.com:2222~/webapps/production plugin list
KomponenteWert hierStandard, wenn weggelassen
scheme(weggelassen)ssh
userdev_userdein aktueller Systembenutzer
hostexample.comerforderlich
port222222
path~/webapps/productiondas Home-Verzeichnis des ssh-Benutzers

Der Pfad kommt ohne Trennzeichen aus. Schreibe ihn direkt hinter den Port, oder direkt hinter den Host, wenn du den Port weggelassen hast, und beginne ihn mit / oder ~. Neben ssh dokumentiert die Config-Referenz des Handbooks die Schemata vagrant, docker, docker-compose und docker-compose-run. Letzteres startet mit docker-compose run einen frischen Container, statt einen bereits laufenden zu verwenden.

Eine Voraussetzung ist absolut: Der entfernte Server braucht sein eigenes WP-CLI, und es muss auf wp hören. Ein wp, das funktioniert, wenn du dich manuell einloggst, kann über --ssh trotzdem als command-not-found zurückkommen, weil die Shell, die einen entfernten Befehl ausführt, nicht denselben $PATH aufbaut. Die meisten Distributionen setzen nahe an den Anfang der ~/.bashrc eine Abfrage, die früh aussteigt, wenn die Shell nicht interaktiv ist – jede PATH-Zeile darunter wird also nie ausgeführt; zsh liest in dieser Situation ~/.zshenv statt ~/.zshrc. Die Lösung besteht darin, $PATH auf der Gegenseite explizit zu setzen.

Diese Zeichenkette zweimal zu tippen, reicht schon. Registriere Aliasse in der wp-cli.yml deines Projekts oder in deiner globalen ~/.wp-cli/config.yml:

@prod:
  ssh: deploy@example.com~/webapps/production
@stage:
  ssh: deploy@staging.example.com~/webapps/staging
@all:
  - @prod
  - @stage
wp @prod plugin update --all
wp @all core check-update

Eine Alias-Gruppe führt einen einzigen Aufruf gegen mehrere Installationen aus – das ist der Unterschied zwischen der Betreuung von zehn Kunden-Sites und dem Einloggen in zehn Dashboards. Für eine lokale Installation, die nicht in deinem aktuellen Verzeichnis liegt, teilt der globale Parameter --path WP-CLI mit, wo die WordPress-Dateien liegen:

wp --path=/var/www/example.com/htdocs plugin update --all

Wie geht es weiter?

Die eine Erkenntnis, die es wert ist, mitgenommen zu werden: WP-CLI versteht die Datenstrukturen von WordPress, mysql und phpMyAdmin tun das nicht – und genau deshalb gehört ein Domainwechsel in wp search-replace und nirgendwo sonst hin. Nimm dir die nächste Migration vor, die bei dir ansteht, schreibe die --dry-run-Zeile, lies den Bericht und führe wp db export aus, bevor du das Flag weglässt. Alles oben Beschriebene ist in dem Moment unumkehrbar, in dem du Return drückst.

FAQs

Aktualisiert wp search-replace jede Site in einem Multisite-Netzwerk?

Nein. Der Befehl arbeitet auf den Tabellen, die WordPress selbst registriert. Im Multisite-Betrieb erhältst du also nur die Tabellen der aktuellen Site, sofern du nicht --network ergänzt. Um jede Tabelle in der Datenbank zu erreichen – unabhängig vom Präfix und davon, ob WordPress sie kennt –, nutze --all-tables; diese Option hat Vorrang vor --network und --all-tables-with-prefix. In einem Netzwerk solltest du zusätzlich --url angeben, damit WP-CLI in die richtige Site bootet.

Warum weigert sich WP-CLI, als root zu laufen?

WP-CLI bricht mit einem YIKES-Fehler ab, wenn es den root-Benutzer erkennt. Alles innerhalb der Installation, einschließlich Plugins und Themes, die nicht von dir stammen, würde die Reichweite von root über den Server erben – ein einziges Stück bösartiger Code könnte also die ganze Maschine übernehmen. Das Flag --allow-root überspringt die Prüfung, und Container, die als root laufen, brauchen es häufig, aber das Projekt rät davon ab. Führe die Befehle stattdessen als der Systembenutzer aus, dem die WordPress-Dateien gehören.

Was bedeutet die Fehlermeldung 'This does not seem to be a WordPress installation'?

WP-CLI hat dort, wo es gesucht hat, keine WordPress-Core-Dateien gefunden und daher nie gebootet. Führe den Befehl aus dem Verzeichnis aus, das wp-admin, wp-content und wp-includes enthält, oder verweise mit dem globalen Parameter --path auf die Installation. Übergib den Wert in der Gleichheitszeichen-Form, --path=/var/www/html, denn ein durch Leerzeichen getrenntes Argument lässt das Flag ohne Wert zurück und derselbe Fehler tritt erneut auf.

Läuft WP-CLI unter Windows?

WP-CLI ist für eine UNIX-ähnliche Umgebung wie Linux, macOS, FreeBSD oder Cygwin gebaut und wird unter Windows selbst nur teilweise unterstützt. Auf einem Windows-Rechner sind WSL oder Cygwin daher der verlässliche Weg. Außerdem wird WordPress 4.9 oder neuer benötigt, und alles, was hinter dem aktuellen WordPress-Release zurückliegt, funktioniert möglicherweise nicht vollständig.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.