~/wordpress-plugins/

WordPress-Plugins entwickeln

Vom Plugin-Header über Actions und Filter bis zu Gutenberg-Blöcken: wie ein sauberes WordPress-Plugin aufgebaut ist und worauf das Plugin-Verzeichnis achtet.

WordPress ist das Paradebeispiel für eine Plattform, die von Erweiterungen lebt. Das offizielle Plugin-Verzeichnis listet Zehntausende Plugins, und kaum eine Website kommt ohne aus. Die Einstiegshürde ist niedrig: Wer etwas PHP kann, schreibt in wenigen Minuten ein funktionierendes Plugin. Die eigentliche Kunst liegt darin, es so zu bauen, dass es sicher ist, mit anderen Plugins zusammenspielt und auch nach dem nächsten WordPress-Update noch funktioniert.

Das Grundgerüst

Ein Plugin ist ein Ordner unter wp-content/plugins/. Darin liegt eine Hauptdatei, deren Kopfkommentar WordPress ausliest. Pflicht ist nur die Zeile Plugin Name, sinnvoll sind einige weitere Angaben.

<?php
/**
 * Plugin Name:       Lesezeit anzeigen
 * Description:       Blendet über jedem Beitrag die geschätzte Lesezeit ein.
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      7.4
 * Author:            Ihr Name
 * License:           GPL-2.0-or-later
 * Text Domain:       lesezeit-anzeigen
 */

defined( 'ABSPATH' ) || exit;

Die letzte Zeile verhindert, dass die Datei direkt über ihre Adresse aufgerufen wird. Für größere Plugins hat sich eine Aufteilung bewährt: Hauptdatei als schlanker Einstieg, Logik in einem Ordner includes/, Skripte und Styles in assets/, Übersetzungen in languages/ und eine uninstall.php, die beim Löschen des Plugins eigene Optionen und Tabellen entfernt.

Hooks: Actions und Filter

WordPress ruft Ihr Plugin nicht direkt auf. Stattdessen bietet es an vielen Stellen sogenannte Hooks an, an die sich Plugins hängen. Es gibt zwei Arten:

  • Actions sind Ereignisse. An einer bestimmten Stelle sagt WordPress „jetzt passiert X“, und alle registrierten Funktionen werden ausgeführt. Beispiele sind init, wp_enqueue_scripts oder save_post.
  • Filter reichen einen Wert durch. Jede registrierte Funktion bekommt ihn, darf ihn verändern und muss ihn zurückgeben. Beispiele sind the_content oder the_title.
add_filter( 'the_content', function ( $inhalt ) {
    if ( ! is_singular( 'post' ) || ! in_the_loop() ) {
        return $inhalt;
    }
    $woerter = str_word_count( wp_strip_all_tags( $inhalt ) );
    $minuten = max( 1, (int) ceil( $woerter / 200 ) );
    $hinweis = sprintf(
        '<p class="lesezeit">%s</p>',
        esc_html( sprintf( 'Lesezeit: etwa %d Minuten', $minuten ) )
    );
    return $hinweis . $inhalt;
} );

Ein Filter, der vergisst, den Wert zurückzugeben, lässt den Inhalt verschwinden. Das ist einer der häufigsten Anfängerfehler. Über die Priorität als drittes Argument von add_filter und add_action steuern Sie, ob Ihre Funktion vor oder nach anderen läuft. Eigene Hooks mit do_action und apply_filters machen Ihr Plugin wiederum für andere erweiterbar.

Blöcke für den Editor

Seit der Block-Editor (Gutenberg) Standard ist, liefern viele Plugins eigene Blöcke. Ein Block besteht aus einer Beschreibungsdatei block.json, JavaScript für die Darstellung im Editor und entweder gespeichertem HTML oder einer PHP-Funktion, die den Block serverseitig ausgibt. Das offizielle Paket @wordpress/create-block erzeugt ein lauffähiges Gerüst samt Build-Konfiguration:

npx @wordpress/create-block@latest lesezeit-block

Für den Build nutzt das Gerüst @wordpress/scripts, eine vorkonfigurierte Kombination aus Bundler, Babel und Linting. Sie müssen also kein eigenes Build-Setup pflegen.

