Traditionelles WordPress: ein Stack. WordPress PHP rendert alles — Frontend-Seiten, Admin-Bildschirme, REST API. Ihr Theme kümmert sich sowohl um die Inhaltsbearbeitung (über das Admin-Panel) als auch um die Frontend-Darstellung (über PHP-Vorlagen).
Headless WordPress: zwei Stacks. WordPress kümmert sich um die Inhaltsbearbeitung und Datenspeicherung. Ein separates JavaScript-Frontend (das auf Vercel, Netlify, Cloudflare Pages usw. läuft) ruft Inhalte von WordPress über die REST API oder GraphQL ab und rendert Seiten unabhängig.
“` Traditionell: [ WordPress ] → Inhalt → Frontend (PHP-Vorlagen) ↑ ↑ └──── derselbe Server ─────────┘
Headless: [ WordPress ] → Inhalt → [ JavaScript Frontend ] (CMS) (API) (Next.js / Astro / usw.) “`
Für die meisten WordPress-Seiten ist traditionelles WordPress immer noch die richtige Wahl. Headless ist die richtige Wahl, wenn Sie seine spezifischen Vorteile benötigen und die Komplexität akzeptieren.
Benutzerdefinierte Felder sind einer der größten Reibungspunkte in headless WordPress. Hier ist der Grund.
Der WordPress-Kern hat Standardfelder — Titel, Inhalt, Auszug, Beitragsbild, Autor, Datum. Diese sind gut definiert, konsistent über alle WordPress-Seiten hinweg und werden vollständig von headless Frontend-SDKs unterstützt (wp-rest-api-Clientbibliotheken, WPGraphQL usw.).
Benutzerdefinierte Felder sind plugin-definiert. ACF fügt seine eigenen Felder hinzu, die auf eigene Weise gespeichert werden und über eine eigene API bereitgestellt werden. Meta Box macht dasselbe. Pods, Toolset, CMB2, Carbon Fields — jeder hat seinen eigenen Ansatz.
Frontend-SDKs wissen nichts über benutzerdefinierte Felder, weil sie es nicht können — die Definitionen leben im Plugin-Code, nicht im Kern von WordPress.
TypeScript kann benutzerdefinierte Feldtypen nicht aus einer WordPress-API-Antwort ableiten. Ein fetch('/wp-json/wp/v2/posts/123')-Aufruf gibt ein generisches Post-Objekt plus eine „ACF“-Eigenschaft mit den Feldern zurück, die das Plugin hinzugefügt hat. TypeScript sieht dies als any oder Record.
Das Ergebnis: data.custom_fields.hero_title kompiliert gut, selbst wenn das Feld hero_headline heißt. Tippfehler werden zu Laufzeitfehlern.
Ein Entwickler fügt eine neue Feldgruppe in seinem lokalen WordPress hinzu. Sie pushen den Code in die Staging-Umgebung. Das Staging-WordPress hat diese Feldgruppe noch nicht. Der Frontend-Code, der das neue Feld erwartet, bricht.
Ohne Schema-Synchronisation wird headless WordPress zum Debugging-Albtraum.
Die REST API von WordPress gibt benutzerdefinierte Felder inkonsistent aus:
meta aus (Standardverhalten des WP-Kerns)acf aus (ACF-Integration)Für eine Next.js-Komponente, die einen Hero-Block rendert, sind möglicherweise 3 separate API-Aufrufe erforderlich: einer für den Beitrag, einer für das Beitragsbild, einer für den verwandten Beitrag, der in einem Beziehungsfeld referenziert wird. Das ist langsam und komplex.
GraphQL (über WPGraphQL) ist besser für headless geeignet, da es Ihnen ermöglicht, tief verschachtelte Daten in einer einzigen Anfrage abzufragen. Aber WPGraphQL kennt keine benutzerdefinierten Felder — Sie benötigen ein separates „WPGraphQL für ACF“-Plugin, um die Lücke zu schließen, und es wird unabhängig gewartet, sodass es hinter ACF-Updates zurückbleibt.
Field Forge wurde mit headless WordPress im Hinterkopf entwickelt. Es adressiert jeden der oben genannten Schmerzpunkte.
Anstelle von wp_postmeta speichert Field Forge Feldwerte in einer speziellen indizierten Tabelle. API-Antworten, die benutzerdefinierte Felder abrufen, sind dramatisch schneller — 3–10x schneller auf großen Seiten. Für headless Workflows, bei denen das Frontend bei jedem Build (oder jeder Anfrage für SSR) Inhalte von WordPress abruft, ist dies wichtig.
Benutzerdefinierte Tabellenspeicherfunktion →
Field Forge generiert automatisch .d.ts-TypeScript-Definitionen für jede Feldgruppe. Laden Sie die Datei herunter, committen Sie sie in Ihr Frontend-Repo und erhalten Sie vollständige Typensicherheit:
“`typescript import type { HeroSectionFields } from ‘@/types/fieldforge’;
function Hero({ data }: { data: HeroSectionFields }) { return
; // TypeScript-Autovervollständigung + Fehlerprüfung } “`
Typen werden automatisch aktualisiert, wenn Sie Feldgruppen bearbeiten. Führen Sie den TypeScript-Export erneut aus, um zu synchronisieren.
TypeScript-Generierungsfunktion →
Wenn Field Forge und WPGraphQL beide aktiv sind, registriert Field Forge automatisch GraphQL-Typen für jede Feldgruppe bei der Aktivierung. Null Konfiguration. Benutzerdefinierte Felder werden sofort abfragbar:
“graphql query GetPage { page(id: "home", idType: URI) { title fieldforge { heroSection { title subtitle backgroundImage { sourceUrl } } } } } “
Kein separates WPGraphQL für ACF-Plugin erforderlich.
GraphQL-Generierungsfunktion →
Field Forge gibt benutzerdefinierte Feldwerte an den Kern-REST-Endpunkten unter einer fieldforge-Eigenschaft aus:
“`json GET /wp-json/wp/v2/posts/123
{ “id”: 123, “title”: { “rendered”: “Unsere Dienstleistungen” }, “fieldforge”: { “service_list”: [ { “name”: “Webdesign”, “description”: “…” }, { “name”: “SEO”, “description”: “…” } ] } } “`
Ein API-Aufruf gibt den Beitrag + alle benutzerdefinierten Felder zurück. Kein N+1-Problem.
Field Forges Local JSON Sync speichert Feldgruppen als JSON-Dateien in Ihrem Theme-Verzeichnis. Committen Sie in git. Bereitstellung über Umgebungen hinweg. Dev, Staging und Produktion haben immer dasselbe Schema.
Hier ist ein vollständiger Einrichtungsleitfaden für Next.js mit Field Forge.
“bash npx create-next-app@latest my-headless-site --typescript --app cd my-headless-site “
Erstellen Sie lib/wordpress.ts:
“`typescript const WP_API_URL = process.env.WP_API_URL || ‘https://wp.example.com/wp-json’;
export async function fetchPost(slug: string) { const res = await fetch(${WP_API_URL}/wp/v2/posts?slug=${slug}); const posts = await res.json(); return posts[0]; }
export async function fetchPage(slug: string) { const res = await fetch(${WP_API_URL}/wp/v2/pages?slug=${slug}); const pages = await res.json(); return pages[0]; } “`
Laden Sie die .d.ts-Datei aus dem Field Forge-Adminbereich herunter: Field Forge → Tools → TypeScript Export → Download.
Speichern Sie in types/fieldforge.d.ts:
“`typescript export interface WPImage { id: number; url: string; alt: string; sizes: { thumbnail: string; medium: string; large: string; full: string; }; }
export interface HeroSectionFields { title: string; subtitle: string; background_image: WPImage; cta_button: { text: string; url: string; }; }
export interface PageWithFields { id: number; title: { rendered: string }; fieldforge: { hero_section?: HeroSectionFields; }; } “`
app/[slug]/page.tsx:
“`typescript import { fetchPage } from ‘@/lib/wordpress’; import type { PageWithFields, HeroSectionFields } from ‘@/types/fieldforge’;
export default async function Page({ params }: { params: { slug: string } }) { const page: PageWithFields = await fetchPage(params.slug);
return (
{page.fieldforge.hero_section && ( )} ); }
function Hero({ data }: { data: HeroSectionFields }) { return (
{data.subtitle}
); } “`
Das ist eine minimale Next.js + Field Forge-Einrichtung. TypeScript-Autovervollständigung funktioniert. Die Umbenennung von Feldnamen ist sicher. Der Build schlägt fehl, wenn Sie eine Eigenschaft falsch schreiben.
generateStaticParamsFür die statische Seitengenerierung (schnellste Option) rufen Sie alle Seiten zur Build-Zeit ab:
“typescript export async function generateStaticParams() { const res = await fetch(${WP_API_URL}/wp/v2/pages`); const pages = await res.json();
return pages.map((page: any) => ({ slug: page.slug, })); } “`
Next.js wird jede Seite zur Build-Zeit als statisches HTML vor-rendern.
Astro ist hervorragend für Inhaltsseiten mit headless WordPress.
“bash npm create astro@latest my-site cd my-site “
Erstellen Sie src/lib/wordpress.ts:
“`typescript const WP_API_URL = import.meta.env.WP_API_URL;
export async function getPages() { const res = await fetch(${WP_API_URL}/wp/v2/pages); return res.json(); }
export async function getPageBySlug(slug: string) { const res = await fetch(${WP_API_URL}/wp/v2/pages?slug=${slug}); const [page] = await res.json(); return page; } “`
src/pages/[slug].astro:
“`astro
import { getPages, getPageBySlug } from ‘@/lib/wordpress’; import type { PageWithFields } from ‘@/types/fieldforge’; import Hero from ‘@/components/Hero.astro’;
export async function getStaticPaths() { const pages = await getPages(); return pages.map((page: any) => ({ params: { slug: page.slug }, props: { page }, })); }
const { page } = Astro.props as { page: PageWithFields };
{page.fieldforge.hero_section && ( )} “`
Astros statische Generierung funktioniert gut mit Field Forges REST API — ein Build, alle Inhalte abgerufen, statisches HTML ausgegeben.
Für Vue-Entwickler ist Nuxt das bevorzugte headless WordPress-Framework.
“bash npx nuxi@latest init my-site cd my-site “
server/api/page/[slug].get.ts:
“`typescript export default defineEventHandler(async (event) => { const { slug } = getRouterParams(event); const config = useRuntimeConfig();
const response = await $fetch( ${config.wpApiUrl}/wp/v2/pages?slug=${slug} );
return response[0]; }); “`
pages/[slug].vue:
“`vue
import type { PageWithFields } from '@/types/fieldforge';
const route = useRoute(); const { data: page } = await useFetch(/api/page/${route.params.slug}); “`
Für Svelte-Fans:
“`typescript // src/routes/[slug]/+page.server.ts import type { PageServerLoad } from ‘./$types’; import type { PageWithFields } from ‘$lib/types/fieldforge’;
export const load: PageServerLoad = async ({ params, fetch }) => { const res = await fetch(${WP_API_URL}/wp/v2/pages?slug=${params.slug}); const pages = await res.json(); const page: PageWithFields = pages[0];
return { page }; }; “`
“`svelte import type { PageData } from './$types'; import Hero from '$lib/components/Hero.svelte';
export let data: PageData;
{#if data.page.fieldforge.hero_section} {/if} “`
Für Seiten, die tief verschachtelte Abfragen benötigen, ist GraphQL effizienter als REST:
“typescript async function fetchHomepage() { const query = query GetHomepage { page(id: “home”, idType: URI) { title fieldforge { heroSection { title subtitle backgroundImage { sourceUrl altText } ctaButton { text url } } } } } `;
const res = await fetch(${WP_API_URL}/graphql, { method: ‘POST’, headers: { ‘Content-Type’: ‘application/json’ }, body: JSON.stringify({ query }), });
const { data } = await res.json(); return data.page; } “`
Eine Anfrage ruft die gesamte Seite einschließlich benutzerdefinierter Felder ab. Kein N+1-Problem.
Sollte ich REST oder GraphQL mit headless WordPress verwenden? Hängt vom Frontend und der Komplexität ab. REST ist einfacher einzurichten. GraphQL ist effizienter für tief verschachtelte Abfragen und reduziert das Überladen von Daten. Für kleine Seiten, REST. Für Seiten mit komplexen Inhaltsstrukturen, GraphQL.
Wie gehe ich mit Vorschauen in headless WordPress um? Die Vorschau ist einer der schwierigsten Teile von headless. Optionen: Next.js-Vorschau-Modus (ruft Entwurf-Inhalte mit einem geheimen Token ab), Gatbys Vorschau-Plugin oder benutzerdefinierte WordPress → Frontend-Webhooks.
Wie oft sollte ich meine statische Seite neu erstellen? Hängt von der Häufigkeit der Inhaltsaktualisierungen ab. Für täglich aktualisierte Inhalte, nächtliche Builds. Für weniger häufige Updates, webhook-triggerte Builds (WordPress veröffentlicht einen Beitrag → Webhook löst einen Build aus).
Kann ich Inhalte über das headless Frontend bearbeiten? Ja, über die WordPress REST API oder WPGraphQL-Mutationen. Aber für redaktionelle Workflows bearbeiten die meisten Teams im WordPress-Admin und lassen das Frontend lesen.
Wie gehe ich mit Formularen in headless WordPress um? Optionen: 1) Form Forge sendet an die WordPress REST API, 2) Drittanbieter-Formularservice (Formspree, Netlify Forms), 3) Direkte API-Integration mit Formularservices. In den meisten Fällen ist Form Forge + REST API die einfachste Lösung.
Was ist mit Medienuploads? Headless-Frontends verwenden typischerweise immer noch die Medienbibliothek von WordPress zur Speicherung. Das Frontend ruft Bild-URLs aus API-Antworten ab. Für von Benutzern hochgeladene Inhalte, POST an den Medien-REST-Endpunkt von WordPress.
Erhalten Sie Field Forge — ab $35/Jahr →
Die kostenlose Version umfasst die REST API und grundlegende Typen. Kostenpflichtige Pläne schalten die automatische TypeScript-Generierung, die automatische GraphQL-Registrierung und fortschrittliche headless Werkzeuge frei.