# single-{cpt}.html : un template dédié à chaque type de contenu personnalisé

> Dans un thème bloc, un fichier single-{cpt}.html suffit à donner une mise en page propre à chaque type de contenu personnalisé. Nommage, métadonnées et création depuis l'éditeur.

- Auteur : Clément Hadrot
- Publié le : 2022-01-24
- Mis à jour le : 2022-01-24
- Catégorie : FSE
- URL : https://wpmoderne.dev.wordpress-developpement.fr/fse/single-cpt-html-template-dedie-type-contenu/

## L’essentiel

- Le nom du fichier détermine automatiquement le type de contenu ciblé
- Les métadonnées s'affichent via le bloc Champ personnalisé ou un bloc dédié
- La priorité de résolution suit une hiérarchie précise

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

> L'essentiel à retenir : Le nom du fichier détermine automatiquement le type de contenu ciblé ; Les métadonnées s'affichent via le bloc Champ personnalisé ou un bloc dédié ; La priorité de résolution suit une hiérarchie précise

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_rest` sur 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.html` doit être créé séparément : rien ne le génère automatiquement à partir du template `single`.

## 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.
