vendredi 25 septembre 2026

À propos

Contact

Headless & API

Remix et WordPress headless : loaders, cache et formulaires

Construire un front Remix sur WPGraphQL : chargement des données par route, en-têtes de cache HTTP et formulaires sans bibliothèque tierce.

Par Clément Hadrot • 24 novembre 2023 • 4 min de lecture • Aucun commentaire
Remix et WordPress headless : loaders, cache et formulaires

Après plusieurs projets Next.js pour des clients avec un catalogue éditorial simple, un studio de céramique nous a demandé quelque chose de plus léger : un site rapide, sans complexité inutile côté gestion d’état, où chaque page interroge WordPress au moment où elle est demandée. Remix s’est imposé pour sa philosophie : les données se chargent côté serveur, dans une fonction dédiée à chaque route, sans magie cachée.

Ce choix a simplifié beaucoup de choses qu’on avait l’habitude de bricoler ailleurs, en particulier le cache et les formulaires.

Le loader : une fonction, une route, une requête

Chaque fichier de route Remix exporte une fonction loader exécutée côté serveur avant le rendu. C’est elle qui interroge WPGraphQL et transmet les données au composant :

export async function loader({ params }) {
  const data = await requeteWPGraphQL(REQUETE_PIECE, { slug: params.slug });
  if (!data.piece) {
    throw new Response('Introuvable', { status: 404 });
  }
  return json(data.piece);
}

Pas de useEffect, pas d’état de chargement à gérer manuellement : au moment où le composant s’exécute, la donnée est déjà là, résolue côté serveur.

Le cache par en-tête HTTP, sans magie

Remix expose une fonction headers par route, qui définit les en-têtes de la réponse renvoyée au navigateur ou à un CDN placé devant l’application :

export function headers() {
  return {
    'Cache-Control': 'public, max-age=60, stale-while-revalidate=600',
  };
}

Un contenu de catalogue de céramique change rarement dans la minute : un court max-age combiné à un stale-while-revalidate généreux suffit à absorber le pic de trafic d’une mise en avant sur les réseaux sociaux, sans jamais afficher une page cassée pendant la revalidation.

L'essentiel à retenir : Un loader par route, exécuté côté serveur uniquement ; Le cache se règle avec un simple en-tête HTTP ; Les formulaires postent sans JavaScript grâce aux actions

Les actions : des formulaires qui écrivent vers WordPress

Une fonction action, exportée dans le même fichier que le loader, reçoit les soumissions de formulaire côté serveur. Pour un formulaire de contact qui écrit dans WordPress via une mutation GraphQL personnalisée :

export async function action({ request }) {
  const donnees = await request.formData();
  const resultat = await requeteWPGraphQL(MUTATION_CONTACT, {
    nom: donnees.get('nom'),
    message: donnees.get('message'),
  });
  if (resultat.erreurs) {
    return json({ erreur: 'Envoi impossible' }, { status: 422 });
  }
  return redirect('/contact/merci');
}

Le formulaire HTML lui-même n’a besoin d’aucun gestionnaire JavaScript pour fonctionner : un simple <Form method="post"> de Remix suffit, et l’expérience reste fonctionnelle même si le JavaScript n’a pas encore fini de se charger côté client.

Gérer les erreurs de validation proprement

  • La fonction action renvoie un objet d’erreurs typé, jamais une exception non gérée.
  • Le composant de route lit cet objet via useActionData pour afficher les messages au bon endroit du formulaire.
  • Aucune bibliothèque de gestion de formulaire supplémentaire n’a été nécessaire sur ce projet, la plateforme suffisait.

Un piège rencontré avec l’authentification des mutations

Les mutations WPGraphQL qui écrivent du contenu exigent une authentification, généralement via un jeton transmis en en-tête. Sur Remix, ce jeton doit rester strictement côté serveur, jamais transmis au client : la fonction action s’exécutant déjà côté serveur, il suffit de lire le secret depuis les variables d’environnement du serveur, sans jamais l’exposer dans le bundle client.

Un projet où chaque route sait exactement ce qu’elle charge et ce qu’elle écrit reste lisible bien après le lancement, contrairement à un état global qui grossit au fil des fonctionnalités ajoutées.

Ce qu’on retient

Remix impose une discipline qui sert particulièrement bien un projet WordPress headless : un loader qui charge, une action qui écrit, des en-têtes qui cachent. Sur un site à dominante éditoriale sans interactivité complexe, cette simplicité se traduit directement par moins de code à maintenir et par des temps de chargement perçus très courts, sans étape de chargement côté client à gérer.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi