# Développer un widget imbriqué Elementor avec Widget_Nested_Base

> Créer un widget Elementor à enfants modifiables, sur le modèle des nested elements, avec la classe Widget_Nested_Base et son pendant JavaScript.

- Auteur : WordPress Développement
- Publié le : 2023-10-19
- Mis à jour le : 2026-09-30
- Catégorie : Elementor
- URL : https://www.wpmoderne.fr/elementor/widget-imbrique-elementor-widget-nested-base/

## L’essentiel

- Widget_Nested_Base gère un conteneur avec des enfants imbriqués
- Chaque enfant reste un vrai container éditable
- Le rendu JavaScript doit répliquer fidèlement le PHP

Depuis l'introduction des nested elements (Tabs et Accordion imbriqués), Elementor propose une base spécifique pour construire ce type de widget : `Widget_Nested_Base`. Contrairement à un widget classique qui hérite de `Widget_Base` et affiche un contenu figé par ses propres contrôles, un widget imbriqué délègue une partie de son contenu à des containers enfants que l'utilisateur peut remplir librement avec n'importe quel widget Elementor.

Pour un client qui voulait un widget « Étapes » présentant un processus en plusieurs blocs numérotés, chacun pouvant contenir un texte libre, une image ou même un bouton, la solution la plus propre était de construire ce widget sur ce modèle plutôt que de multiplier les champs répéteur classiques.

## Structure de base de la classe PHP

Un widget imbriqué étend `\Elementor\Modules\NestedElements\Base\Widget_Nested_Base` et doit définir le nombre de conteneurs enfants ainsi que leurs identifiants via la méthode `get_default_children_elements` ou par un contrôle répéteur qui pilote leur nombre :

```
class Widget_Etapes extends \Elementor\Modules\NestedElements\Base\Widget_Nested_Base {

    public function get_name() {
        return 'widget-etapes';
    }

    public function get_title() {
        return __( 'Étapes', 'mon-theme' );
    }

    public function get_icon() {
        return 'eicon-numbered-list';
    }

    protected function register_controls() {
        $repeater = new \Elementor\Repeater();
        $repeater->add_control(
            'titre_etape',
            [
                'label' => __( 'Titre de l\'étape', 'mon-theme' ),
                'type' => \Elementor\Controls_Manager::TEXT,
                'default' => __( 'Étape', 'mon-theme' ),
            ]
        );

        $this->add_control(
            'etapes',
            [
                'label' => __( 'Étapes', 'mon-theme' ),
                'type' => \Elementor\Controls_Manager::REPEATER,
                'fields' => $repeater->get_controls(),
                'prevent_empty' => true,
                'default' => [
                    [ 'titre_etape' => __( 'Analyse', 'mon-theme' ) ],
                    [ 'titre_etape' => __( 'Conception', 'mon-theme' ) ],
                ],
            ]
        );
    }
}
```

## Récupérer et rendre les containers enfants

La particularité de `Widget_Nested_Base` tient à sa méthode `get_default_children_elements`, qui définit combien de containers enfants existent, en fonction par exemple du nombre d'entrées du répéteur. Chaque container enfant reçoit un identifiant stable qu'il faut utiliser pour son rendu PHP :

```
protected function get_default_children_elements() {
    $repeater_items = $this->get_settings( 'etapes' );
    $children = [];

    foreach ( $repeater_items as $index => $item ) {
        $children[] = [
            '_element_id' => 'etape-' . $index,
        ];
    }

    return $children;
}

protected function content_template() {
    // Le rendu JS répète la même logique via Backbone/Marionette.
}
```

> L'essentiel à retenir : Widget_Nested_Base gère un conteneur avec des enfants imbriqués ; Chaque enfant reste un vrai container éditable ; Le rendu JavaScript doit répliquer fidèlement le PHP

Le rendu final du widget doit ensuite parcourir les enfants avec `print_child( $index )` pour afficher le container correspondant à l'endroit voulu dans le HTML :

```
protected function render() {
	$settings = $this->get_settings_for_display();
	$etapes   = $settings['etapes'];

	echo '<ol class="widget-etapes">';

	foreach ( $etapes as $index => $etape ) {
		echo '<li class="widget-etapes__item">';
		echo '<h3 class="widget-etapes__titre">' . esc_html( $etape['titre_etape'] ) . '</h3>';
		echo '<div class="widget-etapes__contenu">';
		$this->print_child( $index );
		echo '</div>';
		echo '</li>';
	}

	echo '</ol>';
}
```

La méthode `print_child()` affiche le container enfant situé à la position donnée. L'ordre des enfants suit celui du répéteur : le troisième élément du répéteur correspond au troisième container. Cette correspondance par position est la clé de tout le widget, et aussi la source des erreurs les plus fréquentes, que nous verrons plus bas.

## Enregistrer le widget et activer la fonctionnalité

Comme tout widget, la classe s'enregistre auprès du gestionnaire de widgets d'Elementor, sur le crochet dédié :

```
add_action( 'elementor/widgets/register', function ( $widgets_manager ) {
	require_once __DIR__ . '/class-widget-etapes.php';
	$widgets_manager->register( new Widget_Etapes() );
} );
```

