headless-wordpress-astro-setup.html
< BACK Bureau vintage avec pages manuscrites et magnétophone dans une lumière dorée de fin d'après-midi

WordPress Headless + Astro : Une Configuration Fonctionnelle pour les Sites à Contenu Dense

Un client m'a appelé début 2023 -- un éditeur de médias exploitant environ 14 000 articles sur WordPress, un thème assemblé par quatre développeurs sur six ans, et un score Core Web Vitals franchement embarrassant. Son LCP affichait 7,2 secondes sur mobile. Ils avaient essayé WP Rocket, ils avaient essayé un CDN, ils avaient même supprimé la moitié de leurs extensions. Toujours lent. Le problème n'était pas WordPress lui-même. C'était que chaque rendu de page passait par PHP, un thème obèse, et une chaîne de requêtes en base de données qu'on n'avait pas examinée depuis 2018.Core Web Vitals score that was genuinely embarrassing. Their LCP was clocking in at 7.2 seconds on mobile. They'd tried WP Rocket, they'd tried a CDN, they'd even stripped half their plugins. Still slow. The problem wasn't WordPress itself. It was that every single page render was going through PHP, a bloated theme, and a database query chain that hadn't been looked at since 2018.

Point clé : WordPress headless avec Astro est le meilleur compromis pour les sites de contenu : wp-admin pour les éditeurs, front-end statique et rapide pour les visiteurs, et WPGraphQL qui relie les deux.Headless WordPress with Astro is the content-site sweet spot: wp-admin for editors, static-fast front end for visitors, and WPGraphQL bridging the two.

C'est à ce moment que je me suis vraiment engagé dans une architecture headless avec Astro comme frontend. Pas parce que c'est à la mode -- mais parce que pour un site contenant des milliers d'articles avec du contenu éditorial lourd, c'était la seule architecture qui avait du sens.Astro as the frontend. Not because it's fashionable -- because for a site pushing thousands of posts with heavy editorial content, it was the only architecture that made sense.

Voici exactement comment je l'ai configuré. Les compromis, la vraie configuration, les points qui m'ont posé problème.

---

Pourquoi Astro et Pas Next.js

Je reçois souvent cette question. Next.js est la réponse évidente si vous avez déjà une équipe fortement orientée React ou si vous avez besoin d'interactivité côté client complexe. Mais pour les sites lourds en contenu ? Astro gagne, et ce n'est pas particulièrement serré.Next.js is the obvious answer if you've already got a React-heavy team or you need complex client-side interactivity. But for content-heavy sites? Astro wins, and it's not particularly close.

Astro expédie zéro JavaScript par défaut. Pour un blog, un site d'actualités ou un portail de documentation, c'est le bon choix. Vous optez pour JavaScript où vous en avez besoin, plutôt que de refuser un bundle React de 200 kb que vous ne voulez généralement pas. La documentation Astro sur l'hydratation partielle -- ils l'appellent l'architecture Islands -- l'explique mieux que je ne peux le faire en une phrase, mais en résumé : seules les parties interactives reçoivent du JS. Le corps de l'article, l'en-tête, la barre latérale ? Du HTML statique.zero JavaScript by default. For a blog, a news site, or a documentation portal, that's the correct default. You opt into JavaScript where you need it, rather than opting out of a 200kb React bundle you mostly don't want. The Astro docs on partial hydration -- they call it the Islands architecture -- explain it better than I can in a sentence, but the short version is: only the interactive bits get JS. The article body, the header, the sidebar? Static HTML.

J'ai construit un site de contenu juridique fin 2022 avec Next.js et WordPress. Assez rapide, mais le client n'arrêtait pas de demander pourquoi son score Lighthouse était 74 sur mobile alors que « c'est censé être rapide maintenant ». Frais d'hydratation. Avec Astro, ce même type de site atteint maintenant régulièrement 95-98. Je ne me vante pas -- c'est juste ce que l'architecture vous offre gratuitement.

Ce qu'Astro n'est pas bon à faire

C'est important d'être honnête. Si votre site a besoin de personnalisation en temps réel, d'un panier d'achat lourd, ou de quelque chose qui dépend vraiment de l'état côté client sur plusieurs composants, Astro commence à sembler maladroit. Ce n'est pas une application React. Le motif Islands est puissant, mais c'est un modèle mental différent de la construction d'SPA. J'ai essayé de forcer un tableau de bord client dans un projet Astro mi-2023 et j'ai fini par revenir à Next.js en deux semaines. Sachez ce que vous construisez.

