Next.js-Entwickler in Bremen

Next.js vor einem WordPress-Backend für Bremer Unternehmen: REST API oder WPGraphQL, Entwurfsvorschau mit Draft Mode, Seiten neu bauen, wenn die Redaktion veröffentlicht, und was gegenüber einem klassischen Theme fehlt.

Next.js-Entwickler

Mein Platz in der WordPress-Community

  • Mein wordpress.org-Konto besteht seit 2006.
  • Ich habe zum WordPress-Core in den Versionen 7.0 und 7.1 beigetragen.
  • Ich betreue 30 Plugins auf wordpress.org.
  • Ich organisiere WordCamps und trete dort als Speaker auf.
  • Ich war bei jedem WordCamp Europe von 2017 bis 2026 dabei.

Mein WordPress.org-Profil

Mariusz Szatkowski hier, einzelner Entwickler aus Gdynia, mit WordPress seit 2006. Für Bremen schreibe ich über den Fall, den ich bei Next.js-Anfragen am häufigsten sehe: Ein WordPress mit eingespielter Redaktion bleibt, das öffentliche Frontend wird ein Next.js-Projekt. Alle Angaben zu WordPress stammen aus dem Entwicklerhandbuch, alle zu Next.js aus der Dokumentation auf nextjs.org. Die npm-Registry führt als neueste Version 16.4.6 mit Datum 9. November 2026.

Glockenspiel in der Böttcherstraße in Bremen

Foto: Dietmar Rabich, CC BY-SA 4.0, Wikimedia Commons.

#Was WordPress dem Frontend liefert

Bei einer REST-Anfrage an /wp/v2/posts gelten laut Handbuch zu den globalen Parametern zwei Stellschrauben, die über die Ladezeit des Frontends entscheiden.

  • _fields begrenzt die Antwort auf benannte Felder, etwa _fields=id,slug,title,link. WordPress überspringt dann die übrigen Felder, die Antwort wird kleiner und die Abfrage billiger. Seit WordPress 5.3 geht das auch für verschachtelte Felder wie einzelne Meta-Schlüssel.
  • _embed lädt verknüpfte Ressourcen mit, zum Beispiel Autor und Begriffe, in einer Anfrage statt in mehreren. Seit WordPress 5.4 lässt sich die Liste der Beziehungen begrenzen.

Ohne weitere Angabe liefert die Sammlung laut Referenz zu Beiträgen zehn Beiträge pro Seite und nur solche mit dem Status publish. Das ist für die Auslieferung richtig und für die Vorschau der Punkt, an dem man umstellen muss.

#REST oder WPGraphQL

WPGraphQL ist ein Plugin und kein Teil des Kerns. Die Entwickler vergleichen beides in der Seite WPGraphQL vs. WP REST API: GraphQL hat eine Spezifikation und ein streng typisiertes Schema, die REST API kann Felder und Endpunkte registrieren, erzwingt aber kein Schema, und viele Plugins tun es nicht.

REST APIWPGraphQL
HerkunftWordPress-KernPlugin
Antwort zuschneiden_fields, _embedFelder in der Abfrage
Schemawird nicht erzwungenstreng typisiert
SEO-Feldernur wenn das SEO-Plugin sie ausliefertErweiterungen für Yoast SEO, Rank Math, SEOPress
VorschauStatus und Autosaves per AnfrageHeader X-GraphQL-Preview

Die Erweiterungen für die SEO-Plugins stehen auf der Erweiterungsseite von WPGraphQL. Mein Vorgehen: Ich lese zuerst, welche Inhaltstypen und Plugins Ihr WordPress hat, und wähle danach. Bei einem schlanken Redaktionsauftritt reicht die REST API oft aus. Bei vielen eigenen Feldern und Beziehungen lohnt das typisierte Schema.

#Vorschau für Entwürfe mit Draft Mode

In einem klassischen Theme öffnet die Schaltfläche Vorschau den Entwurf auf derselben Seite. Im Headless-Aufbau gehört die Vorschau dem Frontend. WordPress lässt die Adresse über den Filter preview_post_link ändern, sodass die Schaltfläche auf Ihr Next.js zeigt.

Dort greift der Draft Mode. Ein Route Handler prüft ein gemeinsames Geheimnis und setzt das Cookie __prerender_bypass. Mit diesem Cookie überspringt fetch() den Next.js-Cache und fragt WordPress direkt, alle anderen Besucher sehen weiter die zwischengespeicherte Seite. Die Dokumentation nennt eine Falle, die ich in meinen Handlern beachte: Der Zielpfad kommt aus dem CMS und nicht aus dem Query-String, sonst entsteht eine offene Weiterleitung.

