Le Content Layer d’Astro traite historiquement les fichiers Markdown locaux comme des collections typées. La question s’est posée sur un projet de blog culturel : pourquoi ne pas traiter WordPress exactement de la même façon, comme une source de collection parmi d’autres, plutôt que de bricoler des appels fetch dispersés dans les pages ? Un loader personnalisé permet précisément cela.
Ce choix évite d’installer un plugin générique aux options mal maîtrisées : le loader reste un simple fichier, entièrement lisible, adapté exactement au schéma du site.
Déclarer la collection
Dans src/content/config.ts, la collection s’appuie sur un loader personnalisé plutôt que sur un dossier de fichiers, avec un schéma validé via Zod :
import { defineCollection, z } from 'astro:content';
import { loaderWordPress } from '../loaders/wordpress';
const articles = defineCollection({
loader: loaderWordPress({ url: 'https://cms.exemple.fr/graphql' }),
schema: z.object({
titre: z.string(),
slug: z.string(),
extrait: z.string(),
datePublication: z.string(),
}),
});
export const collections = { articles };
Écrire le loader lui-même
Un loader Content Layer expose une fonction qui reçoit un contexte avec un accès au store de données d’Astro, dans lequel chaque élément est inséré avec un identifiant stable :
export function loaderWordPress({ url }) {
return {
name: 'loader-wordpress',
load: async ({ store, logger }) => {
const reponse = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: REQUETE_ARTICLES }),
});
const { data } = await reponse.json();
store.clear();
for (const article of data.posts.nodes) {
store.set({
id: article.slug,
data: {
titre: article.title,
slug: article.slug,
extrait: article.excerpt,
datePublication: article.date,
},
});
}
logger.info(`${data.posts.nodes.length} articles chargés depuis WordPress`);
},
};
}

Ce que la validation de schéma apporte
Si un champ attendu manque côté WordPress (un extrait vide sur un article mal renseigné), Astro le signale au moment du chargement, avec un message d’erreur explicite pointant vers l’élément fautif. C’est une différence appréciable par rapport à un simple fetch dans une page, où une donnée manquante ne se découvre souvent qu’au rendu, sous forme d’un affichage cassé silencieux.
Consommer la collection dans une page
Une fois la collection déclarée, elle se consomme exactement comme n’importe quelle collection basée sur des fichiers locaux, avec les mêmes fonctions getCollection et getEntry déjà connues des utilisateurs d’Astro :
---
import { getCollection } from 'astro:content';
const tousLesArticles = await getCollection('articles');
---
<ul>
{tousLesArticles.map((a) => <li>{a.data.titre}</li>)}
</ul>
Le reste de l’équipe front, qui ne connaît pas forcément WPGraphQL, manipule une collection Astro classique, sans avoir besoin de comprendre le détail de la requête envoyée à WordPress en coulisses.
Rebuilds incrémentaux
Le store fourni au loader permet, plutôt que de vider et recharger l’intégralité de la collection à chaque fois, de ne mettre à jour que les éléments réellement modifiés depuis le dernier chargement, à condition de comparer une date de modification avant de réécrire chaque entrée. Sur ce projet, le loader interroge d’abord les identifiants et dates de modification, puis ne redemande le contenu complet que pour les articles réellement changés.
- Utiliser le champ
modifiedde chaque contenu WordPress comme référence de comparaison. - Conserver la date du dernier chargement complet dans le contexte du loader entre deux exécutions.
- Ne réécrire dans le store que les entrées dont la date de modification a réellement changé.
Un loader Content Layer maison prend une heure à écrire correctement, contre plusieurs jours passés par le passé à configurer et déboguer un plugin générique pas toujours pensé pour le schéma exact du projet.
Ce qu’on retient
Le Content Layer d’Astro traite WordPress avec la même rigueur que n’importe quelle autre source de contenu : schéma validé, identifiants stables, chargement incrémental possible. Pour un site qui n’a pas besoin de rendu dynamique à chaque requête, cette approche simplifie nettement la relation entre WordPress et le générateur de site statique, sans dépendance à un plugin tiers à la roadmap incertaine.