WordPress traditionnel : une pile. WordPress PHP rend tout — pages frontend, écrans d’administration, REST API. Votre thème gère à la fois l’édition de contenu (via l’administration) et l’affichage frontend (via des modèles PHP).
WordPress headless : deux piles. WordPress gère l’édition de contenu et le stockage des données. Un frontend JavaScript séparé (fonctionnant sur Vercel, Netlify, Cloudflare Pages, etc.) récupère le contenu depuis WordPress via REST API ou GraphQL et rend les pages de manière indépendante.
“` Traditionnel : [ WordPress ] → Contenu → Frontend (modèles PHP) ↑ ↑ └──── même serveur ─────────┘
Headless : [ WordPress ] → Contenu → [ Frontend JavaScript ] (CMS) (API) (Next.js / Astro / etc.) “`
Pour la plupart des sites WordPress, WordPress traditionnel est toujours le bon choix. Le headless est le bon choix lorsque vous avez besoin de ses avantages spécifiques et que vous acceptez la complexité.
Les champs personnalisés sont l’un des plus grands points de friction dans WordPress headless. Voici pourquoi.
Le cœur de WordPress a des champs standard — titre, contenu, extrait, image à la une, auteur, date. Ceux-ci sont bien définis, cohérents sur tous les sites WordPress, et entièrement pris en charge par les SDK frontend headless (bibliothèques clientes wp-rest-api, WPGraphQL, etc.).
Les champs personnalisés sont définis par des plugins. ACF ajoute ses propres champs, stockés à sa manière, exposés via sa propre API. Meta Box fait de même. Pods, Toolset, CMB2, Carbon Fields — chacun a sa propre approche.
Les SDK frontend ne connaissent pas les champs personnalisés car ils ne le peuvent pas — les définitions vivent dans le code du plugin, pas dans le cœur de WordPress.
TypeScript ne peut pas inférer les types de champs personnalisés à partir d’une réponse API WordPress. Un appel fetch('/wp-json/wp/v2/posts/123') renvoie un objet Post générique plus une propriété “ACF” avec les champs que le plugin a ajoutés. TypeScript voit cela comme any ou Record.
Le résultat : data.custom_fields.hero_title se compile bien même si le champ est nommé hero_headline. Les fautes de frappe deviennent des erreurs d’exécution.
Un développeur ajoute un nouveau groupe de champs sur son WordPress local. Il pousse le code vers la mise en scène. Le WordPress de mise en scène n’a pas encore ce groupe de champs. Le code frontend qui s’attend au nouveau champ échoue.
Sans synchronisation de schéma, WordPress headless devient un cauchemar de débogage.
L’API REST de WordPress expose les champs personnalisés de manière incohérente :
meta (comportement par défaut du cœur de WP)acf (intégration d’ACF)Pour qu’un composant Next.js rende un bloc Hero, il pourrait avoir besoin de 3 appels API séparés : un pour l’article, un pour l’image à la une, un pour l’article connexe référencé dans un champ de relation. C’est lent et complexe.
GraphQL (via WPGraphQL) est mieux adapté pour le headless car il vous permet de requêter des données profondément imbriquées en une seule requête. Mais WPGraphQL ne connaît pas les champs personnalisés — vous avez besoin d’un plugin séparé “WPGraphQL pour ACF” pour combler le fossé, et il est maintenu indépendamment, donc il est en retard par rapport aux mises à jour d’ACF.
Field Forge a été conçu en pensant à WordPress headless. Il aborde chaque point de douleur énuméré ci-dessus.
Au lieu de wp_postmeta, Field Forge stocke les valeurs de champ dans une table indexée dédiée. Les réponses API qui récupèrent des champs personnalisés sont considérablement plus rapides — 3 à 10 fois plus rapides sur les grands sites. Pour les flux de travail headless où le frontend récupère le contenu depuis WordPress à chaque construction (ou à chaque requête pour SSR), cela compte.
Fonction de stockage de table personnalisée →
Field Forge génère automatiquement des définitions TypeScript .d.ts pour chaque groupe de champs. Téléchargez le fichier, engagez-le dans votre dépôt frontend, obtenez une sécurité de type complète :
“`typescript import type { HeroSectionFields } from ‘@/types/fieldforge’;
function Hero({ data }: { data: HeroSectionFields }) { return
; // Autocomplétion TypeScript + vérification d’erreurs } “`
Les types se mettent à jour automatiquement lorsque vous éditez des groupes de champs. Relancez l’exportation TypeScript pour synchroniser.
Fonction de génération TypeScript →
Lorsque Field Forge et WPGraphQL sont tous deux actifs, Field Forge enregistre automatiquement les types GraphQL pour chaque groupe de champs lors de l’activation. Aucune configuration requise. Les champs personnalisés deviennent immédiatement interrogeables :
“graphql query GetPage { page(id: "home", idType: URI) { title fieldforge { heroSection { title subtitle backgroundImage { sourceUrl } } } } } “
Aucun plugin séparé WPGraphQL pour ACF nécessaire.
Fonction de génération GraphQL →
Field Forge expose les valeurs de champs personnalisés sur les points de terminaison REST de base sous une propriété fieldforge :
“`json GET /wp-json/wp/v2/posts/123
{ “id”: 123, “title”: { “rendered”: “Nos Services” }, “fieldforge”: { “service_list”: [ { “name”: “Conception Web”, “description”: “…” }, { “name”: “SEO”, “description”: “…” } ] } } “`
Un appel API renvoie l’article + tous les champs personnalisés. Pas de problème N+1.
La synchronisation JSON locale de Field Forge enregistre les groupes de champs sous forme de fichiers JSON dans votre répertoire de thème. Engagez-le dans git. Déployez à travers les environnements. Dev, mise en scène et production ont toujours le même schéma.
Voici un guide de configuration complet pour Next.js avec Field Forge.
“bash npx create-next-app@latest my-headless-site --typescript --app cd my-headless-site “
Créer 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]; } “`
Téléchargez le fichier .d.ts depuis l’administration de Field Forge : Field Forge → Outils → Export TypeScript → Télécharger.
Enregistrez dans 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}
); } “`
C’est une configuration minimale Next.js + Field Forge. L’autocomplétion TypeScript fonctionne. Le renommage des champs est sûr. La construction échoue si vous faites une faute de frappe dans une propriété.
generateStaticParamsPour la génération de site statique (option la plus rapide), récupérez toutes les pages au moment de la construction :
“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 pré-rendra chaque page en HTML statique au moment de la construction.
Astro est excellent pour les sites de contenu avec WordPress headless.
“bash npm create astro@latest my-site cd my-site “
Créer 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 && ( )} “`
La génération statique d’Astro fonctionne bien avec l’API REST de Field Forge — une construction, tout le contenu récupéré, sortie HTML statique.
Pour les développeurs Vue, Nuxt est le framework headless WordPress incontournable.
“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}); “`
Pour les fans de Svelte :
“`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} “`
Pour les sites nécessitant des requêtes profondément imbriquées, GraphQL est plus efficace que 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; } “`
Une requête récupère toute la page y compris les champs personnalisés. Pas de problème N+1.
Devrais-je utiliser REST ou GraphQL avec WordPress headless ? Cela dépend du frontend et de la complexité. REST est plus simple à configurer. GraphQL est plus efficace pour les requêtes profondément imbriquées et réduit le sur-récupération. Pour les petits sites, REST. Pour les sites avec des structures de contenu complexes, GraphQL.
Comment gérer les aperçus dans WordPress headless ? L’aperçu est l’une des parties les plus difficiles du headless. Options : mode aperçu Next.js (récupère le contenu brouillon avec un token secret), plugin d’aperçu de Gatsby, ou déclencheurs webhook personnalisés WordPress → frontend.
À quelle fréquence devrais-je reconstruire mon site statique ? Cela dépend de la fréquence de mise à jour du contenu. Pour un contenu mis à jour quotidiennement, des constructions nocturnes. Pour des mises à jour moins fréquentes, des constructions déclenchées par webhook (WordPress publie un article → le webhook déclenche une construction).
Puis-je éditer du contenu via le frontend headless ? Oui, via l’API REST de WordPress ou les mutations WPGraphQL. Mais pour les flux de travail éditoriaux, la plupart des équipes éditent dans l’administration WordPress et laissent le frontend lire.
Comment gérer les formulaires dans WordPress headless ? Options : 1) Form Forge envoie à l’API REST de WordPress, 2) Service de formulaire tiers (Formspree, Netlify Forms), 3) Intégration API directe avec des services de formulaire. Pour la plupart des cas, Form Forge + API REST est la solution la plus simple.
Qu’en est-il des téléchargements de médias ? Les frontends headless utilisent généralement encore la bibliothèque de médias de WordPress pour le stockage. Le frontend récupère les URL d’images à partir des réponses API. Pour le contenu téléchargé par l’utilisateur, POST vers le point de terminaison REST des médias de WordPress.
Obtenez Field Forge — à partir de 35$/an →
La version gratuite inclut l’API REST et des types de base. Les plans payants débloquent la génération automatique TypeScript, l’enregistrement automatique GraphQL et des outils avancés pour le headless.