Der WordPress-Teil ist heikel, weil ein Entwurf nicht dasselbe ist wie eine ungespeicherte Änderung an einem veröffentlichten Beitrag:

  • Ein neuer Entwurf lässt sich über status abfragen. Der Parameter nimmt laut Referenz mehrere Werte, also etwa status=draft,publish. Der Server des Frontends braucht dafür eine Anmeldung, das Handbuch zur Authentifizierung nennt seit WordPress 5.6 die Application Passwords.
  • Die Änderungen an einem bereits veröffentlichten Beitrag liegen in dessen Autosave. Die Referenz zu Revisionen führt dafür GET /wp/v2/posts/<id>/autosaves auf.
  • Bei WPGraphQL übernimmt das ein Header. Die Seite zu Vorschauen beschreibt X-GraphQL-Preview: database_id=123, und WPGraphQL legt dann die Felder des neuesten Autosaves über den veröffentlichten Beitrag.

Dieselbe Seite nennt eine Grenze, die Sie vor dem Projekt kennen sollten: Die Anfrage muss als Nutzer authentifiziert sein, der den Beitrag bearbeiten darf. Ein Vorschau-Link für Personen ohne WordPress-Konto geht so nicht. Die Dokumentation beschreibt das Gegenmuster: Der Server des Frontends meldet sich mit eigenen Zugangsdaten bei WordPress an und schützt den Zugang selbst, etwa über ein Geheimnis.

#Veröffentlichen: vom WordPress-Hook zu revalidateTag

Für Inhalte aus einem CMS empfiehlt die Next.js-Seite zu Revalidating kein Zeitintervall, sondern ein langes Cache-Leben und einen Webhook: Die Quelle meldet die Änderung, revalidateTag entwertet die Daten. In WordPress gibt es dafür keinen Kern-Webhook, aber den Hook transition_post_status. Er läuft laut Handbuch bei jedem Statuswechsel, aber auch bei jedem Speichern, ohne dass der Status sich ändert. Das passt, denn die Redaktion speichert veröffentlichte Beiträge laufend nach.

add_action( 'transition_post_status', function ( $new, $old, $post ) {
	if ( 'publish' !== $new && 'publish' !== $old ) {
		return;
	}
	wp_remote_post( 'https://www.example.de/api/revalidate', array(
		'headers'  => array( 'x-revalidate-secret' => REVALIDATE_SECRET ),
		'body'     => array( 'tag' => 'posts' ),
		'blocking' => false,
	) );
}, 10, 3 );

Die Bedingung fängt auch das Zurückziehen eines Beitrags ab: Wer von publish auf draft wechselt, soll ebenfalls aus den Listen verschwinden. blocking steht laut Referenz zu wp_remote_post standardmäßig auf true; mit false wartet das Speichern im Editor nicht auf Next.js.

Auf der Next.js-Seite nimmt ein Route Handler den Aufruf entgegen:

// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache'

export async function POST(request: Request) {
  if (request.headers.get('x-revalidate-secret') !== process.env.REVALIDATE_SECRET) {
    return new Response('Unauthorized', { status: 401 })
  }
  const form = await request.formData()
  const tag = form.get('tag')
  if (typeof tag !== 'string') {
    return new Response('Missing tag', { status: 400 })
  }
  revalidateTag(tag, { expire: 0 })
  return Response.json({ revalidated: true })
}

Die Daten selbst bekommen ihr Etikett beim Abruf: fetch(url, { next: { tags: ['posts'] } }). Zwei Angaben der Dokumentation zu revalidateTag sind für diesen Aufbau wichtig. Erstens ist die Variante mit einem Argument veraltet, es braucht ein zweites. Zweitens markiert profile="max" die Daten nur als veraltet, und die nächste Anfrage bekommt noch den alten Stand, während im Hintergrund neu geladen wird. Für den Aufruf aus einem Webhook nennt die Seite ausdrücklich { expire: 0 }, damit die nächste Anfrage frische Daten holt. Eine Neuberechnung löst übrigens die Anfrage aus und nicht der Aufruf: Seiten laden nach, wenn sie besucht werden.

Mit einem Etikett für alle Beiträge ist das grob, aber robust. Feinere Etiketten pro Beitrag oder Kategorie lohnen sich erst bei vielen Seiten. Dazu kommt eine Grenze auf der WordPress-Seite: Laut bekannten Einschränkungen von WPGraphQL braucht WPGraphQL Smart Cache einen Hoster mit tag-basiertem Cache und dem Header X-GraphQL-Keys, den viele Hoster nicht bieten. Die Seite rät außerdem davon ab, beim Build alle Beiträge und Seiten abzurufen, weil das den WordPress-Server überlasten kann. Ich baue die wichtigsten Seiten vorab und lasse die übrigen beim ersten Aufruf entstehen.

#Bilder und SEO-Felder

