In diesem Beitrag möchte ich dir gerne einen Weg aufzeigen, wie du sehr einfach und ebenso sicher nicht verwendete Dateien in deiner WordPress-Instanz finden kannst. Du benötigst dafür ein wenig technisches Verständnis – aber keine Sorge: Ich nehme dich an die Hand und führe dich Schritt für Schritt durch den gesamten Prozess.
Der Bedarf für diese Lösung entstand aus einem ganz praktischen Grund: Mein eigener Blog hat mittlerweile satte 174.000 Dateien angesammelt – da wird es höchste Zeit, etwas auszumisten und wieder Platz auf dem Server zu schaffen.
Für das Finden von nicht benötigten Dateien unter WordPress gibt es diverse Plugins. Diese haben jedoch alle den Nachteil, dass sie direkt auf der WordPress-Instanz laufen, Systemressourcen verbrauchen und – wie viele Kommentare zeigen – nicht immer zuverlässig oder sicher funktionieren. Daher habe ich mir folgenden Weg überlegt:
Ich exportiere die WordPress-Beiträge als JSON-Datei mit den wichtigsten Feldern (ID, Titel, Inhalt). Anschließend lade ich das Upload-Verzeichnis herunter und lasse ein Python-Skript prüfen, ob die Dateien in den Beiträgen referenziert werden. Alle nicht gefundenen Dateien können theoretisch als ungenutzt eingestuft und anschließend überprüft oder gelöscht werden.
⚠️ Wichtiger Hinweis:
Ich empfehle dir dringend, vor dem Löschen von Dateien ein vollständiges Backup deiner WordPress-Instanz anzulegen. Idealerweise testest du die Löschung zunächst in einer Staging-Umgebung oder auf einer Kopie deiner Seite. In seltenen Fällen kann es vorkommen, dass Dateien fälschlich als ungenutzt erkannt werden – insbesondere wenn sie über PageBuilder, Custom Fields oder Medien-IDs referenziert werden.
Inhaltsverzeichnis
- Warum bestehende Plugins nicht immer zuverlässig arbeiten
- Schritt 1 – Export der Tabelle wp_posts als JSON
- Schritt 2 – Download des Upload-Verzeichnisses
- Schritt 3 – Ausführen des Python-Skripts zur Suche nach verwaisten Bildern
- Schritt 4 – Aufräumen der WordPress-Datenbank
- Aufräumen via SSH
- Fazit
Warum bestehende Plugins nicht immer zuverlässig arbeiten
Es gibt diverse Plugins wie Media Cleaner, DNUI (Delete Not Used Image) oder ähnliche, die versprechen, ungenutzte Mediendateien automatisch zu erkennen und zu löschen. Grundsätzlich eine praktische Idee – doch in den Kommentaren dieser Plugins häufen sich Berichte über falsch gelöschte Dateien, die offenbar doch noch in Verwendung waren.
Die Wiederherstellung solcher Dateien ist oft aufwendig und erfordert entweder Backups oder manuelle Nacharbeit.
Meine Lösung setzt daher auf einen anderen Ansatz:
Sie analysiert die Inhalte kontrolliert und nachvollziehbar außerhalb des WordPress-Systems – und ist damit deutlich sicherer und transparenter.
Schritt 1 – Export der Tabelle wp_posts
als JSON
Als Erstes werden die Spalten ID
, post_title
und post_content
aus der WordPress-Tabelle wp_posts
exportiert. Der Tabellenpräfix wp_
kann bei dir abweichen – diesen findest du in der Datei wp-config.php
unter:
$table_prefix = 'wp_';
In manchen Fällen sind mehrere WordPress-Instanzen in einer Datenbank vorhanden. Achte also darauf, den richtigen Präfix zu verwenden.
Der Export über phpMyAdmin ist dabei besonders einfach: Du führst lediglich ein SELECT
-Statement aus, das dir die relevanten Inhalte liefert. Der eigentliche Export als JSON erfolgt über die integrierte Exportfunktion.
SQL-Statement:
SELECT ID as "id", post_title as 'Titel', post_content as 'Content' FROM wp_posts WHERE post_type in ('page', 'post');
Wenn du dieses SQL-Statement in phpMyAdmin ausführst, erscheint eine Tabelle mit den Ergebnissen. Scrolle nun ganz nach unten – dort findest du den Link „Exportieren“. Ein Klick darauf öffnet eine neue Seite, auf der du den Exporttyp von SQL auf JSON umstellst. Danach nur noch mit OK bestätigen, und der Export startet.



