# InnerBlocks et templates : construire des blocs composés dans Gutenberg

> Grille de cartes, colonnes, accordéon… le composant InnerBlocks permet d'imbriquer des blocs enfants. Voici comment le maîtriser, avec template et allowedBlocks.

- Auteur : Clément Hadrot
- Publié le : 2020-08-20
- Mis à jour le : 2020-08-20
- Catégorie : Blocs Gutenberg
- URL : https://wpmoderne.dev.wordpress-developpement.fr/blocs/innerblocks-template-blocs-composes-gutenberg/

## L’essentiel

- Utiliser InnerBlocks pour créer un bloc conteneur
- Restreindre les blocs enfants avec allowedBlocks
- Verrouiller la structure avec templateLock

Depuis la mise à jour 5.5 de WordPress, sortie ce mois-ci avec son lot de nouveautés côté sitemaps XML natifs et chargement différé des images, l'écosystème des blocs continue lui aussi de mûrir. Un besoin revient sans cesse chez les clients qui ont goûté à Gutenberg : pouvoir composer des mises en page à base de blocs imbriqués, comme une grille de cartes où chaque carte reste éditable indépendamment. C'est exactement ce que permet le composant `InnerBlocks`.

Dans cet article, on construit un bloc « grille de cartes » : un conteneur qui accueille un nombre variable de blocs « carte », chacun avec une image, un titre et un texte. On verra comment pré-remplir la structure avec un `template`, restreindre les blocs autorisés avec `allowedBlocks`, et verrouiller tout ou partie de l'arborescence avec `templateLock`.

## Le principe d'InnerBlocks

Le composant `InnerBlocks`, exposé par `@wordpress/block-editor`, permet à un bloc d'accueillir d'autres blocs en son sein, exactement comme le fait le bloc natif Colonnes. Contrairement à un attribut classique, le contenu des blocs enfants n'est pas stocké dans l'attribut du bloc parent : chaque bloc enfant est sérialisé indépendamment dans le HTML final, imbriqué entre les commentaires délimiteurs du bloc parent.

Concrètement, cela donne un contenu structuré de cette forme une fois publié :

```
<!-- wp:wpmoderne/grille-cartes -->
<div class="wpmoderne-grille">
<!-- wp:wpmoderne/carte -->
<div class="wpmoderne-carte">…</div>
<!-- /wp:wpmoderne/carte -->
<!-- wp:wpmoderne/carte -->
<div class="wpmoderne-carte">…</div>
<!-- /wp:wpmoderne/carte -->
</div>
<!-- /wp:wpmoderne/grille-cartes -->
```

## Créer le bloc conteneur « grille de cartes »

Le bloc parent n'a besoin d'aucun attribut particulier pour stocker les cartes : `InnerBlocks` s'en charge. Sa fonction `edit()` se contente d'afficher la zone d'accueil des blocs enfants.

```
import { registerBlockType } from '@wordpress/blocks';
import { InnerBlocks } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';

const ALLOWED_BLOCKS = [ 'wpmoderne/carte' ];
const TEMPLATE = [
    [ 'wpmoderne/carte' ],
    [ 'wpmoderne/carte' ],
    [ 'wpmoderne/carte' ],
];

registerBlockType( 'wpmoderne/grille-cartes', {
    title: __( 'Grille de cartes', 'wpmoderne' ),
    icon: 'grid-view',
    category: 'common',

    edit() {
        return (
            <div className="wpmoderne-grille">
                <InnerBlocks
                    allowedBlocks={ ALLOWED_BLOCKS }
                    template={ TEMPLATE }
                    templateLock="insert"
                />
            </div>
        );
    },

    save() {
        return (
            <div className="wpmoderne-grille">
                <InnerBlocks.Content />
            </div>
        );
    },
} );
```

Dans `save()`, on n'utilise jamais `InnerBlocks` directement mais son pendant statique, `InnerBlocks.Content`, qui se contente de restituer le HTML déjà sérialisé des blocs enfants sans réimporter toute la logique d'édition.

