Von der Idee zum WordPress-Plug-in: Schlagwörter automatisch hinzufügen #2

Alexander Trust, den 26. Januar 2021
Wordpress - Wallpaper
Wordpress – Wallpaper

In Teil 1 von der Idee zum WordPress-Plug-in beschrieb ich bereits umfassend die Beweggründe, wie man von ein paar Zeilen Code für eine regelmäßig wiederkehrende Aufgabe am Ende des Tages zu einem ausgewachsenen Plug-in kam. Der vorherige Text wies außerdem bereits fertigen, funktionierenden Quellcode auf, mit dem man von Hand ohne Weiteres hätte arbeiten können. Doch was wäre ein Plug-in ohne Komfort. Für Komfort dient die Eingabe vom Nutzer, und die speichert man am besten in der Datenbank ab.

Genau das wollen wir Euch dann in dieser Ausgabe erklären, und auch, welche Grenzen unser Plug-in weiterhin hat. Die Herangehensweise zeigt vor allem, dass so ein relativ einfaches Projekt mit ein wenig Fantasie und Aufwand zu etwas richtig seriösem aufgebaut werden kann.

Das Plug-in braucht mehr Komfort

Anstatt den Quellcode immer von Hand anzupassen, wenn man neue Schlagwörter hinzufügen möchte, kann man dazu die Datenbank bei WordPress verwenden und entsprechende Formulare. Folgende „Details“ und „Fragen“ gibt es unter anderem zu klären, von denen wir aber nur einige exemplarisch nennen wollen:

  • Wie kann ich mit der Datenbank von WordPress kommunizieren?
  • Benötige ich eine eigene Tabelle?
  • Wie handhabt WordPress Formulare?
  • Gibt es Sicherheitsvorkehrungen zu treffen?
  • Muss ich mehrere Plug-in-Dateien erstellen?
  • Was ist die WordPress-Nonce, und wie kann sie mir in diesem Fall helfen?

Wann benötige ich für mein Plug-in eine eigene Tabelle?

Es ist eine viel diskutierte Frage, ob es sinnvoll sein kann, eine eigene Tabelle für ein WordPress-Plug-in einzurichten. Eines der Schwergewichte unter den WordPress-Plug-ins, Yoast SEO, änderte vor ein paar Monaten seine Einstellung zu der Thematik und migriert seitdem mit jedem Update zunehmend mehr Daten aus WordPress-Tabellen in eigene.

Für mich liegt die Antwort auf der Hand: Ich mache immer eine eigene Tabelle, wenn ich eigene Daten verwenden möchte. Sieht man davon ab, dass WordPress-Tabellen vor allem bei großen Websites sowieso relativ unübersichtlich werden, kann es beim Abfragen von Daten auch Performance-Vorteile bieten. In der Tat ergibt es aber nur wenig Sinn, den Aufwand zu betreiben, wenn man am Ende nur eine Handvoll Datensätze speichern mag. Die lassen sich zur Not auch noch in der WordPress-Tabelle sichern.

Wie kommuniziere ich mit der WordPress-Datenbank?

WordPress hält für Entwickler Befehle zur Verfügung, um mit der Datenbank zu kommunizieren. In Einzelfällen kann es sinnvoll sein, die WordPress-Routinen zu umgehen und mittels PHP oder anderer Scriptsprachen die Kommunikation zur Datenbank auf eigene Faust zu unternehmen. Das ist aber nur in Fällen ratsam, in denen man wirklich viele Datensätze bearbeitet, und an dieser Stelle rede ich von zehntausenden Datensätzen und mehr, die regelmäßig immer wieder abgefragt werden oder aktualisiert werden. Denn zur Wahrheit gehört, dass die WordPress-Datenbank-Engine nicht die schnellste ist.

In Teil 1 wiesen wir bereits auf Befehle wie add_option() (vgl. WordPress Code-Referenz) hin, mit dem sich Daten ohne Weiteres in die Tabelle wp_options von WordPress hinzufügen lassen. Mittels update_option() kann man vorhandene Datensätze aktualisieren, und sie mit delete_option() entsprechend wieder entfernen.

Doch wir wollen nicht die WordPress-Tabelle zumüllen, sondern mit der eigenen Tabelle kommunizieren. Diese funktioniert über die wpdb-Schnittstelle.

