Bild von Saeid Samani
Saeid Samani
Saeid Samani ist Webentwickler, kreativer Denker und Unternehmer mit einem tiefen Verständnis für digitale Prozesse und moderne Webtechnologien. Er entwickelt durchdachte Webanwendungen, optimierte Benutzererlebnisse und skalierbare Lösungen, die Design, Funktionalität und Strategie miteinander verbinden. In seinem Blog teilt Saeid seine Erfahrungen aus der täglichen Praxis – von sauberem Code und effizientem Workflow bis hin zu Themen rund um Webentwicklung, Automatisierung und digitale Trends. Sein Stil: klar, pragmatisch und immer mit dem Ziel, Wissen greifbar und anwendbar zu machen. Abseits der Arbeit liebt er es, Neues zu lernen, Ideen auszuprobieren und Wege zu finden, Technologie sinnvoll im Alltag einzusetzen.

WordPress-Plugins selbst programmieren – Grundlagen, Hooks und REST-API erklärt

Ein eigenes WordPress-Plugin zu schreiben ist leichter, als viele denken. Statt Code-Snippets im Theme zu verstecken, lohnt sich eine saubere, modulare Lösung – update-sicher, wiederverwendbar und professionell versionierbar. In diesem Beitrag erfahren Sie, warum eigene Plugins so mächtig sind, wie Hooks (Actions & Filter) wirklich funktionieren und wie Sie mit einer klaren Struktur und einer einfachen REST-API im Handumdrehen Ihr erstes Plugin entwickeln – inklusive Praxistipps und Tool-Empfehlungen für einen sauberen Start.

Inhaltsverzeichnis

Warum ein eigenes WordPress-Plugin?

Viele Entwicklerinnen und Entwickler starten damit, kleinere Code-Snippets direkt ins Theme oder in die functions.php zu schreiben. Das funktioniert zwar kurzfristig – ist aber auf Dauer weder übersichtlich noch update-sicher.
Sobald du eigene Funktionen, Integrationen oder Anpassungen regelmäßig nutzt, lohnt es sich, daraus ein eigenes Plugin zu machen.

Ein Plugin ist im Grunde nichts anderes als ein kleines, eigenständiges PHP-Programm, das WordPress um bestimmte Funktionen erweitert. Es ist sauber gekapselt, kann bei Bedarf aktiviert oder deaktiviert werden und bleibt beim Theme- oder Core-Update vollständig erhalten.

Die wichtigsten Vorteile auf einen Blick:

  • Update-Sicherheit:
    Alle Anpassungen liegen außerhalb deines Themes. Wenn du das Theme wechselst oder aktualisierst, bleibt dein Plugin unverändert bestehen.
  • Wiederverwendbarkeit:
    Einmal gut strukturiert, kannst du dein Plugin in mehreren Projekten einsetzen oder sogar veröffentlichen – etwa auf GitHub oder im offiziellen WordPress-Plugin-Verzeichnis.
  • Bessere Wartbarkeit:
    Durch eine klare Dateistruktur und sauberen Code trennst du Logik von Darstellung. Das erleichtert das Debuggen und spätere Erweiterungen.
  • Teamfähigkeit und Versionierung:
    Wenn du im Team arbeitest, ist ein Plugin die ideale Einheit, um mit Tools wie Git zu versionieren, Features zu testen und stabile Releases zu erstellen.
  • Klar definierter Funktionsumfang:
    Du kannst dich auf eine konkrete Aufgabe konzentrieren: z. B. ein Kontaktformular, ein REST-API-Interface, ein Dashboard-Widget oder eine Schnittstelle zu externen Diensten.
  • Schnellere Fehlersuche:
    Fehler in Themes sind oft schwer einzugrenzen. Ein Plugin lässt sich hingegen isoliert deaktivieren oder gezielt prüfen, ohne das ganze Frontend zu beeinträchtigen.
  • Rechtliche und datenschutzrechtliche Kontrolle:
    Besonders in Zeiten der DSGVO ist es hilfreich, eigene Lösungen zu haben, bei denen du genau weißt, welche Daten erhoben und verarbeitet werden. Ein selbst geschriebenes Plugin gibt dir diese Transparenz.
  • Lern- und Qualitätsgewinn:
    Wer eigene Plugins entwickelt, lernt WordPress auf einer tieferen Ebene kennen – etwa wie Hooks, Actions, Filter, REST-Routen und Datenbankabfragen wirklich funktionieren. Dieses Verständnis macht dich langfristig zu einem besseren Entwickler.