Für Bilder liefert die Referenz zu Medien die Felder source_url, alt_text und media_details. Die Bildkomponente von Next.js verlangt bei entfernten Bildern laut Dokumentation eine Liste erlaubter Adressmuster in next.config.ts (remotePatterns, so konkret wie möglich) sowie Breite und Höhe, denn Next.js kennt die Datei beim Build nicht. Beides stammt aus media_details; wer die Maße weglässt, bekommt Layoutverschiebungen und verschlechtert den CLS-Wert. Als Zielwerte gelten die offiziellen Schwellen von web.dev: LCP bis 2,5 s, INP bis 200 ms, CLS bis 0,1.

Der WordPress-Kern kennt weder Meta-Titel noch Meta-Beschreibung. Diese Felder kommen aus Ihrem SEO-Plugin, und für WPGraphQL gibt es Erweiterungen für Yoast SEO, Rank Math und SEOPress. Bei der REST API muss das Plugin die Felder selbst ausliefern. Im Frontend übernimmt generateMetadata laut Dokumentation die Werte aus den abgerufenen Daten. Wichtig ist, dass Canonical, hreflang und strukturierte Daten nach dem Umzug nicht stillschweigend wegfallen. Die Liste prüfe ich vor dem Livegang Seite für Seite gegen die alte Website.

#Was die Redaktion gegenüber einem Theme verliert

Das gehört in jedes Gespräch, bevor ein Headless-Projekt beginnt:

  • Die Vorschau ist nicht mehr eingebaut. Sie ist ein Baustein, der gebaut, getestet und gepflegt werden muss. Für Personen ohne WordPress-Konto gibt es keinen Link, solange er nicht eigens gebaut wird.
  • Plugins, die im Theme etwas ausgeben, tun das nicht mehr von selbst. Ein Formular-, Karten- oder Buchungs-Plugin rendert im Theme. Im Next.js-Frontend braucht jedes eine eigene Lösung oder bleibt weg.
  • Neue Blöcke brauchen eine Entsprechung im Frontend. Was die Redaktion im Editor einfügt, ist erst dann sichtbar, wenn das Frontend es kennt.
  • Es gibt zwei Systeme, die laufen müssen. WordPress mit Updates und Sicherung bleibt, dazu kommt der Betrieb von Next.js.

Wenn Ihre Website im Kern aus Seiten und Beiträgen besteht und die Redaktion viel mit Plugins arbeitet, ist ein gut gebautes klassisches Theme oft die bessere Wahl. Dafür gibt es die Seite zu WordPress in Bremen. Für Inhaltsseiten ohne viel Interaktion beschreibe ich Astro in Bremen, und wer von Next.js auf ein schlankeres Frontend wechseln möchte, findet die Migration von Next.js zu Astro in Bremen.

#Zwei Server, zwei Empfänger: der LfDI Bremen

Bei einem Headless-Aufbau fließen Daten über zwei Systeme: das WordPress-Backend und den Server oder Dienst, der das Frontend ausliefert, dazu kommen die Webhook- und Vorschau-Anfragen dazwischen. Zuständig für Bremen und Bremerhaven ist der Landesbeauftragte für Datenschutz und Informationsfreiheit (LfDI Bremen). Auf seiner Seite zur Datenübermittlung in die USA steht: Seit dem Angemessenheitsbeschluss der EU-Kommission vom 10. Juli 2023 dürfen personenbezogene Daten an zertifizierte US-Empfänger übermittelt werden, ohne weitere Übermittlungsinstrumente. Voraussetzung ist, dass der Empfänger unter dem EU-US Data Privacy Framework zertifiziert ist, und das müssen Datenexporteure vorab prüfen; das US-Handelsministerium veröffentlicht dazu eine Liste.

Für Sie heißt das in der Praxis: Ich liste im schriftlichen Umfang auf, wo das WordPress läuft, wo das Frontend läuft und welche Dienste dazwischen Daten sehen, etwa ein Anbieter für Formulare oder Suche. Die Prüfung der Zertifizierung und die rechtliche Bewertung gehören zu Ihrer Rechtsberatung und Ihrem Datenschutzbeauftragten. Wie Next.js ohne US-Plattform betrieben werden kann, beschreibe ich auf den Seiten zum Self-Hosting.

#Checkliste vor dem Livegang

  1. REST oder WPGraphQL ist begründet, und _fields oder die Abfrage ziehen nur die Felder, die das Frontend zeigt.
  2. Die Vorschau-Adresse in WordPress zeigt auf das Frontend, der Handler prüft ein Geheimnis und liest den Zielpfad aus dem CMS.
  3. Neue Entwürfe und ungespeicherte Änderungen an veröffentlichten Beiträgen sind getestet, mit einem Redaktionskonto und mit einem Kollegen.
  4. Der Webhook läuft bei Veröffentlichen, Ändern und Zurückziehen, und das Geheimnis liegt nicht im Code.
  5. Jedes Plugin mit Ausgabe im Frontend hat eine Lösung oder ist bewusst gestrichen.
  6. Bilder haben Breite, Höhe und Alternativtext; remotePatterns ist eng gefasst.
  7. Meta-Titel, Meta-Beschreibung, Canonical, hreflang und strukturierte Daten sind gegen die alte Website geprüft.
  8. Die Liste der Systeme und Anbieter, die Daten sehen, ist geschrieben.

