Un client vend des formations en ligne référencées comme un type de contenu personnalisé, formation. Sur son ancien thème classique, l’affichage d’une formation reposait sur un fichier single-formation.php assez long, mélangeant boucle WordPress et blocs de mise en page en dur. Avec le passage à un thème bloc, la même logique tient dans un fichier bien plus court, et surtout entièrement modifiable depuis l’éditeur de site.
Voici comment fonctionne ce mécanisme, et où se nichent les pièges les plus fréquents.
La convention de nommage
Dans un thème bloc, la hiérarchie de templates reprend les mêmes principes que la hiérarchie de templates classique, mais appliquée à des fichiers HTML plutôt qu’à des fichiers PHP. Pour cibler spécifiquement l’affichage d’un type de contenu personnalisé, le fichier doit porter le nom single-{slug-du-cpt}.html, placé dans le dossier templates du thème :
mon-theme/
└── templates/
├── single.html
├── single-formation.html
└── archive-formation.html
En l’absence de single-formation.html, WordPress se rabat sur single.html, puis sur index.html si aucun des deux n’existe. C’est exactement la même logique de repli que la hiérarchie de templates traditionnelle.
Créer le template depuis l’éditeur de site

Depuis Apparence > Éditeur > Templates > Ajouter un nouveau, WordPress propose directement, si le type de contenu personnalisé est correctement enregistré avec show_in_rest à true, un choix « Unique : Formations » dans la liste des templates suggérés. Sélectionner cette option crée un fichier prêt à être personnalisé, déjà relié au bon type de contenu.
Afficher les métadonnées personnalisées
C’est souvent là que le bât blesse : un type de contenu personnalisé s’accompagne presque toujours de champs additionnels (durée, prix, formateur). Deux approches coexistent aujourd’hui. La première consiste à enregistrer ces champs comme meta avec show_in_rest activé et à utiliser le bloc Champ personnalisé, encore limité en options d’affichage. La seconde, plus fiable pour un rendu soigné, consiste à créer un bloc dynamique dédié qui va chercher la métadonnée via get_post_meta() côté serveur.
Exemple de déclaration du champ
register_post_meta( 'formation', 'duree_heures', array(
'show_in_rest' => true,
'single' => true,
'type' => 'integer',
) );
Les pièges rencontrés sur ce projet
- Oublier
show_in_restsur le type de contenu empêche l’éditeur de site de proposer le template dédié. - Un slug de type de contenu trop long peut rendre le nom de fichier difficile à repérer parmi d’autres templates.
- Le template
archive-formation.htmldoit être créé séparément : rien ne le génère automatiquement à partir du templatesingle.
Créer un bloc dynamique pour un rendu plus riche
Sur la page de détail d’une formation, afficher simplement la durée sous forme de texte brut ne suffisait pas : le client souhaitait une icône, une mise en forme conditionnelle selon que la formation soit encore ouverte aux inscriptions, et un badge coloré selon le niveau. Ce type de rendu a nécessité l’écriture d’un petit bloc dynamique, enregistré côté serveur, dont le rendu final s’appuie directement sur get_post_meta() :
register_block_type( 'mon-theme/badge-formation', array(
'render_callback' => function() {
$duree = get_post_meta( get_the_ID(), 'duree_heures', true );
return sprintf(
'<span class="badge-formation">%d heures</span>',
(int) $duree
);
},
) );
Ce bloc s’insère ensuite normalement dans le template single-formation.html, aux côtés des blocs natifs comme Post Title ou Post Content, sans que l’éditeur ne fasse de distinction visuelle particulière entre un bloc natif et un bloc personnalisé de ce type.
En résumé
Le principe reste fidèle à ce que les développeurs WordPress connaissent depuis des années : un nom de fichier précis pour cibler un contexte précis. Ce qui change, c’est la facilité d’édition visuelle une fois le fichier créé, et la nécessité de repenser l’affichage des métadonnées avec les outils du bloc — natif ou personnalisé — plutôt qu’avec une boucle PHP classique.