Wann lohnt sich ein eigenes Plugin?

  • Wenn du eine Funktion brauchst, die dein Theme nicht bietet, aber projektübergreifend nützlich ist.
  • Wenn du externe APIs anbinden möchtest (z. B. CRM, Newsletter, Chatbots).
  • Wenn du Admin-Oberflächen für eigene Optionen, Shortcodes oder Widgets bauen willst.
  • Wenn du sensible Daten oder Prozesse in einer kontrollierten Umgebung halten möchtest (statt sie an Plugins Dritter auszulagern).
  • Oder ganz einfach: Wenn du Ordnung und Kontrolle in deinem Code bevorzugst.

Kurz gesagt:
Ein eigenes Plugin ist wie ein kleiner, unabhängiger „Mikrodienst“ innerhalb deiner WordPress-Installation. Du entscheidest, was es kann, wann es läuft und wie es gepflegt wird – ohne dass Theme- oder Core-Updates dir dazwischenfunken.

Und das Beste: Schon wenige Zeilen PHP genügen, um zu starten. Mit klarer Struktur, einigen Hooks und einem einfachen Bootstrap kannst du von Beginn an professionell entwickeln, statt nur Code-Fragmente zu verwalten.

Hooks in WordPress – was sie eigentlich sind

Stell dir WordPress wie eine Veranstaltung vor. Der Core ruft während des Ablaufs viele „Programmpunkte“ auf: Seite laden, Beitrag speichern, Inhalt ausgeben usw. Hooks sind offizielle „Andockpunkte“ in diesem Ablauf, an denen du dich einklinken darfst, ohne Core-Dateien zu verändern.

  • Actions = Tu etwas, wenn Ereignis X passiert.
    Beispiele: „Wenn ein Beitrag gespeichert wurde, schreibe ein Log“, „Beim Initialisieren lade meine Übersetzungen“.
  • Filters = Verändere ein Stück Daten, bevor es weitergereicht/ausgegeben wird.
    Beispiele: „Hänge ein Icon vor den Titel“, „Formatiere den Auszug anders“.

Merke:

  • Actions haben kein Rückgabewert-Zwang (du führst Code aus).
  • Filters müssen zurückgeben, was sie verarbeiten (häufig: den modifizierten String/Array).

Mini-Beispiele

// Action: läuft bei jedem Seitenaufruf (nach Setup) einmal
add_action('init', function () {
    // z. B. Custom-Post-Type registrieren
});

// Filter: ändert Titel im Frontend
add_filter('the_title', function ($title) {
    if (is_admin()) return $title;
    return '🔧 ' . $title;
});

Eigene Hooks bereitstellen

Plugins können selbst Erweiterungspunkte schaffen:

do_action('mein_plugin/nach_aufgabe', $objektId);

$wert = apply_filters('mein_plugin/wert_anpassen', $wert, $kontext);

So machst du dein Plugin offen für andere Plugins/Themes – ohne enge Kopplung.

Empfohlene Plugin-Struktur (übersichtlich & skalierbar)

mein-plugin/
├─ mein-plugin.php // Plugin-Header + Bootstrap
├─ src/
│ ├─ Admin/ // Admin-spezifische Klassen
│ ├─ Frontend/ // Frontend-spezifische Klassen
│ ├─ Api/ // REST-Controller
│ └─ Bootstrap.php // Hooks registrieren
├─ assets/ // CSS/JS/Bilder
├─ languages/ // i18n (.pot/.po/.mo)
└─ uninstall.php // Aufräumen bei Deinstallation
  • Sicherheit & Qualität: Nonces (bei Formularen), Daten sanitizen (z. B. sanitize_text_field), Ausgaben escapen (esc_html, esc_attr), nur benötigte Assets laden, Textdomain für Übersetzungen nutzen.
  • Git kurz & knapp: Repo anlegen, regelmäßig committen, Releases taggen – mehr braucht es am Anfang nicht.

Kurzes REST-API-Beispiel (GET & POST)

Ziel:

  • GET liefert alle Beiträge aus der Kategorie „programmierung“ (optional via Query-Param änderbar).
  • POST nimmt Parameter entgegen (Kategorie & Anzahl) und liefert entsprechend gefilterte Beiträge.

Lege die Datei src/Api/Posts_Controller.php an und binde sie in deinem mein-plugin.php ein.

<?php
/**
* Plugin Name: Beispiel Plugin – REST API Demo
* Description: Minimalbeispiel für Hooks & REST-Routen.
* Version: 1.0.0
* Author: Dein Name
* Text Domain: beispiel-rest
*/

