WordPress: vom Einstieg bis zur Entwicklung · Modul 6: REST API und Headless

Lektion 3 von 5Übung 16 Min.

Eigene Endpunkte entwickeln

Lernziele
  • eigene Routen mit register_rest_route anlegen
  • Parameter deklarieren, prüfen und bereinigen
  • Antworten und Fehler sauber zurückgeben
  • entscheiden, wann ein eigener Endpunkt nötig ist

Die Standardrouten decken Inhalte ab, aber keine Geschäftslogik. Sobald etwas berechnet, geprüft oder aus mehreren Quellen zusammengeführt werden soll – freie Plätze, ein Preis mit Rabatt, eine Buchung mit Bestätigungsmail –, ist ein eigener Endpunkt der richtige Weg. Diese Lektion zeigt, wie Sie eine Route anlegen, wie Sie Eingaben absichern und wie eine Antwort aussieht, mit der andere Systeme gut arbeiten können.

1. Wann ein eigener Endpunkt?

ÜbungStandardroute, Metafeld oder eigener Endpunkt?
  1. Blogbeiträge für eine App abrufen

  2. Die Dauer eines Kurses in der Antwort mitliefern

  3. Freie Plätze aus drei Tabellen berechnen und als eine Zahl liefern

  4. Eine Buchung anlegen, dabei Verfügbarkeit prüfen und eine Mail senden

0 von 4 eingeschätzt

Eine gute Faustregel: Geht es um eine Ressource, die WordPress schon kennt, erweitern Sie die vorhandene Route – mit register_post_meta oder register_rest_field. Geht es um einen Vorgang, also ein Verb wie „buchen“, „prüfen“, „berechnen“, gehört das in eine eigene Route. Das hält die Schnittstelle verständlich und vermeidet Doppelarbeit.

2. Eine Route anlegen

Definition 3.1
register_rest_route
Die Funktion, mit der Plugins eigene Routen registrieren – auf dem Hook rest_api_init. Sie erwartet einen Namensraum mit Version (radwerk/v1), ein Routenmuster und eine Beschreibung mit Methode, Callback, Rechteprüfung und Parametern.
Baukastenregister_rest_route zusammenstellen
includes/Rest.php
1<?php
2add_action( 'rest_api_init', function () {
3 register_rest_route( 'radwerk/v1', '/termine/(?P<id>\d+)', [
4 'methods' => 'GET',
5 'callback' => 'radwerk_termine_lesen',
6 'permission_callback' => fn() => current_user_can( 'edit_posts' ),
7 'args' => [
8 'id' => [
9 'validate_callback' => fn( $w ) => is_numeric( $w ) && $w > 0,
10 'sanitize_callback' => 'absint',
11 ],
12 ],
13 ] );
14} );
15
16function radwerk_termine_lesen( WP_REST_Request $anfrage ) {
17 $id = (int) $anfrage['id'];
18
19 $treffer = get_transient( "radwerk_termin_$id" );
20 if ( false !== $treffer ) {
21 return rest_ensure_response( $treffer );
22 }
23
24 $daten = radwerk_termin_daten( $id );
25 if ( ! $daten ) {
26 return new WP_Error( 'nicht_gefunden', 'Termin unbekannt', [ 'status' => 404 ] );
27 }
28 set_transient( "radwerk_termin_$id", $daten, 5 * MINUTE_IN_SECONDS );
29
30 return rest_ensure_response( $daten );
31}
Mit Rechteprüfung: Nur angemeldete Konten mit passender Berechtigung kommen durch.

Der Namensraum verhindert Namenskollisionen und ermöglicht spätere Versionen: Eine radwerk/v2 kann neben v1 bestehen, sodass angebundene Systeme Zeit zum Umstellen haben. Im Routenmuster lassen sich Platzhalter mit regulären Ausdrücken definieren; (?P<id>\d+) bedeutet, dass an dieser Stelle eine Zahl erwartet wird, die später als Parameter id zur Verfügung steht.

3. Eingaben und Antworten

Jeder Parameter sollte in args deklariert werden. WordPress prüft dann selbst, ob Pflichtfelder vorhanden sind, ob der Typ stimmt und ob der Wert die Prüfung besteht – und antwortet andernfalls mit 400 und einer verständlichen Meldung, bevor Ihr Code überhaupt läuft. Für Antworten gilt: rest_ensure_response liefert ein sauberes Objekt, WP_Error mit Statuscode einen sauberen Fehler. Eigene Header, etwa für Gesamtzahlen bei Listen, lassen sich ergänzen.

Antwort mit Kopfzeilen und Schema
1<?php
2function radwerk_termine_liste( WP_REST_Request $anfrage ) {
3 $seite = (int) $anfrage->get_param( 'page' );
4 $treffer = radwerk_termine_suchen( $seite );
5
6 $antwort = rest_ensure_response( $treffer['eintraege'] );
7 $antwort->header( 'X-WP-Total', (string) $treffer['gesamt'] );
8 $antwort->header( 'X-WP-TotalPages', (string) ceil( $treffer['gesamt'] / 20 ) );
9
10 return $antwort;
11}
12
13// Schema beschreibt die Antwort – erscheint in der Selbstbeschreibung der API
14'schema' => fn() => [
15 'title' => 'termin',
16 'type' => 'object',
17 'properties' => [
18 'id' => [ 'type' => 'integer' ],
19 'titel' => [ 'type' => 'string' ],
20 'frei' => [ 'type' => 'integer', 'description' => 'freie Plätze' ],
21 ],
22],
VorhersageWelchen Statuscode liefert diese Anfrage?
Anfrage
1GET /wp-json/radwerk/v1/termine/abc
2
3// In der Route deklariert:
4'id' => [ 'validate_callback' => fn( $w ) => is_numeric( $w ) ]
Was gibt dieser Code aus? Wählen Sie eine Antwort.

