~/wordpress-plugins/plugin-erstellen-grundgeruest/

WordPress-Plugin erstellen: Grundgerüst, Plugin-Header und erste Funktion

Vom leeren Ordner zum funktionierenden Plugin: Header, Ordnerstruktur, Aktivierungs-Hook, ein Shortcode mit Einstellung und eine saubere uninstall.php.

Ein WordPress-Plugin besteht im einfachsten Fall aus einem Ordner unter wp-content/plugins/ und einer PHP-Datei mit einem Kopfkommentar, in dem mindestens Plugin Name steht. Sobald die Datei dort liegt, zeigt WordPress das Plugin in der Plugin-Liste an und Sie können es aktivieren. In diesem Artikel bauen Sie ein kleines, aber vollständiges Plugin: mit Header, Schutz gegen Direktaufruf, Aktivierungslogik, einem Shortcode, einer gespeicherten Einstellung und sauberer Deinstallation.

Als Beispiel dient das Plugin „Hinweisbox“: Ein Shortcode [hinweisbox] gibt einen frei einstellbaren Hinweistext in einem Kasten aus.

Voraussetzungen

  • Eine lokale WordPress-Installation, etwa über @wordpress/env (Docker), eine Desktop-Lösung oder einen lokalen Webserver.
  • Grundkenntnisse in PHP. Für die Grundlagen der Sprachen hilft der Bereich Programmiergrundlagen.
  • In der wp-config.php der Testumgebung define( 'WP_DEBUG', true );, damit Hinweise und Warnungen sichtbar werden.

Entwickeln Sie nie auf einer Live-Website. Ein Syntaxfehler in einem aktiven Plugin kann die gesamte Seite lahmlegen.

Schritt 1: Ordner und Hauptdatei anlegen

Ordner- und Dateiname sollten zum späteren Slug passen, also nur Kleinbuchstaben, Ziffern und Bindestriche enthalten:

wp-content/plugins/hinweisbox/
├── hinweisbox.php
├── uninstall.php
├── includes/
│   └── admin.php
└── languages/

Die Hauptdatei beginnt mit dem Plugin-Header:

<?php
/**
 * Plugin Name:       Hinweisbox
 * Description:       Gibt per Shortcode einen einstellbaren Hinweistext aus.
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      7.4
 * Author:            Ihr Name
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       hinweisbox
 */

defined( 'ABSPATH' ) || exit;

define( 'HINWEISBOX_VERSION', '1.0.0' );
define( 'HINWEISBOX_PFAD', plugin_dir_path( __FILE__ ) );

defined( 'ABSPATH' ) || exit; beendet das Skript, wenn jemand die Datei direkt über ihre URL aufruft, statt sie über WordPress zu laden. Die Konstanten halten Version und Pfad an einer Stelle fest.

Die wichtigsten Header-Felder

Feld Bedeutung
Plugin Name Anzeigename, einzige Pflichtangabe
Description Kurzbeschreibung in der Plugin-Liste
Version aktuelle Versionsnummer Ihres Plugins
Requires at least niedrigste unterstützte WordPress-Version
Requires PHP niedrigste PHP-Version, darunter verweigert WordPress die Aktivierung
License, License URI Lizenz, für das offizielle Verzeichnis GPL-kompatibel
Text Domain Kennung für Übersetzungen, entspricht in der Regel dem Slug
Update URI verhindert Verwechslungen mit gleichnamigen Plugins aus dem Verzeichnis
Requires Plugins Slugs von Plugins, die vorher aktiv sein müssen

Schritt 2: Präfixe konsequent verwenden

Alle Plugins teilen sich einen gemeinsamen PHP-Namensraum. Heißt Ihre Funktion get_settings(), kollidiert sie früher oder später mit einem anderen Plugin. Deshalb erhalten alle Funktionen, Konstanten, Optionsnamen und Hooks ein eindeutiges Präfix, hier hinweisbox_. Alternativ deklarieren Sie einen eigenen PHP-Namespace am Dateianfang. Optionsnamen in der Datenbank brauchen das Präfix trotzdem.

Schritt 3: Aktivierung und Standardwerte

Beim Aktivieren soll das Plugin einen Standardtext speichern, falls noch keiner existiert:

register_activation_hook( __FILE__, 'hinweisbox_aktivieren' );

function hinweisbox_aktivieren() {
    if ( false === get_option( 'hinweisbox_text' ) ) {
        add_option( 'hinweisbox_text', 'Dieser Beitrag wird regelmäßig aktualisiert.' );
    }
}

register_activation_hook() muss in der Hauptdatei stehen und erhält deren Pfad. Der Aktivierungs-Hook läuft nur beim Aktivieren, nicht bei automatischen oder manuellen Updates. Logik, die nach jedem Update laufen soll, etwa Datenbankanpassungen, prüfen Sie besser über eine gespeicherte Versionsnummer.

