vendredi 25 septembre 2026

À propos

Contact

Headless & API

Mapper les blocs Gutenberg vers des composants React en headless

Plutôt qu'afficher du HTML brut, transformez chaque bloc Gutenberg en composant React piloté par ses propres props. La méthode et ses pièges.

Par Clément Hadrot • 24 mars 2022 • 5 min de lecture • Aucun commentaire
Mapper les blocs Gutenberg vers des composants React en headless

Charger le CSS des blocs Gutenberg pour afficher le HTML brut, comme évoqué dans un précédent article, dépanne rapidement mais reste une solution de contournement : le front n’a alors aucun contrôle sur le rendu, aucune possibilité d’ajouter une interactivité propre à React (un carrousel, un lazy-load personnalisé), et reste dépendant du CSS généré par WordPress. Le mapping des blocs vers de véritables composants React va plus loin : chaque bloc devient une donnée structurée, interprétée et rendue par le framework front lui-même.

Cet article couvre le parsing du contenu en blocs, l’association de chaque type à un composant, et la gestion des blocs imbriqués ou inconnus. Il ne traite pas le chargement du CSS des blocs core, sujet distinct déjà couvert séparément.

Récupérer le contenu sous forme de blocs structurés

Par défaut, l’API REST WordPress renvoie le contenu déjà rendu en HTML dans content.rendered, sans structure de blocs exploitable directement. Pour obtenir la structure brute, deux options : exposer le champ content.raw (réservé aux utilisateurs autorisés à éditer, donc peu adapté à un usage public), ou parser le HTML rendu côté front avec un analyseur de blocs dédié comme @wordpress/block-serialization-default-parser, qui reconnaît les commentaires HTML délimitant chaque bloc (<!-- wp:paragraph -->).

import { parse } from '@wordpress/block-serialization-default-parser';

const blocs = parse(article.content.raw);
// [
//   { blockName: 'core/paragraph', attrs: {}, innerHTML: '<p>...</p>', innerBlocks: [] },
//   { blockName: 'core/image', attrs: { id: 42, url: '...' }, innerHTML: '...', innerBlocks: [] },
// ]

Sur un projet où exposer content.raw publiquement posait un problème d’accès, j’ai plutôt utilisé une route REST personnalisée côté WordPress qui appelle parse_blocks() (la fonction PHP native équivalente) et renvoie directement la structure JSON, évitant de dupliquer la logique de parsing côté front.

register_rest_field( 'post', 'blocs', array(
    'get_callback' => function ( $object ) {
        $post = get_post( $object['id'] );
        return parse_blocks( $post->post_content );
    },
) );

Un composant par type de bloc

L'essentiel à retenir : Parser le contenu en blocs avec un identifiant et des attributs ; Un composant React par type de bloc, avec repli pour les blocs inconnus ; Structure arborescente pour les blocs avec enfants

Une fois la structure obtenue, chaque bloc est rendu par un composant React dédié, sélectionné dynamiquement selon blockName :

const COMPOSANTS_BLOCS = {
  'core/paragraph': BlocParagraphe,
  'core/heading': BlocTitre,
  'core/image': BlocImage,
  'core/quote': BlocCitation,
  'core/list': BlocListe,
};

function RenduBloc({ bloc }) {
  const Composant = COMPOSANTS_BLOCS[bloc.blockName];

  if (!Composant) {
    return <BlocInconnu bloc={bloc} />;
  }

  return <Composant attrs={bloc.attrs} innerHTML={bloc.innerHTML} />;
}

function RenduContenu({ blocs }) {
  return blocs.map((bloc, i) => <RenduBloc key={i} bloc={bloc} />);
}

Exemple : le composant image

function BlocImage({ attrs }) {
  return (
    <figure>
      <img src={attrs.url} alt={attrs.alt ?? ''} width={attrs.width} height={attrs.height} />
      {attrs.caption && <figcaption>{attrs.caption}</figcaption>}
    </figure>
  );
}

Ce composant peut désormais utiliser un composant d’image optimisée propre au framework (comme next/image), avec lazy-loading et redimensionnement automatique, ce qu’un HTML brut affiché tel quel ne permet pas.

Gérer les blocs inconnus sans planter

Un site évolue : un auteur peut utiliser un bloc tiers (une extension installée après coup) ou un bloc core ajouté dans une version de WordPress plus récente que celle prise en compte par le mapping. Sans repli, le front planterait ou afficherait un espace vide silencieux. Le composant BlocInconnu doit au minimum afficher le HTML brut du bloc, en repli :

function BlocInconnu({ bloc }) {
  if (process.env.NODE_ENV === 'development') {
    console.warn(`Bloc non mappé : ${bloc.blockName}`);
  }
  return <div dangerouslySetInnerHTML={{ __html: bloc.innerHTML }} />;
}

L’avertissement en environnement de développement uniquement permet de repérer rapidement les blocs manquants pendant la phase de test, sans polluer la console en production.

Blocs avec enfants imbriqués

Certains blocs, comme core/columns, contiennent des blocs enfants dans innerBlocks, qu’il faut rendre récursivement plutôt qu’à plat :

function BlocColonnes({ bloc }) {
  return (
    <div style={{ display: 'flex', gap: '1.5rem' }}>
      {bloc.innerBlocks.map((colonne, i) => (
        <div key={i} style={{ flex: 1 }}>
          <RenduContenu blocs={colonne.innerBlocks} />
        </div>
      ))}
    </div>
  );
}

Comparaison avec l’affichage HTML brut

CritèreHTML brut + CSS des blocsMapping en composants React
Effort de mise en placeFaibleÉlevé, proportionnel au nombre de blocs utilisés
Contrôle du rendu et de l’interactivitéAucunTotal, propre au framework front
Maintenance à l’ajout d’un nouveau blocAucune (rendu automatiquement)Nécessite d’ajouter le composant correspondant

Je ne recommande le mapping complet que lorsque le front a réellement besoin d’interactivité propre sur certains blocs : pour un site éditorial simple sans composant interactif spécifique, le CSS des blocs core suffit souvent, avec un effort de maintenance bien moindre.

En résumé

Mapper les blocs Gutenberg vers des composants React demande de parser le contenu en structure de blocs, d’associer chaque type à un composant dédié, et de toujours prévoir un repli pour les blocs non mappés ou imbriqués. Cet effort supplémentaire, comparé à un simple affichage HTML brut, se justifie surtout quand le front doit ajouter une interactivité ou une optimisation que WordPress seul ne fournit pas.

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