- den Aufbau der WordPress-Datenbank kennen
- die passende Speicherart für Plugin-Daten wählen
- mit $wpdb sicher lesen und schreiben
- eigene Tabellen mit dbDelta anlegen und versioniert aktualisieren
Die meisten Plugins kommen ohne eigene Tabellen aus: Optionen, Inhaltstypen und Metadaten decken viele Fälle ab und haben den Vorteil, dass Export, REST API und Werkzeuge automatisch funktionieren. Es gibt aber Situationen, in denen eine eigene Tabelle deutlich besser ist – etwa bei Tausenden Buchungen, Protokollen oder Statistiken, die nach Datum und Status ausgewertet werden. Diese Lektion zeigt, wann sich eine eigene Tabelle lohnt, wie Sie sie sauber anlegen und warum jede Abfrage mit prepare abgesichert sein muss.
1. Die Standardtabellen
2. Welche Speicherart passt?
Die E-Mail-Adresse für Benachrichtigungen
Die Dauer eines Werkstatttermins
50.000 Buchungen mit Datum, Kunde, Status und Betrag, die nach Zeitraum ausgewertet werden
Die Wetterdaten eines externen Dienstes für eine Stunde
Metadaten sind flexibel, aber jede Eigenschaft ist eine eigene Zeile, und die Werte werden als Text gespeichert. Abfragen wie „alle Buchungen im März mit Status bezahlt, sortiert nach Betrag“ müssen deshalb mehrere Verknüpfungen über große Tabellen machen. Eine eigene Tabelle mit passenden Spalten und Indizes erledigt dasselbe in einem Bruchteil der Zeit.
3. Sicher abfragen mit $wpdb
1SELECT * FROM wp_radwerk_buchungen WHERE status = 'offen'3 Buchungen mit passendem Status
x' OR '1'='1 mit und ohne prepare. Ohne Schutz wird die Eingabe Teil des SQL-Befehls; mit prepare bleibt sie ein Wert.1<?php2global $wpdb;3$tabelle = $wpdb->prefix . 'radwerk_buchungen';45// Lesen – Werte immer über Platzhalter6$offen = $wpdb->get_results( $wpdb->prepare(7 "SELECT id, kunde, termin FROM %i WHERE status = %s AND termin >= %s ORDER BY termin",8 $tabelle, 'offen', current_time( 'mysql' )9) );1011// Schreiben – insert bereitet automatisch vor12$wpdb->insert( $tabelle,13 [ 'kunde' => $name, 'termin' => $zeit, 'status' => 'offen', 'betrag' => 49.90 ],14 [ '%s', '%s', '%s', '%f' ]15);Die Platzhalter %s für Texte, %d für ganze Zahlen, %f für Kommazahlen und %i für Tabellen- und Spaltennamen sorgen dafür, dass Werte korrekt maskiert werden. insert, update und delete bereiten ihre Daten selbst vor, get_results und query nicht – dort ist prepare Pflicht, sobald ein Wert von außen kommt.
4. Eigene Tabellen anlegen
Eigene Tabellen entstehen im Aktivierungshook mit dbDelta. Die Funktion vergleicht die gewünschte Struktur mit der vorhandenen und legt fehlende Tabellen und Spalten an. Sie ist sehr pingelig: zwei Leerzeichen nach PRIMARY KEY, jede Spalte in einer eigenen Zeile, Schlüsselwörter in Großbuchstaben. Eine gespeicherte Schema-Version sorgt dafür, dass Änderungen bei Updates automatisch nachgezogen werden.
1<?php2const SCHEMA = '1.1';34public static function tabellen() {5 global $wpdb;6 $zeichensatz = $wpdb->get_charset_collate();7 $sql = "CREATE TABLE {$wpdb->prefix}radwerk_buchungen (8 id bigint(20) unsigned NOT NULL AUTO_INCREMENT,9 kunde varchar(190) NOT NULL,10 termin datetime NOT NULL,11 status varchar(20) NOT NULL DEFAULT 'offen',12 betrag decimal(8,2) NOT NULL DEFAULT 0,13 PRIMARY KEY (id),14 KEY termin_status (termin, status)15 ) $zeichensatz;";16 require_once ABSPATH . 'wp-admin/includes/upgrade.php';17 dbDelta( $sql );18 update_option( 'radwerk_schema', self::SCHEMA, false );19}Variablen
Ausgabe
Leistung und Pflege
Eine eigene Tabelle ist nur so schnell wie ihre Indizes. Ein Index ist ein sortiertes Verzeichnis über eine oder mehrere Spalten, mit dem die Datenbank passende Zeilen findet, ohne die ganze Tabelle zu lesen. Er sollte zu den häufigsten Abfragen passen: Wer meist nach Datum und Status filtert, legt einen kombinierten Index über beide Spalten an. Zu viele Indizes verlangsamen dagegen das Schreiben. Mit dem SQL-Befehl EXPLAIN lässt sich prüfen, ob eine Abfrage einen Index nutzt; das Plugin Query Monitor zeigt langsame Abfragen direkt im Backend an.
Zur Pflege gehört auch das Aufräumen. Buchungen von vor fünf Jahren braucht niemand mehr in der Tabelle – eine geplante Aufgabe kann sie archivieren oder löschen, was zugleich den Datenschutzgrundsatz der Speicherbegrenzung erfüllt. Wer personenbezogene Daten speichert, sollte außerdem die Filter wp_privacy_personal_data_exporters und wp_privacy_personal_data_erasers nutzen, damit Auskunfts- und Löschanfragen über die Werkzeuge von WordPress auch die eigene Tabelle erfassen. Schließlich gehört die Tabelle in die Deinstallation – mit Rückfrage, ob die Daten wirklich gelöscht werden sollen.
Ein Beispiel: Ein Café mit Online-Vorbestellungen speicherte jede Bestellung zunächst als Beitrag mit zwölf Metafeldern. Nach zwei Jahren und 40.000 Bestellungen dauerte die Tagesauswertung über zehn Sekunden. Nach dem Umzug in eine eigene Tabelle mit Index über Abholdatum und Status lieferte dieselbe Auswertung das Ergebnis in unter 50 Millisekunden.
5. Häufige Fragen
Muss ich meine eigene Tabelle beim Export berücksichtigen? Ja. Der WordPress-Export und viele Umzugswerkzeuge kennen nur die Standardtabellen. Bieten Sie einen eigenen Export an und integrieren Sie Ihre Daten in die Datenschutz-Werkzeuge von WordPress (Export und Löschung personenbezogener Daten).
Was sind Transients? Zwischengespeicherte Werte mit Ablaufzeit, gesetzt mit set_transient. Mit einem Objekt-Cache wie Redis liegen sie im Arbeitsspeicher, sonst in wp_options. Sie können jederzeit verschwinden – der Code muss dann neu berechnen.
Wie groß darf eine Metadaten-Tabelle werden? Es gibt keine feste Grenze, aber ab einigen hunderttausend Zeilen werden Filter über Metawerte spürbar langsam. Dann lohnt ein Blick auf Taxonomien, eigene Tabellen oder einen Suchindex.
6. Übung zum Selbermachen
Legen Sie in Ihrem Übungsplugin eine Tabelle für Kontaktanfragen mit Spalten für Name, E-Mail, Nachricht und Zeitpunkt an. Schreiben Sie eine Funktion, die eine Anfrage mit $wpdb->insert speichert, und eine zweite, die alle Anfragen der letzten sieben Tage mit prepare abfragt. Erhöhen Sie danach die Schema-Version, ergänzen Sie eine Spalte „erledigt“ und prüfen Sie mit einem Datenbankwerkzeug, dass dbDelta sie hinzugefügt hat, ohne vorhandene Anfragen zu löschen.
- [1]WordPress.org (2026): Code Reference – class wpdb, wpdb::prepare(), dbDelta().
- [2]WordPress.org (2026): Plugin Handbook – Creating Tables with Plugins.
- [3]OWASP (2025): SQL Injection Prevention Cheat Sheet.
Stand: September 2026, WordPress 7.1, PHP 8.3. Kursmaterial der Klarwerk Akademie. WordPress entwickelt sich schnell – maßgeblich ist die aktuelle Dokumentation auf developer.wordpress.org.