Schritt 4: Die erste Funktion, ein Shortcode

add_action( 'init', 'hinweisbox_registrieren' );

function hinweisbox_registrieren() {
    add_shortcode( 'hinweisbox', 'hinweisbox_ausgabe' );
}

function hinweisbox_ausgabe( $atts ) {
    $atts = shortcode_atts(
        array( 'typ' => 'info' ),
        $atts,
        'hinweisbox'
    );

    $text = get_option( 'hinweisbox_text', '' );
    if ( '' === $text ) {
        return '';
    }

    return sprintf(
        '<div class="hinweisbox hinweisbox--%1$s">%2$s</div>',
        esc_attr( sanitize_key( $atts['typ'] ) ),
        esc_html( $text )
    );
}

Zwei Details sind wichtig. Erstens gibt ein Shortcode seinen Inhalt per return zurück und gibt ihn nie direkt mit echo aus, sonst landet er an der falschen Stelle der Seite. Zweitens wird alles, was ausgegeben wird, mit esc_html() oder esc_attr() maskiert. Warum das so wichtig ist, erklärt der Artikel WordPress-Plugin absichern.

add_action( 'init', ... ) ist bereits ein Hook: WordPress ruft Ihre Funktion zu einem festgelegten Zeitpunkt auf. Wie Actions und Filter zusammenspielen, zeigt der Artikel WordPress-Hooks erklärt.

Schritt 5: Eine Einstellungsseite

Den Text soll man im Adminbereich ändern können. Die Settings API übernimmt das Speichern inklusive Sicherheitsprüfung. Legen Sie den Code in includes/admin.php ab und binden Sie ihn in der Hauptdatei nur im Adminbereich ein:

if ( is_admin() ) {
    require_once HINWEISBOX_PFAD . 'includes/admin.php';
}
<?php
defined( 'ABSPATH' ) || exit;

add_action( 'admin_init', function () {
    register_setting( 'hinweisbox', 'hinweisbox_text', array(
        'type'              => 'string',
        'sanitize_callback' => 'sanitize_text_field',
    ) );
} );

add_action( 'admin_menu', function () {
    add_options_page( 'Hinweisbox', 'Hinweisbox', 'manage_options', 'hinweisbox', 'hinweisbox_seite' );
} );

function hinweisbox_seite() {
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }
    ?>
    <div class="wrap">
        <h1>Hinweisbox</h1>
        <form method="post" action="options.php">
            <?php settings_fields( 'hinweisbox' ); ?>
            <input type="text" class="regular-text" name="hinweisbox_text"
                   value="<?php echo esc_attr( get_option( 'hinweisbox_text', '' ) ); ?>">
            <?php submit_button(); ?>
        </form>
    </div>
    <?php
}

settings_fields() erzeugt die nötigen versteckten Felder samt Nonce, register_setting() sorgt mit dem sanitize_callback dafür, dass nur bereinigter Text in der Datenbank landet. Die Seite erscheint unter „Einstellungen“.

Schritt 6: Sauber deinstallieren

Wird das Plugin gelöscht, sollen keine Reste in der Datenbank bleiben. Dafür legen Sie eine uninstall.php an:

<?php
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
    exit;
}

delete_option( 'hinweisbox_text' );

Die Prüfung auf WP_UNINSTALL_PLUGIN stellt sicher, dass die Datei nur im Rahmen einer echten Deinstallation läuft. Beim bloßen Deaktivieren bleibt die Einstellung erhalten, damit Nutzer nach einer Reaktivierung nichts neu eingeben müssen.

Schritt 7: Übersetzbar machen

Texte für die Benutzeroberfläche schreiben Sie mit Übersetzungsfunktionen wie __( 'Text', 'hinweisbox' ) oder esc_html__(). Die Text Domain muss mit dem Header übereinstimmen. Rufen Sie solche Funktionen nicht zu früh auf, also nicht direkt beim Laden der Datei, sondern frühestens im init-Hook. Aktuelle WordPress-Versionen melden zu frühe Aufrufe als Hinweis. Für Plugins aus dem offiziellen Verzeichnis lädt WordPress die Übersetzungen von translate.wordpress.org automatisch.

Skripte und Styles richtig einbinden

Braucht die Hinweisbox eigenes CSS, laden Sie es über die Enqueue-Funktionen und nur dort, wo es gebraucht wird:

add_action( 'wp_enqueue_scripts', function () {
    wp_register_style(
        'hinweisbox',
        plugins_url( 'assets/hinweisbox.css', __FILE__ ),
        array(),
        HINWEISBOX_VERSION
    );
} );