Sicherheit ist Pflicht

Plugins laufen mit vollen Rechten in der WordPress-Installation. Eine Lücke in Ihrem Code ist eine Lücke in jeder Website, die es nutzt. Vier Regeln decken die meisten Fälle ab:

  1. Rechte prüfen: Vor jeder Aktion mit current_user_can() sicherstellen, dass die Person das darf.
  2. Absicht prüfen: Formulare und AJAX-Aufrufe mit einer Nonce absichern (wp_nonce_field(), check_admin_referer(), check_ajax_referer()).
  3. Eingaben bereinigen: Alles aus $_POST, $_GET und Co. mit passenden Funktionen wie sanitize_text_field() oder absint() säubern.
  4. Ausgaben escapen: Erst beim Ausgeben mit esc_html(), esc_attr() oder esc_url() maskieren. Datenbankabfragen mit Variablen immer über $wpdb->prepare().
Häufigste Lücke: fehlendes Escaping

Die meisten gemeldeten Schwachstellen in Plugins sind Cross-Site-Scripting durch ungeprüfte Ausgaben und fehlende Rechteprüfungen in AJAX- oder REST-Endpunkten. Wer konsequent „früh bereinigen, spät escapen“ umsetzt, schließt den Großteil davon aus.

Lokale Entwicklungsumgebung

Entwickeln Sie nie direkt auf einer Live-Website. Bewährt sind lokale Umgebungen auf Basis von Docker, etwa das offizielle Werkzeug @wordpress/env, das mit einem Befehl eine WordPress-Instanz mit Ihrem Plugin startet. Aktivieren Sie in der Testumgebung WP_DEBUG, damit Warnungen und veraltete Funktionsaufrufe sofort sichtbar werden.

Ins Plugin-Verzeichnis

Das Verzeichnis auf wordpress.org ist der größte Vertriebsweg. Voraussetzungen sind eine GPL-kompatible Lizenz, eine readme.txt im vorgegebenen Format und das Einhalten der Plugin-Richtlinien. Dazu gehört zum Beispiel, dass ein Plugin ohne Zustimmung der Betreiber keine Werbelinks oder Credits im Frontend der Website einblendet. Nach einer manuellen Prüfung erhalten Sie Zugang zu einem SVN-Repository, über das Sie Versionen ausliefern. Ablauf und Fallstricke behandelt der Bereich Add-ons veröffentlichen und pflegen.

Kompatibel bleiben

WordPress legt großen Wert auf Rückwärtskompatibilität, markiert alte Funktionen aber als veraltet. Testen Sie Ihr Plugin vor jedem größeren WordPress-Release mit der Beta-Version, halten Sie die Angabe Tested up to in der readme.txt aktuell und prefixen Sie alle Funktions-, Klassen- und Optionsnamen, damit sie nicht mit anderen Plugins kollidieren.

faq

Fragen und Antworten

Plugin oder Code in der functions.php des Themes?
Alles, was mit der Funktion der Website zu tun hat, gehört in ein Plugin, etwa eigene Inhaltstypen, Shortcodes oder Schnittstellen. Die functions.php ist für Darstellungsfragen des Themes gedacht. Wechselt man das Theme, verschwindet ihr Code, ein Plugin bleibt erhalten.
Welche PHP-Version sollte mein Plugin unterstützen?
Orientieren Sie sich an den Mindestanforderungen, die WordPress selbst aktuell angibt, und an den Versionen, die Ihre Zielgruppe tatsächlich nutzt. Im Plugin-Header legen Sie mit Requires PHP fest, ab welcher Version Ihr Plugin aktiviert werden darf.
Muss ein Plugin im offiziellen Verzeichnis kostenlos sein?
Der Eintrag selbst ist kostenlos und der dort angebotene Code muss vollständig nutzbar sein. Erlaubt ist ein kostenloses Plugin, zu dem es außerhalb des Verzeichnisses eine kostenpflichtige Erweiterung gibt. Nicht erlaubt sind künstlich gesperrte Funktionen im kostenlosen Code, die erst nach Bezahlung freigeschaltet werden.