Eigene Tabelle für WordPress erstellen

Klar kann man die Tabelle für das eigene Plug-in auch von Hand erstellen, über phpMyAdmin oder eine andere Software, auch am Desktop-Computer. Wer sich auskennt, kann dazu auch einfach die mysql-Schnittstelle auf dem Server mittels Terminal verwenden. Doch bei einem Plug-in geht es ja um die Wiederverwendbarkeit und die Möglichkeit, dass auch andere Nutzer damit arbeiten können.

Entsprechend nutzen wir die WordPress-eigenen Mittel, um die Tabelle zu erstellen. Der beste Zeitpunkt dafür ist übrigens beim „Aktivieren“ des Plug-ins. Wie im ersten Teil dieses Tutorials schon beschrieben, trennt WordPress zwischen dem Aktivieren, Deaktivieren und Deinstallieren. Dafür gibt es extra drei passende „Auslöser“, die wir uns zunutze machen können.

In unserem Fall benötigen wir eine Tabelle, die lediglich drei Reihen umfasst, eine fortlaufende Nummerierung (ID), eine Suchphrase (searchstring) und ein Schlagwort (keywordstring). Um in mySQL eine Tabelle mit dieser Struktur einzurichten, benötigt man folgenden Code:

CREATE TABLE XYZ (
		id mediumint(9) NOT NULL AUTO_INCREMENT,
		searchstring varchar(25) NOT NULL,
		keywordstring varchar(25) NOT NULL,
		UNIQUE KEY id (id),
	    UNIQUE KEY searchstring (searchstring)
	) ZEICHENSATZ;

Wir müssen der Tabelle noch einen Namen geben und auch einen Zeichensatz angeben. Da aber durch die Installation von WordPress je nach Konfiguration von WordPress ein Zeichensatz genutzt wird, und wir uns nicht den Kopf darüber zerbrechen wollen, welcher das ist, verwenden wir einfach $wpdb->get_charset_collate() (vgl. WordPress Code-Referenz), um den Zeichensatz abzufragen.

Ja, und auch bei der Namensgebung für die Tabelle, wollen wir uns zumindest an die Gepflogenheiten halten und greifen daher auf das Präfix zurück, das WordPress uns anbietet, und Nutzer bei der Installation individuell einrichten können ($wpdb->prefix). Unsere Tabelle nennen wir dann noch sn_add_keywords, die entsprechend mit dem Präfix von WP ausgestattet wird.

Tabelle bei Plug-in-Aktivierung einrichten

Nun gehen wir davon aus, dass wir die Tabelle beim Aktivieren des Plug-ins einrichten möchten. Wir greifen dazu also auf den register_activation_hook() (vgl. WordPress Code-Referenz) zurück.

Dieser Aufruf hat zwei Parameter. Der erste nennt den Dateinamen des Plug-ins inklusive Pfadangabe. Dafür gibt es glücklicherweise eine Konstante namens __FILE__, die uns die Arbeit erleichtert, wenn wir uns an die Konventionen halten und unser Plug-in auch im Plug-in-Verzeichnis unterbringen. Der zweite Parameter ruft eine Funktion auf, die dann zum Zeitpunkt der Aktivierung des Plug-ins aktiv wird.

Wir erstellen also eine Funktion, die uns die Tabelle erstellt. Die sieht wie folgt aus:

function sn_add_keywords_create_database() {
  global $wpdb;
  $charset_collate = $wpdb->get_charset_collate();
  $table_name = $wpdb->prefix . 'sn_add_keywords';

  $sql = "CREATE TABLE $table_name (
		id mediumint(9) NOT NULL AUTO_INCREMENT,
		searchstring varchar(25) NOT NULL,
		keywordstring varchar(25) NOT NULL,
		UNIQUE KEY id (id),
    UNIQUE KEY searchstring (searchstring)
	) $charset_collate;";

	require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
	dbDelta( $sql );
}

Die rufen wir dann mit dem passenden Auslöser auf:

register_activation_hook(__FILE__, 'sn_add_keywords_create_database');

Tabelle bei der Deinstallation löschen