---

Configurer WordPress comme CMS découplé

WordPress est véritablement un bon backend découplé. L'API REST WP est livrée dans le cœur, elle est bien documentée, et votre équipe éditoriale n'a rien de nouveau à apprendre. Ce dernier point compte bien plus que les développeurs ne l'admettent généralement.WP REST API ships in core, it's well-documented, and your editorial team doesn't have to learn anything new. That last point matters more than developers usually admit.

Voici la configuration que j'utilise :

  1. Installez WordPress sur un sous-domaine -- j'utilise cms.yourdomain.com ou api.yourdomain.com. Gardez-le derrière une authentification de base ou au minimum restreignez le trafic public direct. Le frontend est yourdomain.com. Deux déploiements séparés. -- I use cms.yourdomain.com or api.yourdomain.com. Keep it behind basic auth or at minimum restrict direct public traffic. The frontend is yourdomain.com. Two separate deployments.
  2. Installez le [plugin WPGraphQL](https://www.wpgraphql.com/) -- je préfère GraphQL à REST pour les sites de contenu car vous pouvez co-localiser vos requêtes avec vos composants et récupérer exactement les champs dont vous avez besoin. Pas de sur-récupération. L'API REST fonctionne, mais une fois que vous avez 15+ champs personnalisés par type de contenu, l'approche GraphQL est notablement plus propre. -- I prefer GraphQL over REST for content sites because you can co-locate your queries with your components and fetch exactly the fields you need. No over-fetching. The REST API is fine, but once you've got 15+ custom fields per post type, the GraphQL approach is noticeably cleaner.
  3. Installez Advanced Custom Fields (ACF) et l'extension WPGraphQL pour ACF. Cette combinaison est ce qui rend WordPress vraiment flexible en tant que modèle de contenu headless -- vous pouvez définir des données structurées par type de contenu, les exposer via GraphQL, et Astro les consomme proprement. and the WPGraphQL for ACF extension. This combo is what makes WordPress genuinely flexible as a headless content model -- you can define structured data per post type, expose it through GraphQL, and Astro consumes it cleanly.
  4. Désactivez les commentaires, les emojis et le XML-RPC par défaut si vous ne l'avez pas déjà fait. Ceux-ci ajoutent une surcharge et une surface d'attaque dont vous n'avez pas besoin. if you haven't already. These add overhead and attack surface you don't need.
  5. Définissez les permaliens à quelque chose de sensé avant de commencer à construire. Les changer en milieu de projet une fois que vos routes Astro sont déjà en place, c'est vraiment pénible. to something sensible before you start building. Changing them mid-project when your Astro routes are already set is a genuine pain.

Une chose qui piège les gens : CORS. Par défaut, WordPress ne laissera pas votre serveur de développement Astro (fonctionnant sur localhost:4321) faire des requêtes vers votre installation WP. Mettez ceci dans le functions.php de votre thème ou un petit plugin utilitaire pendant le développement :localhost:4321) make requests to your WP install. Drop this into your theme's functions.php or a small utility plugin during development:

`` add_action('init', function() { header("Access-Control-Allow-Origin: *"); }); `` add_action('init', function() { header("Access-Control-Allow-Origin: *"); }); ``

Resserrez cela sur des origines spécifiques en production. Évidemment.

---

La Structure du Projet Astro

Je la garde opinée et cohérente d'un projet à l'autre. Après une douzaine ou so de constructions headless, c'est ce qui fonctionne :

`` src/ components/ layouts/ pages/ index.astro blog/ [slug].astro lib/ wpgraphql.ts ← toute la logique de requête WP vit ici styles/ `` src/ components/ layouts/ pages/ index.astro blog/ [slug].astro lib/ wpgraphql.ts ← all WP query logic lives here styles/ ``

Le fichier lib/wpgraphql.ts est l'endroit où je centralise chaque récupération GraphQL. Pas d'appels de récupération en ligne dispersés dans les fichiers de page. Chaque requête est une fonction asynchrone nommée et exportée. Déboguer cela sur 14 000 articles quand quelque chose casse à 2 h du matin -- vous vous en remercierez plus tard.lib/wpgraphql.ts file is where I centralise every GraphQL fetch. No inline fetch calls scattered across page files. Every query is a named, exported async function. Debugging this across 14,000 posts when something breaks at 2am -- you'll thank yourself later.