defined('ABSPATH') || exit;

// Autoload oder require der Controller-Datei:
require __DIR__ . '/src/Api/Posts_Controller.php';

add_action('rest_api_init', function () {
(new \MeinPlugin\Api\Posts_Controller())->register_routes();
});
<?php
// Datei: src/Api/Posts_Controller.php
namespace MeinPlugin\Api;

defined('ABSPATH') || exit;

class Posts_Controller {

    const NS = 'meinplugin/v1';

    public function register_routes() {
        // GET /wp-json/meinplugin/v1/posts
        register_rest_route(self::NS, '/posts', [
            'methods'             => 'GET',
            'callback'            => [$this, 'get_posts_by_category'],
            'permission_callback' => '__return_true', // öffentlich lesbar
            'args'                => [
                'category' => [
                    'description' => 'Kategoriename oder -slug',
                    'type'        => 'string',
                    'required'    => false,
                ],
                'per_page' => [
                    'description' => 'Anzahl der Beiträge',
                    'type'        => 'integer',
                    'required'    => false,
                ],
            ],
        ]);

        // POST /wp-json/meinplugin/v1/posts/filter
        register_rest_route(self::NS, '/posts/filter', [
            'methods'             => 'POST',
            'callback'            => [$this, 'post_filter_posts'],
            'permission_callback' => '__return_true', // bei Bedarf absichern
            'args'                => [
                'category' => [
                    'description' => 'Kategoriename oder -slug',
                    'type'        => 'string',
                    'required'    => false,
                ],
                'per_page' => [
                    'description' => 'Anzahl der Beiträge',
                    'type'        => 'integer',
                    'required'    => false,
                ],
            ],
        ]);
    }

    /**
     * GET: Liste Beiträge aus Kategorie (default: "programmierung").
     */
    public function get_posts_by_category(\WP_REST_Request $request) {
        $category = $request->get_param('category');
        $category = $category ? sanitize_text_field($category) : 'programmierung';

        $per_page = $request->get_param('per_page');
        $per_page = $per_page !== null ? absint($per_page) : -1; // alle

        $q = new \WP_Query([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'category_name'  => $category,   // Kategoriename oder Slug
            'posts_per_page' => $per_page,
            'no_found_rows'  => true,
        ]);

        $items = array_map([$this, 'map_post'], $q->posts);
        return rest_ensure_response([
            'category' => $category,
            'count'    => count($items),
            'items'    => $items,
        ]);
    }

    /**
     * POST: Nimmt "category" & "per_page" an, liefert gefilterte Beiträge.
     * Body kann JSON oder form-data sein.
     */
    public function post_filter_posts(\WP_REST_Request $request) {
        $params   = $request->get_json_params() ?: $request->get_body_params();
        $category = isset($params['category']) ? sanitize_text_field($params['category']) : 'programmierung';
        $per_page = isset($params['per_page']) ? absint($params['per_page']) : 5;

        $q = new \WP_Query([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'category_name'  => $category,
            'posts_per_page' => $per_page,
            'no_found_rows'  => true,
        ]);

        $items = array_map([$this, 'map_post'], $q->posts);
        return rest_ensure_response([
            'category' => $category,
            'count'    => count($items),
            'items'    => $items,
        ]);
    }

    private function map_post(\WP_Post $p): array {
        return [
            'id'        => $p->ID,
            'title'     => get_the_title($p),
            'permalink' => get_permalink($p),
            'date'      => get_the_date('c', $p),
            'excerpt'   => wp_strip_all_tags(get_the_excerpt($p)),
        ];
    }
}

Testen (Beispiele):

  • GET: https://deinedomain.tld/wp-json/meinplugin/v1/posts?category=programmierung&per_page=10
  • POST: POST https://deinedomain.tld/wp-json/meinplugin/v1/posts/filter
    JSON-Body: { "category": "programmierung", "per_page": 3 }

Hinweis Sicherheit: Für schreibende/administrative Endpunkte solltest du permission_callback härten (z. B. current_user_can('edit_posts')) und Nonces/Tokens prüfen. Für reine Lese-Endpoints ist __return_true üblich, solange keine sensiblen Daten ausgegeben werden.

Zum Start: Boilerplate-Generator

Für einen schnellen, strukturierten Einstieg empfehle ich den WordPress Plugin Boilerplate Generator: wppb.me – erzeugt dir sofort ein sauberes Grundgerüst mit Loader, i18n und sinnvollen Ordnern. Perfekt, um direkt mit deinen Hooks & REST-Routen loszulegen.