WP-CLI-Löschbefehle: Welche Tabellen jeder Befehl anfasst und was er zurücklässt

Management Summary
Das Löschen von WordPress-Inhalten betrifft häufig mehr als den sichtbaren Beitrag: Verknüpfte Angaben und teilweise Mediendateien gehören ebenfalls dazu. WP-CLI ist ein textbasiertes Verwaltungswerkzeug, das dafür die Löschabläufe von WordPress verwendet. Das ist bei größeren Bereinigungen wichtig, weil direkt entfernte Datenbankzeilen zusammengehörige Reste hinterlassen können. Auswahl und wiederherstellbare Sicherungen müssen vorher feststehen. Eine Datenbankkopie enthält keine hochgeladenen Dateien; spätere Fehler nehmen frühere Löschungen nicht zurück.
Inhalt
WordPress-Daten zu löschen bedeutet mehr als eine Tabellenzeile zu entfernen. Die Anwendung berücksichtigt Beziehungen, Zähler, Cache und Erweiterungen. Direktes SQL umgeht diese Abläufe. Entscheidend sind deshalb Zielauswahl, Nebenwirkungen und eine tatsächlich wiederherstellbare Sicherung.
wp post delete und wp comment delete bieten keinen eigenen --dry-run. Andere WP-CLI-Befehle besitzen durchaus einen Probelauf. Eine vorgelagerte Liste zeigt die ausgewählten Objekte, simuliert aber weder Hooks noch Dateiänderungen und zählt nicht sämtliche betroffenen Datenbankzeilen.