Récupérer les articles au moment de la construction

getStaticPaths d'Astro est ton pain et beurre ici. Pour un blog avec des milliers d'articles :getStaticPaths is your bread and butter here. For a blog with thousands of posts:

`` export async function getStaticPaths() { const posts = await getAllPostSlugs(); // appelle WPGraphQL return posts.map(post => ({ params: { slug: post.slug }, })); } `` export async function getStaticPaths() { const posts = await getAllPostSlugs(); // calls WPGraphQL return posts.map(post => ({ params: { slug: post.slug }, })); } ``

getAllPostSlugs pagine via WPGraphQL en utilisant des curseurs after -- la couche GraphQL de WordPress retourne 100 articles par demande par défaut, donc pour 14 000 articles vous faites 140 requêtes au moment du build. Ça paraît effrayant. En pratique, sur un bon serveur, le build complet s'exécute en environ 4-5 minutes. Tout à fait acceptable pour un site qui se reconstruit quelques fois par jour. paginates through WPGraphQL using after cursors -- WordPress's GraphQL layer returns 100 posts per request by default, so for 14,000 posts you're making 140 requests at build time. That sounds scary. In practice, on a decent server, the full build runs in about 4-5 minutes. Perfectly acceptable for a site that rebuilds a few times per day.

---

Gérer les images sans perdre la tête

C'est le point que personne ne soulève assez. WordPress stocke les URLs des images pointant vers votre sous-domaine CMS. Quand Astro construit statiquement, ces images vivent toujours sur cms.yourdomain.com -- ce qui signifie que les navigateurs de vos visiteurs récupèrent les images depuis votre serveur WordPress, contournant potentiellement votre CDN.cms.yourdomain.com -- which means your visitors' browsers are fetching images from your WordPress server, potentially bypassing your CDN.

Quelques façons de gérer cela :

  • Cloudflare devant les deux domaines. L'option la plus simple. Proxy à travers Cloudflare yourdomain.com et cms.yourdomain.com, configurez un cache agressif sur /wp-content/uploads/*, et c'est bon. Simplest option. Proxy both yourdomain.com and cms.yourdomain.com through Cloudflare, configure aggressive caching on /wp-content/uploads/*, and you're mostly fine.
  • Utilisez un plugin de délocalisation de médias. J'aime bien WP Offload Media -- il déplace les uploads vers S3 (ou un stockage compatible) et réécrit les URLs automatiquement. C'est l'approche que j'utilise pour tout site attendant du trafic sérieux. Votre serveur WordPress arrête complètement de servir les images. I like WP Offload Media -- it moves uploads to S3 (or compatible storage) and rewrites URLs automatically. This is the approach I use for any site expecting serious traffic. Your WordPress server stops serving images entirely.
  • Le composant Image d'Astro. Pour les images que vous contrôlez au moment du build (images à la une récupérées via GraphQL), vous pouvez passer l'URL distante au composant <Image> d'Astro et il optimisera, redimensionnera et servira les images depuis votre résultat de build. Ça fonctionne brillamment. Ne fonctionne pas pour les images intégrées dans le HTML du corps du post -- ça requiert une passe différente. For images you control at build time (featured images pulled via GraphQL), you can pass the remote URL into Astro's <Image> component and it'll optimise, resize, and serve them from your build output. Works brilliantly. Does not work for images embedded in post body HTML -- that requires a different pass.

Seahawk avait un client de contenu voyage l'année dernière -- environ 8 000 posts, extrêmement chargé en images, moyenne de 12 images par article. Leur serveur WordPress était martelé purement par les requêtes d'images même avec la configuration headless. Passer à S3 + CloudFront a réduit leur bande passante d'origine de 94%. Franchement transformateur pour leur facture d'hébergement.

---

Builds Incrémentaux et le Problème du Rebuild

Voici un vrai problème avec la génération statique à l'échelle : votre éditeur publie une correction de post à 15h et doit attendre 5 minutes pour un rebuild complet. Ce n'est pas acceptable dans une salle de rédaction.

Quelques approches que j'ai utilisées :

Option 1 : Netlify ou Vercel avec ISR à la demande. Astro supporte le rendu côté serveur avec des adaptateurs -- vous pouvez exécuter Astro en mode hybride où la plupart des pages sont statiques mais des routes spécifiques sont rendues à la demande. Pour un site d'actualités, je pré-rends souvent statiquement les 30 derniers jours de posts (haut trafic, besoin de vitesse) et définissez les pages d'archives plus anciennes pour un rendu à la demande. Le meilleur des deux mondes. Astro supports server-side rendering with adapters -- you can run Astro in hybrid mode where most pages are static but specific routes are rendered on-demand. For a news site, I'll often statically pre-render the last 30 days of posts (high traffic, needs speed) and set older archive pages to server-render on demand. Best of both worlds.

Option 2 : Builds partiels déclenchés par webhook. WordPress déclenche un webhook à la sauvegarde du post (facile avec le plugin WP Webhooks). Ce webhook atteint un crochet de déploiement Netlify ou Vercel. Le build s'exécute, il récupère seulement ce qui a changé. Ce n'est pas vraiment partiel -- Astro reconstruit quand même tout -- mais si vous gardez votre build rapide, 4 minutes c'est acceptable. WordPress fires a webhook on post save (easy with the WP Webhooks plugin). That webhook hits a Netlify or Vercel deploy hook. The build runs, it fetches only what's changed. It's not truly partial -- Astro still rebuilds everything -- but if you keep your build fast, 4 minutes is workable.

Option 3 : Utilisez simplement SSR pour tout. Déployez Astro avec l'adaptateur Node sur un VPS (j'utilise Hetzner pour ça -- bon marché, rapide, fiable). Chaque page se rend à la demande, vous cachez agressivement au niveau Nginx ou Cloudflare, et vous avez des mises à jour de posts instantanées. C'est ce que je ferais pour une vraie opération d'édition au-delà de 50 000 posts. Deploy Astro with the Node adapter to a VPS (I use Hetzner for this -- cheap, fast, reliable). Every page renders on request, you cache aggressively at the Nginx or Cloudflare level, and you have instant post updates. This is what I'd do for a proper publishing operation over 50,000 posts.

Pour être honnête ? La plupart des sites n'ont pas besoin de la complexité de l'Option 1 ou 3. Une reconstruction de 4 minutes déclenchée par un webhook, c'est bon pour 90 % des sites de contenu.

---

Performance : ce que vous obtenez réellement

Sur le projet éditeur de l'introduction -- voilà ce qui s'est passé après la migration Astro :

  • LCP est passé de 7.2s à 1.1s sur mobile (testé avec WebPageTest depuis un nœud à Londres)1.1s on mobile (tested with WebPageTest from a London node)
  • Total Blocking Time est passé de ~800ms à 0ms (zéro JS par défaut, souvenez-vous)0ms (zero JS by default, remember)
  • Leur rapport Core Web Vitals de Google Search Console est passé de 3 % d'URLs « Bon » à 91 % « Bon » en six semaines suivant le déploiement91% "Good" within six weeks of deployment
  • Les coûts d'hébergement ont baissé parce que leur serveur WordPress ne servait plus les pages, seulement les réponses API

Rien de magique là-dedans. C'est juste ce qui se passe quand on retire le rendu PHP du chemin critique et qu'on arrête de livrer un bundle JavaScript de theme de 400kb à chaque lecteur.

---

Les points qui vont vous piéger

Parlons franchement -- les choses que j'ai dû déboguer sur des projets réels :

  • Les aperçus de brouillon. C'est vraiment pénible dans une architecture headless. L'aperçu natif de WordPress repose sur le rendu front-end. Vous avez besoin de construire un endpoint d'aperçu personnalisé dans Astro qui accepte un nonce d'aperçu WordPress et récupère le brouillon via WPGraphQL. Pas compliqué, mais ça prend une journée pour le faire correctement. This is genuinely annoying in a headless setup. WordPress's native preview relies on front-end rendering. You need to build a custom preview endpoint in Astro that accepts a WordPress preview nonce and fetches the draft via WPGraphQL. Not hard, but it takes a day to do properly.
  • Les redirections. Si l'ancien site avait des centaines de redirections dans .htaccess, elles vivent maintenant sur le serveur WordPress. Vous devez soit les reproduire dans la config d'Astro, soit garder WordPress accessible et faire un proxy sur des chemins spécifiques. J'ai fait les deux. Reproduire dans Astro est plus propre à long terme. If the old site had hundreds of redirects in .htaccess, those live on the WordPress server now. You need to either replicate them in Astro's config, or keep WordPress accessible and proxy specific paths. I've done both. Replicating in Astro is cleaner long-term.
  • La recherche. La recherche intégrée de WordPress est inutile dans une architecture headless. J'utilise Algolia avec le plugin WP Search with Algolia. Indexez vos articles dans WP, interrogez Algolia depuis un composant Astro Island. Ça marche bien. WordPress's built-in search is useless in a headless setup. I use Algolia with the WP Search with Algolia plugin. Index your posts in WP, query Algolia from an Astro Island component. Works well.
  • Menus et navigation. Les menus WordPress sont bizarrement délicats à exposer via WPGraphQL. La route wpgraphql-acf finit souvent par être plus propre -- modelez simplement votre navigation comme un répéteur ACF et c'est fait. WordPress menus are weirdly fiddly to expose through WPGraphQL. The wpgraphql-acf route often ends up being cleaner -- just model your nav as an ACF repeater and call it done.

---

FAQ

Ai-je besoin de WPGraphQL ou puis-je simplement utiliser l'API REST ?

Vous pouvez tout à fait utiliser l'API REST — elle est intégrée à WordPress core et ne nécessite aucun plugin supplémentaire. Pour les sites simples avec des types de posts standard et des champs personnalisés minimes, c'est parfait. GraphQL prend tout son sens quand vous avez des modèles de contenu complexes avec beaucoup de champs personnalisés par type. Pouvoir récupérer exactement les champs dont vous avez besoin en une seule requête, sans vous battre avec les paramètres _embed et les appels REST imbriqués, fait gagner du temps sur chaque requête que vous écrivez. À vous de choisir. Je trouve simplement GraphQL plus propre passé un certain seuil de complexité._embed parameters and nested REST calls, saves time on every query you write. Up to you. I just find GraphQL cleaner past a certain complexity threshold.

Comment gérer l'authentification WordPress pour le contenu réservé aux membres ?

L'authentification JWT est l'approche standard. Installez le plugin JWT Authentication for WP REST API, émettez des tokens à la connexion, passez-les dans les en-têtes de votre requête GraphQL. Du côté Astro, vous géreriez cela avec une route SSR (pas statique) pour que le contenu spécifique à l'utilisateur soit récupéré côté serveur par requête. N'essayez pas de faire cela de manière statique — c'est la route vers la folie.JWT Authentication for WP REST API plugin, issue tokens on login, pass them in your GraphQL request headers. On the Astro side, you'd handle this with an SSR route (not static) so the user-specific content is fetched server-side per request. Don't try to do this statically -- that way lies madness.

N'est-ce pas exagéré pour un petit blog ?

Oui, probablement. Si vous avez moins de 500 articles et un seul éditeur, la charge de maintenir une architecture headless n'en vaut pas la peine. Utilisez simplement un bon thème WordPress, optimisez vos images, et passez à autre chose. Cette architecture s'amortit quand vous avez du volume, de la complexité éditoriale, ou des niveaux de trafic où la performance impacte réellement vos revenus.

À quoi ressemble la configuration d'hébergement en production ?

WordPress (CMS uniquement) sur un petit VPS ou un hébergement WordPress géré — j'utilise Kinsta ou Cloudways. Frontend Astro sur Vercel, Netlify, ou un VPS Hetzner avec Nginx selon le projet. Cloudflare devant tout. Le coût mensuel total pour un site de contenu de taille moyenne est généralement de £60 à £120, ce qui est souvent moins que ce que les clients payaient pour un hébergement WordPress tout-en-un qui peinait sous la charge.less than what clients were paying for an all-in-one WordPress host that was struggling under the load.

---

Le résumé honnête est celui-ci : WordPress headless avec Astro est l'une des meilleures choses qui soit arrivée aux sites de contenu depuis un moment. Non pas parce que c'est nouveau, mais parce que l'écosystème a enfin rattrapé l'idée. WPGraphQL est stable, le système de build d'Astro est rapide, et les gains de performance sont réels et mesurables.

Bien structurer l'architecture dès le départ — en particulier votre stratégie d'images et votre approche de reconstruction — et vous passerez beaucoup moins de temps à éteindre les incendies après. C'est vraiment tout.

< BACK