Les widgets imbriqués reposent sur le module des éléments imbriqués d'Elementor, qui, à la date de cet article, reste associé à des fonctionnalités expérimentales activables dans les réglages d'Elementor. Si le widget ne s'affiche pas dans le panneau ou si ses enfants ne se créent pas, vérifiez d'abord cette activation avant de chercher une erreur dans votre code.

## Une précision sur la classe de base

Le nom complet de la classe de base dépend de la version d'Elementor installée : dans les versions publiées du plugin, elle se trouve dans l'espace de noms des éléments imbriqués (`\Elementor\Modules\NestedElements\Base\Widget_Nested_Base`). Les widgets Tabs et Accordion imbriqués livrés avec Elementor sont les meilleures références : ouvrez leur code dans le dossier du plugin, vous y verrez les méthodes à définir, dont `get_default_children_elements()` et la méthode qui indique la clé du répéteur utilisée comme titre des enfants. Ces deux méthodes sont déclarées abstraites dans la classe de base : une classe qui les oublie provoque une erreur fatale dès le chargement.

La méthode `get_default_children_elements()` décrit les containers créés automatiquement lors de l'ajout du widget : chaque entrée est un tableau avec le type `container` et ses réglages, comme un titre interne affiché dans le Navigateur d'Elementor. Le contrôle répéteur propre aux éléments imbriqués, que les widgets Tabs et Accordion utilisent à la place du répéteur ordinaire, synchronise l'ajout et la suppression d'une ligne avec celle d'un container. Avec un répéteur ordinaire, cette synchronisation n'existe pas : il faudrait la réaliser soi-même en JavaScript. C'est pourquoi la lecture du code de ces widgets de référence vaut mieux que n'importe quel résumé.

## Le rendu côté éditeur

Dans l'éditeur, Elementor n'appelle pas `render()` : il affiche le widget à partir d'un gabarit JavaScript défini par la méthode `content_template()`, écrit avec la syntaxe d'Underscore (`<# ... #>` pour le code, `{{ ... }}` pour l'affichage échappé). Ce gabarit doit reproduire le balisage produit par PHP : mêmes balises, mêmes classes. Sinon, l'aperçu en direct ne ressemble pas à la page publiée, et les styles écrits pour l'une ne s'appliquent pas à l'autre.

Pour les enfants, le gabarit ne les affiche pas lui-même : il prévoit leur emplacement, que l'éditeur remplit ensuite avec les containers réels. C'est le rôle de la méthode qui retourne le sélecteur de l'élément accueillant les enfants, et de celle qui désigne le sélecteur de chaque emplacement. Un sélecteur inexact se traduit par des containers qui apparaissent au mauvais endroit, ou pas du tout, dans le panneau d'édition.

## Un cas concret : le widget Étapes d'une page de service

Le client voulait présenter un parcours en quatre étapes : diagnostic, devis, réalisation, suivi. Avec des champs classiques, chaque étape aurait été limitée à un titre et un paragraphe. Avec des containers enfants, l'équipe éditoriale peut placer dans la deuxième étape un tableau de tarifs, dans la troisième une galerie, dans la dernière un bouton de prise de rendez-vous. Le widget ne fournit que la structure : la liste numérotée, le titre de chaque étape, et les styles communs. Le contenu, lui, reste entièrement libre et modifiable sans toucher au code.

> Un bon widget imbriqué ne décide pas de ce qu'il contient : il décide de la façon dont son contenu s'organise.

## Les pièges à éviter

- Faire diverger le gabarit JavaScript et le rendu PHP : l'éditeur et le site public ne montrent alors pas la même chose.
- Supposer qu'un enfant existe à chaque position du répéteur : `print_child()` ne fait rien si le container est absent, ce qui masque un décalage plutôt que de le signaler.
- Coder en dur le nombre de containers sans relier le répéteur : l'utilisateur ajoute une ligne, et aucun container n'apparaît.
- Oublier les styles : un container enfant hérite de ses propres réglages de largeur et de marges, qui s'ajoutent à ceux de votre structure.
- Ne pas tester avec un contenu volumineux dans chaque enfant : les widgets imbriqués alourdissent le document, et un parcours de vingt étapes se ressent à l'affichage.

## Quand ne pas utiliser un widget imbriqué

Si le contenu de chaque bloc se limite à un titre, un texte et une icône, un répéteur classique suffit et reste plus léger : un seul élément dans le document au lieu d'un container par ligne. Le widget imbriqué se justifie lorsque les blocs doivent accueillir des widgets variés, ou lorsque les rédacteurs doivent pouvoir les composer librement. Il se justifie moins pour un composant figé, que l'on maintiendra plus facilement avec un simple widget et ses contrôles.

## Conclusion

Un widget imbriqué d'Elementor repose sur trois piliers : une classe PHP qui décrit ses enfants et les affiche avec `print_child()`, un contrôle qui relie les lignes aux containers, et un gabarit JavaScript fidèle au rendu public. La fonctionnalité évoluant vite, appuyez-vous sur le code des widgets livrés avec le plugin plutôt que sur votre mémoire, et testez à chaque mise à jour d'Elementor.