In der Shortcode-Funktion rufen Sie dann wp_enqueue_style( 'hinweisbox' ); auf. So landet die Datei nur auf Seiten, auf denen der Shortcode tatsächlich vorkommt. Die Versionsnummer als vierter Parameter sorgt dafür, dass Browser nach einem Update die neue Datei laden statt einer zwischengespeicherten.

Wenn das Plugin wächst

Ein einzelnes Dokument mit Funktionen wird schnell unübersichtlich. Bewährt haben sich einige Grundsätze:

  • Hauptdatei schlank halten: Sie enthält Header, Konstanten, Aktivierungs-Hooks und lädt die übrigen Dateien.
  • Nach Aufgaben trennen: Code für den Adminbereich, das Frontend, die REST API und den Datenzugriff in eigene Dateien oder Klassen legen.
  • Adminbereich nur bei Bedarf laden: wie oben mit is_admin(), damit das Frontend keinen unnötigen Code verarbeitet.
  • Autoloading nutzen: Wer Composer verwendet, kann Klassen per PSR-4 automatisch laden lassen und den Ordner vendor/ mit ausliefern. Achten Sie dann auf eindeutige Namespaces, damit gleichnamige Bibliotheken anderer Plugins nicht kollidieren.
  • Coding Standards anwenden: Die WordPress-Coding-Standards für PHP_CodeSniffer finden Stil- und viele Sicherheitsprobleme automatisch.

Fehler finden

Neben WP_DEBUG hilft WP_DEBUG_LOG, das Fehler in die Datei wp-content/debug.log schreibt, statt sie auf der Seite anzuzeigen. Mit error_log( print_r( $variable, true ) ); geben Sie dort eigene Werte aus. Debug-Plugins zeigen zusätzlich Datenbankabfragen, ausgelöste Hooks und geladene Skripte eines Seitenaufrufs an. Entfernen Sie alle Debug-Ausgaben, bevor Sie das Plugin weitergeben.

Häufige Anfängerfehler

  • Leerzeichen oder Zeilen vor <?php in der Hauptdatei erzeugen „Headers already sent“-Fehler.
  • Fehlendes Präfix führt zu Fatal Errors, sobald ein anderes Plugin denselben Funktionsnamen nutzt.
  • Ausgabe per echo in Shortcodes und Filtern statt Rückgabe.
  • Daten beim Deaktivieren löschen statt erst bei der Deinstallation.
  • Skripte und Styles direkt per <script> ausgeben statt mit wp_enqueue_script() und wp_enqueue_style() im passenden Hook.
  • Kein schließendes ?> ist übrigens kein Fehler, sondern Empfehlung: Am Ende reiner PHP-Dateien verhindert das Weglassen versehentliche Ausgaben.

Wie es weitergeht

Mit diesem Grundgerüst haben Sie alle Bausteine, die fast jedes Plugin braucht. Als Nächstes lohnen sich die Hooks im Detail, eigene Blöcke für den Editor und die Sicherheitsfunktionen. Wenn Ihr Plugin anderen helfen kann, beschreibt der Artikel WordPress-Plugin im offiziellen Plugin-Verzeichnis veröffentlichen, wie Sie es über wordpress.org verteilen.

faq

Fragen und Antworten

Welche Angaben im Plugin-Header sind Pflicht?
Technisch nur Plugin Name. Für ein ernsthaftes Plugin sollten Sie zusätzlich Description, Version, Requires at least, Requires PHP, Author, License und Text Domain setzen. Für das offizielle Verzeichnis sind Lizenzangaben und eine passende readme.txt nötig.
Brauche ich für ein kleines Plugin eine Klasse?
Nein. Für wenige Funktionen reichen gut präfixierte Funktionen oder ein eigener PHP-Namespace. Klassen lohnen sich, sobald das Plugin wächst und Sie Code nach Aufgaben trennen wollen, etwa Adminbereich, Frontend und Datenzugriff.
Was ist der Unterschied zwischen Deaktivieren und Deinstallieren?
Beim Deaktivieren bleibt alles erhalten, das Plugin läuft nur nicht mehr. Das Deinstallieren geschieht, wenn jemand das Plugin im Adminbereich löscht. Erst dann sollten Sie eigene Optionen, Tabellen und geplante Aufgaben entfernen, und zwar in der uninstall.php.
Wo teste ich mein erstes Plugin am besten?
In einer lokalen WordPress-Installation, zum Beispiel mit dem offiziellen Werkzeug @wordpress/env oder einer anderen Docker- oder Desktop-Umgebung. Schalten Sie dort WP_DEBUG ein, damit Fehler und veraltete Funktionsaufrufe sofort angezeigt werden.