#So läuft ein Projekt mit mir

Alles läuft schriftlich: Ihre Anfrage, meine Rückfragen, ein Umfang mit Annahmen und Ausschlüssen, danach eine Staging-Adresse, auf der Redaktion und Geschäftsführung die Seiten selbst durchklicken. Ich bin ein einzelner Entwickler, arbeite remote und führe weder Besprechungen noch Telefonate. Das Layout liefern Sie oder Ihre Agentur; ich setze es um. Updates und kleine Änderungen übernehme ich auf Wunsch in der Wartung in Bremen, die Stunden eines Monats verfallen am Monatsende.

Zum Start brauche ich:

  • die Adresse Ihrer aktuellen Website und einen Zugang zum WordPress mit Redaktionsrechten,
  • die Liste der aktiven Plugins und der Formulare, Karten oder Buchungen auf der Website,
  • das Layout als Vorlage oder Tabelle,
  • den gewünschten Termin und Angaben, wer Inhalte pflegt.

#Fragen aus Bremer Anfragen

REST API oder WPGraphQL? Beides geht. Die REST API steckt im WordPress-Kern, mit _fields und _embed lässt sich die Antwort zuschneiden. WPGraphQL ist ein Plugin mit streng typisiertem Schema und Erweiterungen für SEO-Plugins. Ich entscheide nach Ihren Inhaltstypen und Plugins, nicht nach Geschmack.

Warum sehe ich nach dem Veröffentlichen noch den alten Stand? Weil revalidateTag mit profile="max" nur markiert und die nächste Anfrage noch die alte Seite bekommt, während im Hintergrund neu gebaut wird. Aus einem Webhook rufe ich revalidateTag mit { expire: 0 } auf, dann holt die nächste Anfrage sofort frische Daten.

Kann ein Kollege ohne WordPress-Konto einen Entwurf ansehen? Über WPGraphQL nicht: Laut Dokumentation muss die Anfrage als Nutzer authentifiziert sein, der den Beitrag bearbeiten darf. Eine Freigabe per Link lässt sich im Frontend bauen, mit eigenem Geheimnis. Das ist ein eigener Baustein und gehört in den schriftlichen Umfang.

Woher kommen Meta-Titel und Meta-Beschreibung? Aus Ihrem SEO-Plugin. Der WordPress-Kern kennt dafür kein Feld. Für WPGraphQL gibt es Erweiterungen für Yoast SEO, Rank Math und SEOPress, bei REST muss das Plugin die Felder ausliefern. Next.js liest sie in generateMetadata aus.

Welche Aufsichtsbehörde ist in Bremen zuständig? Der Landesbeauftragte für Datenschutz und Informationsfreiheit der Freien Hansestadt Bremen, kurz LfDI Bremen. Auf seiner Seite zur Datenübermittlung in die USA steht, dass Verantwortliche vorab prüfen müssen, ob ein US-Empfänger unter dem EU-US Data Privacy Framework zertifiziert ist.

Gestalten Sie auch das Layout? Nein. Ein Layout liefere ich nicht, es stammt von Ihnen oder Ihrer Agentur. In einer Tabellenvorlage tragen Sie ein, welches Element wohin gehört, und ich baue daraus das responsive Frontend.

#Ihr Next.js-Vorhaben in Bremen

Ob ein Frontend, das nach dem Veröffentlichen sofort aktuell ist, eine Vorschau, mit der Ihre Redaktion zufrieden ist, oder zuerst die Frage, ob Headless für Sie überhaupt der richtige Weg ist: Schreiben Sie mir über das Kontaktformular. Nennen Sie die Adresse Ihrer aktuellen Website, das Ziel, den gewünschten Termin und die Plugins, auf die Ihre Redaktion nicht verzichten kann. Meine Antwort kommt schriftlich an einem Werktag; eine erste Einschätzung ist kostenlos. Weitere Leistungen: PHP in Bremen für ein Backend, das die Daten liefert, und Headless CMS für den Überblick über die Aufteilung.

Brauchen Sie die Leistung: Next.js-Entwickler in Bremen?

Beschreiben Sie Ihr Projekt per E-Mail. Antwort innerhalb von 48 Stunden.

Projekt beschreiben

Weitere WordPress-Dienste und Wissensbasis entdecken