> L'essentiel à retenir : Utiliser InnerBlocks pour créer un bloc conteneur ; Restreindre les blocs enfants avec allowedBlocks ; Verrouiller la structure avec templateLock

## Restreindre les blocs enfants avec allowedBlocks

La prop `allowedBlocks` prend un tableau de noms de blocs : seuls ceux-ci apparaîtront dans l'inserteur lorsqu'on ajoute un bloc à l'intérieur du conteneur. Sans cette restriction, n'importe quel bloc du site — y compris un bloc Colonnes ou un bloc Image isolé — pourrait s'y glisser, ce qui casserait le design pensé pour la grille.

On peut aussi omettre `allowedBlocks` pour autoriser tous les blocs, ce qui a du sens pour un conteneur générique de type « encadré » ou « section », mais devient risqué pour un composant à la mise en page contrainte comme notre grille de cartes.

## Pré-remplir la structure avec template

La prop `template` attend un tableau de tableaux, chacun de la forme `[ nomDuBloc, attributsInitiaux, blocsEnfants ]`. C'est ce qui permet d'insérer automatiquement trois blocs « carte » vierges dès l'ajout du bloc « grille de cartes », sans que l'utilisateur ait à cliquer trois fois sur le bouton d'ajout.

On peut aussi pré-remplir les attributs de chaque bloc enfant :

```
const TEMPLATE = [
    [ 'wpmoderne/carte', { titre: 'Premier atout' } ],
    [ 'wpmoderne/carte', { titre: 'Deuxième atout' } ],
    [ 'wpmoderne/carte', { titre: 'Troisième atout' } ],
];
```

Le `template` ne s'applique qu'à l'insertion initiale du bloc parent : une fois que l'utilisateur a modifié la structure (ajouté, supprimé un enfant), Gutenberg ne revient jamais dessus tout seul.

## Verrouiller la structure avec templateLock

C'est ici que `InnerBlocks` révèle toute sa flexibilité pour des besoins éditoriaux précis. La prop `templateLock` accepte trois valeurs :

- `"all"` — la structure est totalement figée : impossible d'ajouter, de supprimer ou de déplacer un bloc enfant. Seul le contenu de chaque bloc reste modifiable.
- `"insert"` — on ne peut plus ajouter ni supprimer de blocs enfants, mais on peut toujours les réordonner par glisser-déposer.
- `false` — aucune restriction structurelle : c'est le comportement par défaut si la prop n'est pas précisée.

Pour notre grille de cartes, `"insert"` est souvent le bon compromis : le rédacteur ne peut pas casser la mise en page en ajoutant une quatrième carte qui déborderait visuellement, mais garde la liberté de réorganiser l'ordre d'affichage.

### Un cas particulier : le bloc enfant seul

Le bloc « carte » lui-même n'a rien de spécial : c'est un bloc classique avec ses propres attributs (`titre`, `texte`, `image`), sourcés comme on l'a vu dans un précédent article. La seule contrainte est de veiller à ce que son `save()` produise un balisage cohérent avec les styles CSS pensés pour s'insérer dans la grille du parent.

> Évitez de dupliquer une logique métier entre le bloc parent et ses enfants : laissez chaque bloc gérer ses propres attributs, et réservez au parent uniquement la mise en page globale (classes CSS du conteneur, nombre de colonnes, etc.).

## En résumé

`InnerBlocks` ouvre la voie à des blocs véritablement composés, où chaque partie reste éditable indépendamment tout en respectant une structure imposée par le développeur. Les trois leviers à retenir : `allowedBlocks` pour limiter les blocs autorisés à l'intérieur, `template` pour préconfigurer une structure de départ, et `templateLock` pour geler partiellement ou totalement cette structure une fois le bloc inséré. Combinés intelligemment, ils permettent de livrer des composants de mise en page robustes, sans jamais sacrifier la liberté d'édition sur le contenu lui-même.