Auswahl sichern, prüfen und erst danach löschen
Das folgende Bash-Beispiel exportiert die Datenbank und speichert eine feste Liste sämtlicher Revisionen mit Status inherit. Pfad, Website und privates Sicherungsverzeichnis sind Platzhalter und vorab an die Installation anzupassen. Das Sicherungsverzeichnis darf weder im Webroot noch über einen Webserver-Alias erreichbar sein.
#!/usr/bin/env bash
set -euo pipefail
umask 077
wp_path=/srv/www/example-wordpress
site_url=https://example.invalid
backup_dir=/srv/private/wp-backups
mkdir -p -- "$backup_dir"
run_dir=$(mktemp -d "$backup_dir/revisions.XXXXXXXX")
wp --path="$wp_path" --url="$site_url" db export "$run_dir/database.sql"
wp --path="$wp_path" --url="$site_url" post list \
--post_type=revision --post_status=inherit --posts_per_page=-1 \
--orderby=ID --order=ASC --format=ids > "$run_dir/revision-ids.txt"
wc -w < "$run_dir/revision-ids.txt"
printf 'Review directory: %s\n' "$run_dir"Vor dem nächsten Schritt stehen Prüfung der IDs und zugehörigen Beiträge, erfolgreicher Export und eine getestete Wiederherstellung. Ein SQL-Abzug enthält keine Mediendateien: Bei Medienlöschung sind zusätzlich Uploads und gegebenenfalls externe Speicher zu sichern. Eine konsistente Sicherung laufender Systeme hängt von Tabellen-Engines und Schreibaktivität ab. Ein erfolgreicher Export allein beweist keine vollständige Wiederherstellbarkeit.
Der folgende separate Löschschritt verwendet ausschließlich die geprüfte Datei. run_dir muss auf das zuvor erzeugte Verzeichnis zeigen. Revisionen werden endgültig entfernt; darunter können Autosaves liegen.
wp_path=/srv/www/example-wordpress
site_url=https://example.invalid
run_dir=/srv/private/wp-backups/revisions.REVIEWED
xargs -r -n 100 wp --path="$wp_path" --url="$site_url" \
post delete --force < "$run_dir/revision-ids.txt"xargs -n 100 begrenzt die Anzahl der IDs pro Aufruf; -r verhindert bei GNU xargs einen Aufruf mit leerer Eingabe. Eine überlange einzelne Argumentliste scheitert normalerweise bereits beim Prozessstart. Mehrere Batches können dagegen teilweise erfolgreich sein: Die Aufrufe bilden keinen gemeinsamen Alles-oder-nichts-Vorgang. Ein späterer Fehler macht vorherige Löschungen nicht automatisch rückgängig. Exitstatus, Protokolle und Restbestand müssen geprüft werden. Die gespeicherte Liste verhindert eine neue Auswahl, aber keine zwischenzeitlichen Änderungen am System; für größere Bereinigungen ist ein kontrolliertes Wartungsfenster sinnvoll.
Was die Anwendungsfunktionen erledigen
Beim endgültigen Löschen eines normalen Beitrags bereinigt WordPress zugehörige Post-Metadaten, Kommentare samt Metadaten, Revisionen und Taxonomie-Verknüpfungen. Die Begriffe selbst bleiben normalerweise erhalten. Anhänge werden nicht pauschal mitgelöscht; Elternbezüge können angepasst werden. Hooks sind festgelegte Stellen, an denen Plugins eigenen Code ausführen können. Erweiterungen können dadurch eigene Daten bereinigen. Ob jede Erweiterung vollständig aufräumt, hängt jedoch von deren Implementierung ab. Mit übersprungenen Plugins fehlen deren Hooks möglicherweise.
Ein direktes SQL-DELETE der Beitragszeile führt diese WordPress-Abläufe nicht aus. Ohne eigene Datenbank-Trigger oder Beziehungen bleiben abhängige Datensätze und möglicherweise veraltete Cachewerte zurück. Solche Zeilen sind weiterhin abfragbar. Eine spätere Wiederverwendung derselben ID kann falsche Zuordnungen erzeugen, ist aber keine zwangsläufige Folge jedes Imports.
| Befehl | Wirkung und Grenze |
|---|---|
wp post delete 123 --force | Endgültige Löschung über WordPress; ein normaler Beitrag nimmt angehängte Medien nicht automatisch mit. |
wp post delete 456 --force, falls 456 ein Anhang ist | Löscht den Anhang und die von WordPress erfassten Dateien/Größen. Externe Kopien, Pluginvarianten und Dateifehler benötigen eigene Prüfung; Inhaltslinks können verwaisen. |
wp comment delete 789 --force | Löscht Kommentar und Metadaten; Core aktualisiert den Beitragszähler für freigegebene Kommentare und passt Kindbezüge an. |
wp transient delete --expired | Bereinigt abgelaufene Transienten in der Datenbank; Werte ohne Ablaufzeit bleiben. |
wp db optimize | Ruft mysqlcheck zur Tabellenoptimierung auf; keine WordPress-Inhaltsbereinigung. |
Die Zahlen sind illustrative IDs. Für Spam erfolgt die Auswahl mit wp comment list --status=spam --format=ids; wp comment delete --status=spam ersetzt keine ID-Liste. Bei nachgewiesener Zählerabweichung lautet eine gezielte Reparatur beispielsweise wp comment recount 123, mit einer Beitrags-ID. Nach normalem Core-Löschen ist ein Recount nicht grundsätzlich erforderlich.
Papierkorb und Cache haben unterschiedliche Grenzen
Ohne --force verschiebt WP-CLI geeignete Beiträge in den aktivierten Papierkorb. Bereits im Papierkorb liegende Einträge, Revisionen oder deaktivierter Papierkorb können trotzdem zur endgültigen Löschung führen. Der Papierkorb verändert neben dem Status auch zugehörige Verwaltungsdaten und ist keine unabhängige Sicherung.
Transienten sind wegwerfbare Cachewerte und dürfen bereits vor dem nominellen Ablauf verschwinden. --all umfasst auch Datenbankwerte ohne Ablaufzeit. Der Neuaufbau kann Last verursachen oder Fehler eines Plugins sichtbar machen; „es kann nichts kaputtgehen“ ist keine belastbare Zusage.
Mit persistentem Objektcache unterscheiden sich Einzel- und Sammellöschung: wp transient delete KEY verwendet die WordPress-API und kann den Schlüssel im aktiven Cache löschen. --all und --expired arbeiten im geprüften WP-CLI-Quellstand dagegen auf Datenbankeinträgen und warnen beim externen Cache. Gruppenlöschung ist bei unterstütztem Backend über wp cache flush-group möglich; Gruppenname und Geltungsbereich müssen feststehen. Ein vollständiges wp cache flush betrifft wesentlich mehr und kann je nach Backend weitere Websites treffen.
OPTIMIZE TABLE gezielt bewerten
MySQL baut gewöhnliche InnoDB-Tabellen bei OPTIMIZE TABLE üblicherweise online neu auf. Exklusive Sperren entstehen insbesondere in Vorbereitungs- und Abschlussphasen; bestimmte Einstellungen oder FULLTEXT-Indizes können einen anderen Ablauf erfordern. MariaDB, Engine und Version sind getrennt zu prüfen. Eine durchgehende Schreibsperre ist keine allgemeingültige InnoDB-Regel.
Gelöschter Platz kann intern wiederverwendet werden. Ob Speicher an das Dateisystem zurückgegeben wird, hängt unter anderem vom Tablespace und Neuaufbau ab, nicht davon, ob seit der Löschung überhaupt noch geschrieben wurde. Laufzeit, zusätzlicher Arbeitsraum, I/O und Sperrwartezeiten gehören in die Planung. Ein nächtlicher Pauschallauf folgt daraus nicht.
Fragen und Antworten
Wie lassen sich verwaiste Metadaten untersuchen?
Eine lesende Abfrage sucht Metadaten, deren zugehöriger Beitrag nicht mehr existiert. Dieser Vergleich heißt Anti-Join und liefert zunächst einen Befund. Das Präfix wp_ muss zur gewählten Website passen:
wp db query 'SELECT COUNT(*) FROM wp_postmeta pm LEFT JOIN wp_posts p ON p.ID = pm.post_id WHERE p.ID IS NULL'Vor einer Bereinigung sind Stichproben, Sicherung, Cachefolgen und mögliche Plugin-Verwendung zu prüfen. Das gleiche Muster ist nicht blind auf Taxonomie-Verknüpfungen übertragbar: Objekte können auch Links, Benutzer oder Pluginobjekte sein. Ein Ausführungsplan hilft bei großen Tabellen; eine bestimmte Zugriffsstrategie ist nicht garantiert.
Begrenzt WP_POST_REVISIONS vorhandene Revisionen sofort?
Nein. Ein numerisches Limit wirkt im regulären Revisionsablauf bei der Erstellung weiterer Revisionen, vorbehaltlich Filtern und Autosave-Ausnahmen. false deaktiviert reguläre Revisionen, entfernt bestehende Einträge aber nicht automatisch. Autosaves sind gesondert zu berücksichtigen.
Was ändert Multisite?
Beitragsbefehle beziehen sich auf die ausgewählte Website; --url legt das Ziel ausdrücklich fest. Konfiguration und Aliase können Vorgaben enthalten. Nicht alle Tabellen sind pro Website getrennt: Benutzer- und Netzwerktabellen sind gemeinsame Strukturen. Netzwerktransienten benötigen den passenden --network-Kontext. wp db export umfasst ohne Tabellenfilter die konfigurierte Datenbank, nicht nur die durch --url gewählte Website.
Quellen
- WP-CLI: wp post delete
- WP-CLI: wp comment delete
- WordPress: wp_delete_post
- WordPress: wp_delete_comment
- WordPress: wp_delete_attachment
- WP-CLI: wp comment recount
- WP-CLI: Quellcode der Transient-Befehle
- WP-CLI: Cachegruppen leeren
- WP-CLI: Datenbankexport
- WP-CLI: Datenbankoptimierung
- MySQL 8.4: OPTIMIZE TABLE
- MariaDB: OPTIMIZE TABLE
- WordPress: Revisionen erstellen und aufbewahren
- WP-CLI: Implementierung der Beitragslöschung
- WP-CLI: Beiträge auswählen
- WordPress: Transients-API
- WP-CLI: Befehlsreferenz