4. Vorhandene Routen erweitern

Oft genügt es, eine Standardroute um eigene Felder zu ergänzen. register_rest_field fügt der Antwort ein berechnetes Feld hinzu, etwa die Lesezeit eines Beitrags oder die freien Plätze eines Kurses. Der Vorteil: Aufrufende arbeiten weiter mit der gewohnten Route, und alle Parameter wie _fields oder _embed funktionieren unverändert.

Ein berechnetes Feld ergänzen
1<?php
2add_action( 'rest_api_init', function () {
3 register_rest_field( 'radwerk_termin', 'freie_plaetze', [
4 'get_callback' => fn( $beitrag ) => radwerk_freie_plaetze( $beitrag['id'] ),
5 'schema' => [ 'type' => 'integer', 'context' => [ 'view' ] ],
6 ] );
7} );
Namensraum mit Version, Rechteprüfung an jeder Route, Parameter deklarieren statt selbst prüfen, Fehler als WP_Error mit Statuscode. Wer diese vier Regeln einhält, baut Schnittstellen, mit denen andere gern arbeiten.

5. Leistung und Stabilität

Eigene Endpunkte werden oft häufiger aufgerufen als gedacht – von einer App bei jedem Bildschirmwechsel, von einem Automatisierungsdienst im Minutentakt. Drei Maßnahmen halten sie stabil. Erstens Zwischenspeichern: Ergebnisse, die sich selten ändern, gehören in einen Transient mit kurzer Laufzeit. Zweitens Begrenzen: Listen immer seitenweise ausliefern, nie alles auf einmal. Drittens Abfangen: Wenn der Endpunkt selbst einen externen Dienst aufruft, braucht dieser Aufruf ein Zeitlimit und einen Rückfallwert, sonst hängt bei einer Störung die ganze Schnittstelle.

Zur Stabilität gehört auch eine kurze Dokumentation. Für jede eigene Route sollte festgehalten sein: Adresse, Methode, benötigte Rechte, Parameter mit Typ, Beispielantwort und mögliche Fehler. Ein Schema in der Registrierung erzeugt einen Teil davon automatisch – die Selbstbeschreibung unter /wp-json/radwerk/v1 zeigt dann alle Routen mit ihren Parametern.

6. Ein Beispiel

Ein Yogastudio hat eine App, in der Mitglieder Kurse buchen. Dafür gibt es drei eigene Routen: GET /kurse liefert die Kurse einer Woche mit freien Plätzen, POST /buchungen legt eine Buchung an und DELETE /buchungen/{id} storniert sie. Die Leseroute ist öffentlich und zwischengespeichert, die beiden anderen verlangen eine Anmeldung. Die Buchungsroute prüft in einem Schritt, ob der Kurs existiert, ob Plätze frei sind und ob nicht schon eine Buchung vorliegt; je nach Ergebnis antwortet sie mit 201, 409 oder 403. Die App muss dadurch keine Regeln kennen – sie stellt eine Anfrage und wertet den Statuscode aus.

7. Häufige Fragen

Warum bekomme ich 404 auf meine eigene Route? Meist wurde sie nicht auf rest_api_init registriert, oder das Plugin ist nicht aktiv. Prüfen Sie außerdem die Selbstbeschreibung unter /wp-json – erscheint Ihr Namensraum dort nicht, wird die Registrierung gar nicht ausgeführt.

Wie teste ich Endpunkte? Für lesende Routen genügt der Browser. Für schreibende eignen sich Werkzeuge wie Hoppscotch, Insomnia oder curl. In Tests lässt sich mit der Klasse WP_REST_Request eine Anfrage direkt im PHPUnit-Test auslösen, ohne HTTP.

Brauche ich für jede Route eine eigene Klasse? Nein, aber Struktur hilft: eine Klasse je Themenbereich mit einer Methode register_routes, die alle zugehörigen Routen anmeldet. So bleibt nachvollziehbar, welche Schnittstellen ein Plugin anbietet.

8. Übung zum Selbermachen

Legen Sie in Ihrem Übungsplugin die Route uebung/v1/statistik an, die die Anzahl veröffentlichter Beiträge, Seiten und Kommentare als JSON liefert – öffentlich lesbar. Ergänzen Sie danach eine zweite Route uebung/v1/notiz, die per POST einen Text entgegennimmt und in einer Option speichert; sie darf nur mit der Berechtigung manage_options ausführbar sein. Testen Sie beide Routen einmal angemeldet und einmal in einem privaten Fenster und vergleichen Sie die Statuscodes.

Quellen und weiterführende Literatur
  1. [1]WordPress.org (2026): REST API Handbook – Adding Custom Endpoints, Routes and Endpoints, Schema.
  2. [2]WordPress.org (2026): Code Reference – register_rest_route(), register_rest_field(), rest_ensure_response().
  3. [3]WordPress.org (2026): Plugin Security – Securing REST API Endpoints.

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.

Abschlussquiz

Drei Fragen – dann ist die Lektion geschafft.

Frage 1 von 3

Auf welchem Hook registriert man Routen?