Man könnte die Tabelle theoretisch auch beim Deaktivieren schon löschen. Aber das erachten wir für nicht sinnvoll. Bei der Deinstallation eines Plug-ins sollte man aber sehr wohl darauf achten, hinter sich sauberzumachen. Wir setzen in dem Fall den register_uninstall_hook() ein. Der funktioniert analog zum Aktivierungsauslöser und hat die gleichen beiden Parameter. Wir erstellen also eine Funktion, die die Datenbank löscht:

function sn_add_keywords_remove_database() {
  global $wpdb;
  $table_name = $wpdb->prefix . 'sn_add_keywords';
  $sql = "DROP TABLE IF EXISTS $table_name";
  $wpdb->query($sql);
}

Diese rufen wir dann mit dem Auslöser wie folgt auf:

register_uninstall_hook(__FILE__, 'sn_add_keywords_remove_database');

Wie kommuniziert unser Plug-in mit der Datenbank?

Wie man mittels WordPress-Funktionen mit der Datenbank kommuniziert, haben wir schon angeschnitten. Aber damit unser Plug-in, das ebenfalls kann, benötigt es ein Formular.

Zudem können wir an dieser Stelle noch ein paar Sicherheitsvorkehrungen treffen. Anders als bei einem Formular zur Anmeldung beim Newsletter, wollen wir vermutlich nur Personen Schlagworte hinzufügen lassen, denen wir vertrauen. Auch müssen wir sicherstellen, dass in der Datenbank nichts „Bösartiges“ gespeichert wird. Aus diesem Grund nutzen wir die wordpress-eigenen Befehle für die Datenbankkommunikation, weil manche von ihnen bereits Sicherheitsmechanismen enthalten, und wir so ein bisschen beruhigter sein können. Doch, der Reihe nach.

Formular für die Datenbankeingabe erstellen

An dieser Stelle kann man ohne Umschweife zunächst einmal ein einfaches Formular in HTML erstellen. Wir benötigen zwei Eingabefelder für Text, eventuell noch zwei Etiketten und einen Button (oder Link) zum Absenden des Formulars. Der Einfachheit halber – weil es funktioniert, und um schnell erste Ergebnisse zu erhalten – verwenden wir keine spezielle Aktion zum Auslösen, und nutzen die POST-Methode.

Unser HTML-Formular sieht wie folgt aus:

<form method="POST">
	<?php wp_nonce_field('sn_add_keywords', 'sn_add_keywords_nonce', true, true); ?>
    <h2>Neuen Eintrag hinzufügen:</h2>
    <label for="searchstring">Searchstring:</label>
    <input type="text" id="searchstring" name="searchstring" required>
    <label for="keywordstring">Keywordstring:</label>
    <input type="text" id="keywordstring" name="keywordstring" required>
	<?php submit_button('Hinzufügen'); ?>
</form>

Die submit_button()-Funktion stellt WordPress zur Verfügung. In Klammern übergeben wir die Beschriftung für den Button. Der Button erhält dann auch die typischen Klassen, damit er mittels CSS automatisch in der für WordPress typischen Kolorierung und Form erscheint. Wer das individuelle handhaben mag, kann natürlich einen eigenen Button erstellen.

Was ist dieses Nonce, und wieso brauche ich sie?

Im obersten Feld des Formulars erkennt Ihr den Befehl wp_nonce_field(), den WordPress ebenfalls zur Verfügung stellt. Die „Nonce“ (vgl. Wikipedia) ist eine flüchtige Phrase, die zum Zwecke der Authentifizierung erstellt wird.

WordPress bietet dieses System ebenfalls an. Es ist sehr hilfreich, wenn man die Kommunikation mit der Datenbank nur authentifizierten Nutzern zu ermöglichen. Denn die Nonce wird beim Aufruf erzeugt und ist dann nur in der Session des Nutzers gültig. Würde jemand, der gar nicht mit WordPress eingeloggt ist, versuchen die Funktion auszuführen, scheiterte die Kommunikation daran, dass er nicht die korrekte „Nonce“ dafür hat.

Wir werden dann die erstellte Nonce noch überprüfen, bevor wir tatsächlich in die Datenbank schreiben.

Formular-Daten in die Datenbank schreiben

Nun müssen wir uns also noch darum kümmern, die im Formular eingegebenen Daten beim Klick auf den Button in die Datenbank zu speichern. Wie machen wir das?