Je nach Anzahl der Beiträge kann der Download ein paar Sekunden dauern.
Schritt 2 – Download des Upload-Verzeichnisses
Im zweiten Schritt wird das komplette Upload-Verzeichnis deiner WordPress-Installation heruntergeladen. Dieses befindet sich standardmäßig unter:
/wp-content/uploads/
Ich verwende dafür das kostenlose Tool WinSCP, das eine einfache und übersichtliche Oberfläche bietet. Du benötigst lediglich die SFTP-Zugangsdaten zu deinem Webspace. Diese findest du in der Regel im Kundenbereich deines Hosting-Anbieters.
Falls dir kein direkter Zugriff per SFTP möglich ist, bieten viele Hoster eine alternative Lösung an: Du kannst das Verzeichnis online als ZIP-Archiv erstellen und anschließend herunterladen.
💡 Tipp: Achte darauf, die Ordnerstruktur beizubehalten – das Python-Skript analysiert später jede Datei im Originalpfad.
Schritt 3 – Ausführen des Python-Skripts zur Suche nach verwaisten Bildern
Für das Skript wird lediglich Python 3 benötigt – weitere externe Bibliotheken sind nicht erforderlich.
Das Skript kann direkt über die Kommandozeile im Projektverzeichnis ausgeführt werden:
python3 findunusedfiles.py
Während der Ausführung listet das Skript alle Bilder aus dem Upload-Verzeichnis auf und zeigt direkt in der Konsole an, ob sie verwendet (✅) oder nicht verwendet (❌) wurden.
Die Laufzeitausgabe sieht zum Beispiel so aus:
Nach Abschluss wird eine Datei namens unused_images.txt
erzeugt.
Darin enthalten ist eine Liste aller Bildpfade, die im Export der WordPress-Datenbank (siehe Schritt 1) nicht referenziert wurden.
Diese Datei dient als Grundlage zur manuellen Prüfung oder zum späteren Löschen der nicht verwendeten Dateien.
🔗 Hinweis: Das hier verwendete Skript
findunusedfiles.py
sowie ein Beispiel-SQL-Generator findest du ebenfalls auf GitHub:
github.com/StefanDraeger/wp-unused-files-cleaner
Quellcode
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Titel: WordPress Upload-Verzeichnis auf ungenutzte Dateien prüfen Beschreibung: Dieses Skript durchsucht das lokale Upload-Verzeichnis einer WordPress-Installation nach Bilddateien und vergleicht diese mit den Inhalten aller Beiträge und Seiten, die zuvor als JSON-Datei aus der Tabelle `wp_posts` exportiert wurden. Dateien, die in keinem Beitrag referenziert sind, werden als potenziell ungenutzt gelistet. Autor: Stefan Draeger Webseite: https://draeger-it.blog """ import os import json import sys # Konfiguration UPLOADS_DIR = './wp-content/uploads' JSON_FILE = './wp_posts.json' IMAGE_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.tiff', '.bmp') def format_size(bytes_value): if bytes_value < 1024: return f"{bytes_value} Bytes" elif bytes_value < 1024 ** 2: return f"{bytes_value / 1024:.2f} KB" elif bytes_value < 1024 ** 3: return f"{bytes_value / (1024 ** 2):.2f} MB" else: return f"{bytes_value / (1024 ** 3):.2f} GB" def load_json_data(json_file): if not os.path.isfile(json_file): print(f"❌ Fehler: Datei '{json_file}' nicht gefunden.") sys.exit(1) try: with open(json_file, 'r', encoding='utf-8') as file: raw_json = json.load(file) except json.JSONDecodeError: print(f"❌ Fehler: Datei '{json_file}' ist kein gültiges JSON.") sys.exit(1) for obj in raw_json: if obj.get('type') == 'table' and obj.get('name') == 'wp_posts': return obj.get('data', []) print("❌ Fehler: Keine Daten zur Tabelle 'wp_posts' gefunden.") sys.exit(1) def scan_uploads(content_list): if not os.path.isdir(UPLOADS_DIR): print(f"❌ Fehler: Upload-Verzeichnis '{UPLOADS_DIR}' nicht gefunden.") sys.exit(1) unused_files = [] checked_count = 0 for root, dirs, files in os.walk(UPLOADS_DIR): for file_name in files: if file_name.lower().endswith(IMAGE_EXTENSIONS): full_path = os.path.join(root, file_name) relative_path = os.path.relpath(full_path, '.').replace('\\', '/') checked_count += 1 found = False for i in range(len(content_list)): if relative_path in content_list[i]: content_list[i] = content_list[i].replace(relative_path, '') found = True if found: content_list = [c for c in content_list if 'wp-content/uploads/' in c] print(f"✅ Verwendet: {relative_path}") else: unused_files.append(relative_path) print(f"❌ Nicht verwendet: {relative_path}") return unused_files, checked_count def write_unused_list(unused_files): with open('unused_images.txt', 'w', encoding='utf-8') as f: for path in unused_files: f.write(path + '\n') print("📝 Datei 'unused_images.txt' wurde erstellt.") def write_sql_files(unused_files): with open('delete_attachments.sql', 'w', encoding='utf-8') as del_out: del_out.write("-- SQL-Befehl zum Löschen verwaister Medien aus wp_posts (Typ: attachment)\n\n") del_out.write("DELETE FROM wp_posts\nWHERE post_type = 'attachment'\nAND guid IN (\n") for i, path in enumerate(unused_files): end = ",\n" if i < len(unused_files) - 1 else "\n" del_out.write(f" '{path}'{end}") del_out.write(");\n") print("🗑️ Datei 'delete_attachments.sql' wurde erzeugt.") with open('select_attachments.sql', 'w', encoding='utf-8') as sel_out: sel_out.write("-- SQL-Befehl zur Prüfung verwaister Medien aus wp_posts (Typ: attachment)\n\n") sel_out.write("SELECT ID, guid FROM wp_posts\nWHERE post_type = 'attachment'\nAND guid IN (\n") for i, path in enumerate(unused_files): end = ",\n" if i < len(unused_files) - 1 else "\n" sel_out.write(f" '{path}'{end}") sel_out.write(");\n") print("🔍 Datei 'select_attachments.sql' wurde erzeugt.") def write_log(unused_files, checked_count): total_size_bytes = sum( os.path.getsize(os.path.join('.', path)) for path in unused_files if os.path.isfile(os.path.join('.', path)) ) formatted_size = format_size(total_size_bytes) with open('cleanup_log.txt', 'w', encoding='utf-8') as log: log.write("📄 Ausführungsprotokoll – WordPress Dateiaufräumung\n") log.write("==================================================\n\n") log.write(f"📦 Verarbeitete Dateien: {checked_count}\n") log.write(f"🗂️ Ungenutzte Dateien gefunden: {len(unused_files)}\n") log.write(f"💾 Speicherverbrauch (gesamt): {formatted_size}\n\n") log.write("📝 Die folgenden Dateien wurden erstellt:\n") log.write("- unused_images.txt\n") log.write("- delete_attachments.sql\n") log.write("- select_attachments.sql\n") print("🧾 Logdatei 'cleanup_log.txt' wurde erstellt.") def main(): entries = load_json_data(JSON_FILE) content_list = [entry.get('Content', '') for entry in entries] unused_files, checked_count = scan_uploads(content_list) print("\nAnalyse abgeschlossen.") print(f"Geprüfte Dateien: {checked_count}") print(f"Nicht referenzierte Dateien: {len(unused_files)}\n") if unused_files: print("⚠️ Nicht referenzierte Bilddateien:") for path in unused_files: print(path) write_unused_list(unused_files) write_sql_files(unused_files) write_log(unused_files, checked_count) if __name__ == "__main__": main()
Schritt 4 – Aufräumen der WordPress-Datenbank
⚠️ Wichtiger Hinweis vorab:
Bevor du Änderungen an deiner Datenbank vornimmst, solltest du ein vollständiges Backup deiner WordPress-Datenbank erstellen. So kannst du im Fall eines Fehlers jederzeit alles wiederherstellen.
WordPress speichert alle hochgeladenen Medien – also auch Bilder – in der Tabelle wp_posts
. Dabei handelt es sich um Einträge mit dem Post-Typ attachment
, wobei in der Spalte guid
der Pfad zur Datei gespeichert ist.
Wenn du mit dem Python-Skript verwaiste Bilder identifiziert und vielleicht schon gelöscht hast, verbleiben deren Einträge trotzdem in der WordPress-Mediathek. Diese kannst du gezielt aus der Datenbank entfernen.
Vorgehen:
- Öffne die Datei
unused_images.txt
, die du im vorherigen Schritt erhalten hast. - Jeder darin aufgeführte Pfad (z. B.
wp-content/uploads/2023/08/beispiel.jpg
) lässt sich mit einem einfachen SQL-Befehl entfernen:
DELETE FROM wp_posts WHERE post_type = 'attachment' AND guid LIKE '%wp-content/uploads/2023/08/beispiel.jpg';
- Um diese Aufgabe bei vielen Dateien zu automatisieren, kannst du folgendes Python-Skript nutzen. Es erstellt dir aus
unused_images.txt
eine vollständige SQL-Datei mit allen nötigen Löschbefehlen:
# generate_delete_sql.py with open('unused_images.txt', 'r', encoding='utf-8') as infile, open('delete_attachments.sql', 'w', encoding='utf-8') as outfile: outfile.write("-- SQL-Befehle zum Löschen verwaister Medien aus wp_posts (Typ: attachment)\n\n") for line in infile: path = line.strip() if path: outfile.write(f"DELETE FROM wp_posts WHERE post_type = 'attachment' AND guid LIKE '%{path}';\n")
- Führe die generierte Datei
delete_attachments.sql
anschließend in phpMyAdmin oder über ein externes SQL-Tool aus.
Optional: Erst prüfen, dann löschen
Wenn du sicherstellen willst, dass die Statements korrekt sind, kannst du sie vor dem Löschen zunächst mit SELECT
testen:
SELECT ID, guid FROM wp_posts WHERE post_type = 'attachment' AND guid LIKE '%wp-content/uploads/2023/08/beispiel.jpg';
Mit diesem Schritt entfernst du nicht nur die Bilddateien selbst, sondern auch die dazugehörigen Mediathek-Einträge – für eine wirklich aufgeräumte WordPress-Installation.
Aufräumen via SSH
⚠️ Wichtiger Sicherheitshinweis: Bevor du Dateien vom Server löschst, solltest du unbedingt ein vollständiges Backup deiner WordPress-Installation und der Datenbank anlegen. In seltenen Fällen können Dateien fälschlich als ungenutzt erkannt werden – z. B. wenn sie über PageBuilder, Shortcodes oder Custom Fields eingebunden sind.
Teste den Löschvorgang idealerweise zuerst in einer Staging-Umgebung.
Wenn du Zugriff auf deinen Webserver per SSH hast, kannst du die ungenutzten Dateien aus der Datei unused_images.txt
direkt automatisiert löschen – ohne mühsames Durchklicken per Hand.
Voraussetzungen:
- Die Datei
unused_images.txt
befindet sich auf dem Server (z. B. via WinSCP oder scp hochgeladen). - Du befindest dich im WordPress-Stammverzeichnis oder die Pfade in der Datei stimmen relativ zur aktuellen Position.
Optional: Dry-Run vor dem Löschen
Damit du vorab prüfen kannst, ob die Dateien wirklich existieren:
while IFS= read -r file; do if [ -f "$file" ]; then echo "Würde löschen: $file" else echo "❌ Nicht gefunden: $file" fi done < unused_images.txt
Dateien sicher löschen (nach manueller Prüfung)
while IFS= read -r file; do if [ -f "$file" ]; then rm "$file" echo "✅ Gelöscht: $file" fi done < unused_images.txt
Optional: Löschvorgang protokollieren
while IFS= read -r file; do if [ -f "$file" ]; then rm "$file" echo "$(date +"%F %T") Gelöscht: $file" >> deleted_files.log fi done < unused_images.txt
Fazit
Ein überfülltes Upload-Verzeichnis ist nicht nur unübersichtlich, sondern kann auch unnötig Speicherplatz und Backup-Zeit kosten. Mit dem hier vorgestellten Ansatz hast du eine sichere, transparente und Plugin-freie Lösung, um gezielt ungenutzte Dateien in deiner WordPress-Installation zu identifizieren und aufzuräumen.
Durch die Kombination aus Datenbank-Export, Python-Skript und optionaler Löschung via SSH behältst du die volle Kontrolle – und vermeidest die Risiken automatischer Plugin-Löschungen.
Zudem hast du mit den generierten SQL-Dateien und dem Log eine solide Dokumentation deines Bereinigungsprozesses.
💡 Tipp zum Schluss: Behalte die Anzahl deiner Medien im Blick, deaktiviere nicht benötigte Thumbnails und führe diese Art von Aufräumaktion regelmäßig durch – so bleibt dein System langfristig sauber und performant.