Zum einen haben wir ja geschrieben, dass die Daten mittels POST-Methode übergeben werden. Sie sind dann entsprechend über die POST-Variablen auslesbar. Mit dem Nonce-Field erzeugt WordPress aber noch ein unsichtbares Feld mit dem Authentifizierungstoken. Auch der ist dann als POST-Variable abfragbar und lässt sich so vergleichen.

Für das Schreiben in die Datenbank, kann man entweder ein eigenes QUERY and $wpdb übergeben, oder wir nutzen den von WordPress implementierten $wpdb->insert()-Befehl.

if(is_admin() && (isset($_POST['sn_add_keywords_nonce']) || wp_verify_nonce($_POST['sn_add_keywords_nonce'], 'sn_add_keywords'))) {
	global $wpdb;
	$table_name = $wpdb->prefix . 'sn_add_keywords';
	$newdata = array(
        'searchstring' => sanitize_text_field($_POST['searchstring']),
        'keywordstring' => sanitize_text_field($_POST['keywordstring']),
      );
    $wpdb->insert($table_name, $newdata, '%s');
    wp_safe_redirect(esc_url(admin_url('admin.php?page=sn_add_keywords%2Fsnak.php')));
}
exit();

Über den Befehl wp_safe_redirect() leiten wir nach dem Absenden den Benutzer wieder zurück zur Ausgangsseite. Diese Vorgehensweise hat übrigens einen Nachteil, den wir in Kauf nehmen, der aber für ein frei verfügbares Plug-in ausgebessert werden sollte, zum Beispiel, indem man AJAX verwendet.

Zuletzt stellen wir über den exit()-Befehl sicher, dass wirklich alle POST-Variablen nach dem Abschluss gelöscht werden. So wird das Formular geleert und auch eine neue Nonce erstellt.

Das Plug-in, wie wir es verwenden sieht bei uns dann übrigens derzeit so aus.

Was wir nicht erzählt haben?

Auch dieser Beitrag ist schon wieder ziemlich lang geworden. Deshalb haben wir einige Details geschlabbert. Darunter:

  • Denn in unserem Plug-in haben wir beispielsweise bei der Aktivierung auch eine Versionsnummer übergeben. Die können wir dann bei einem Update vergleichen und nutzen, um so Änderungen an der Datenbank vorzunehmen.
  • Wir haben aber auch unterschlagen, dass wir unsere Tabelle beim Aktivieren bereits mit ein paar Datensätzen ausgestattet haben. Ich finde es immer schöner, wenn man zumindest ein paar Anhaltspunkte hat.
  • Es kann außerdem sinnvoll sein, die Daten nicht zu löschen, oder dies dem Nutzer zur Wahl zu stellen. Um so eine Option haben wir uns bislang nicht gekümmert.
  • WordPress hält auch Alternativen zu den „Auslösern“ bereit. So kann man Dateien namens uninstall.php oder activation.php erstellen. Deren Inhalte werden dann automatisch ausgeführt.
  • Wie Ihr auf dem Screenshot erkennen könnt, geben wir die vorhandenen Datensätze auch im WordPress-Administrationsportal aus. Wie wir das gemacht haben, haben wir an dieser Stelle ebenso geschlabbert.
  • Nicht thematisiert haben wir den Prozess, wie man ein Plug-in bei WordPress einreicht. Vielleicht kommt das in einem anderen Beitrag einmal zur Sprache, oder Ihr findet es bis dahin selbst heraus.
  • Spannend ist auch, wie man bereits vorhandene Daten wieder löscht, oder überarbeitet.
  • Der Quellcode hier enthält auch kein CSS und gibt ganz grundsätzlich nicht das komplette Plug-in wieder, wie wir es verwenden. Zum Zwecke des Tutorials habe ich diesen angepasst, damit er allgemein verständlicher wird.

Tatsächlich ist diese „Idee“, aus der erst eine Handvoll Quellcode wurde, in unserem Fall mittlerweile auf fünf Dateien mit rund 250 Zeilen Quellcode angewachsen (Kommentare inklusive).

Wenn jemand von Euch Fragen zu diesem Projekt hat, kann er uns gerne auf den üblichen Kanälen anschreiben.

Weitere Teile der Reihe Von der Idee zum Wordpress-Plug-in


Ähnliche Nachrichten