# register_widget en 2020 : construire encore un widget classique a-t-il un sens ?

> Les blocs gagnent du terrain, mais une extension distribuée à des centaines de thèmes classiques ne peut pas ignorer register_widget aussi facilement.

- Auteur : WordPress Développement
- Publié le : 2020-06-05
- Mis à jour le : 2026-09-30
- Catégorie : Extensions
- URL : https://www.wpmoderne.fr/extensions/register-widget-2020-widget-classique-sens/

## L’essentiel

- Un widget classique reste lisible par tous les thèmes, blocs ou non
- L'éditeur de widgets par blocs de 5.8 n'existe pas encore en juin 2020
- Le vrai critère est le parc de thèmes que l'extension doit couvrir

Une agence maintient une extension d'affichage d'avis clients, distribuée à environ deux cents sites construits avec des dizaines de thèmes différents, dont une bonne moitié encore sur des bases classiques héritées de 2016 ou 2017, sans le moindre bloc Gutenberg dans leurs zones de widgets. La question posée en réunion d'équipe est simple : faut-il encore, en 2020, écrire un nouveau widget avec `register_widget()`, ou est-ce du temps perdu sur une API qu'on annonce mourante depuis l'arrivée de l'éditeur de blocs ?

La réponse ne tient pas à une mode technique, mais au parc réel que l'extension doit servir. Et pour une extension multi-thèmes destinée à durer, ignorer les widgets classiques revient à couper l'accès à une bonne partie de sa base installée.

## Ce que Gutenberg a changé, et ce qu'il n'a pas changé

Depuis WordPress 5.0, l'éditeur de blocs a remplacé l'éditeur de contenu classique, et un widget de type bloc peut désormais être inséré dans un article ou une page comme n'importe quel autre bloc. Mais les zones de widgets de la barre latérale ou du pied de page, elles, continuent d'utiliser l'écran `widgets.php` classique, avec son système de glisser-déposer hérité. Rien dans le cœur de WordPress, à la date de cet article, ne transforme automatiquement ces zones en zones à blocs : ce chantier existe dans les discussions de la feuille de route de Gutenberg, mais aucune version publiée ne l'implémente encore.

Concrètement, un thème classique appelle toujours `dynamic_sidebar()` dans son fichier `sidebar.php`, et cette fonction continue de fonctionner exactement comme avant, en listant les widgets enregistrés via `register_widget()` et en les rendant dans l'ordre choisi par l'administrateur du site.

## Le cas où le widget classique reste justifié

> L'essentiel à retenir : Un widget classique reste lisible par tous les thèmes, blocs ou non ; L'éditeur de widgets par blocs de 5.8 n'existe pas encore en juin 2020 ; Le vrai critère est le parc de thèmes que l'extension doit couvrir

Pour une extension qui vise un public de thèmes variés, souvent installés depuis des années sur des sites de PME ou d'associations, register_widget reste le seul mécanisme garanti de fonctionner partout, sans supposer que le thème a été mis à jour ou reconstruit avec les blocs en tête. Voici un squelette minimal, conforme à l'API :

```
class Widget_Avis_Clients extends WP_Widget {

	public function __construct() {
		parent::__construct(
			'avis_clients',
			__( 'Avis clients', 'avis-clients' ),
			array(
				'classname'                   => 'widget-avis-clients',
				'description'                 => __( 'Affiche les derniers avis validés.', 'avis-clients' ),
				'customize_selective_refresh' => true,
			)
		);
	}

	public function widget( $args, $instance ) {
		$titre  = isset( $instance['titre'] ) ? $instance['titre'] : '';
		$nombre = isset( $instance['nombre'] ) ? absint( $instance['nombre'] ) : 3;

		echo $args['before_widget'];

		if ( $titre ) {
			echo $args['before_title'] . esc_html( apply_filters( 'widget_title', $titre, $instance, $this->id_base ) ) . $args['after_title'];
		}

		$avis = get_posts( array(
			'post_type'      => 'avis',
			'posts_per_page' => $nombre,
			'no_found_rows'  => true,
		) );

		foreach ( $avis as $un_avis ) {
			echo '<p class="avis">' . esc_html( get_the_title( $un_avis ) ) . '</p>';
		}

		echo $args['after_widget'];
	}

	public function form( $instance ) {
		$titre  = isset( $instance['titre'] ) ? $instance['titre'] : '';
		$nombre = isset( $instance['nombre'] ) ? absint( $instance['nombre'] ) : 3;
		?>
		<p>
			<label for="<?php echo esc_attr( $this->get_field_id( 'titre' ) ); ?>"><?php esc_html_e( 'Titre', 'avis-clients' ); ?></label>
			<input class="widefat" type="text"
				id="<?php echo esc_attr( $this->get_field_id( 'titre' ) ); ?>"
				name="<?php echo esc_attr( $this->get_field_name( 'titre' ) ); ?>"
				value="<?php echo esc_attr( $titre ); ?>">
		</p>
		<p>
			<label for="<?php echo esc_attr( $this->get_field_id( 'nombre' ) ); ?>"><?php esc_html_e( 'Nombre d’avis', 'avis-clients' ); ?></label>
			<input class="tiny-text" type="number" min="1" max="10" step="1"
				id="<?php echo esc_attr( $this->get_field_id( 'nombre' ) ); ?>"
				name="<?php echo esc_attr( $this->get_field_name( 'nombre' ) ); ?>"
				value="<?php echo esc_attr( $nombre ); ?>">
		</p>
		<?php
	}

	public function update( $nouvelle_instance, $ancienne_instance ) {
		return array(
			'titre'  => sanitize_text_field( $nouvelle_instance['titre'] ),
			'nombre' => min( 10, max( 1, absint( $nouvelle_instance['nombre'] ) ) ),
		);
	}
}

add_action( 'widgets_init', function () {
	register_widget( 'Widget_Avis_Clients' );
} );
```

Ce squelette contient tout ce que WordPress attend d'un widget. Le constructeur du parent reçoit l'identifiant de base, le nom affiché dans l'administration et un tableau d'options. La méthode `widget()` produit le rendu public, `form()` dessine le formulaire de l'administration, et `update()` nettoie les valeurs avant leur enregistrement. L'enregistrement lui-même se fait sur `widgets_init`, jamais plus tôt : à ce moment, le gestionnaire de widgets existe et les zones déclarées par les thèmes sont connues.

## Les quatre méthodes, une par une

Le constructeur n'a qu'une tâche, mais elle conditionne tout le reste. L'identifiant de base, ici `avis_clients`, sert de préfixe aux réglages stockés dans la table des options : WordPress conserve les instances d'un même widget dans une seule option, sous la forme `widget_avis_clients`. Changer cet identifiant après la mise en ligne fait perdre tous les réglages déjà saisis par les administrateurs, sans message d'erreur. Choisissez-le une fois pour toutes, et préfixez-le avec le nom de l'extension si vous craignez une collision.

La méthode `widget()` reçoit deux tableaux. Le premier, `$args`, provient de la zone de widgets : c'est le thème qui décide des balises `before_widget`, `after_widget`, `before_title` et `after_title`. Un widget qui ignore ces quatre clés s'affiche de travers dans la moitié des thèmes, puisque chacun attend son propre balisage. Le second, `$instance`, contient les réglages enregistrés pour cette instance précise, et peut être vide si le widget vient d'être ajouté : testez toujours l'existence de chaque clé.

La méthode `form()` s'appuie sur `get_field_id()` et `get_field_name()`. Ces deux fonctions fabriquent des attributs uniques par instance, ce qui permet de placer plusieurs fois le même widget dans la même zone sans que les champs se mélangent. Écrire l'attribut `name` à la main est l'erreur classique : le formulaire s'affiche, semble fonctionner, mais les valeurs ne sont jamais enregistrées.

Enfin, `update()` est le seul endroit où l'entrée de l'administrateur devient une donnée stockée. C'est là que l'on nettoie et que l'on borne : un nombre d'avis compris entre 1 et 10, un titre réduit à du texte brut. La protection à l'affichage, avec `esc_html()`, reste indispensable même si `update()` a déjà nettoyé, car une donnée peut arriver dans la base par une autre voie.

## Le cas concret : l'extension d'avis clients

Reprenons la situation de l'agence. L'extension affiche déjà les avis dans une page dédiée, grâce à un type de contenu propre. Les thèmes classiques qui la reçoivent proposent presque tous une barre latérale : un widget est donc le moyen le plus direct de montrer les trois derniers avis sur toutes les pages, sans demander au client de modifier un seul fichier du thème.

Deux décisions rendent ce widget durable. La première consiste à ne pas dupliquer la logique de récupération des avis : la boucle vit dans une fonction de l'extension, que le widget, un futur bloc et un shortcode appellent tous. La seconde consiste à limiter le coût : `no_found_rows` évite le calcul d'une pagination inutile, et le nombre d'avis reste borné par `update()`. Pour un widget affiché sur chaque page du site, ces deux précautions comptent davantage que l'élégance du code.

> Un widget n'est pas une fonctionnalité, c'est une vitrine : il doit rester mince, et laisser la logique vivre ailleurs, là où plusieurs interfaces pourront la réutiliser.

## Les pièges à éviter

- Changer l'identifiant de base ou le nom de la classe après une mise en production : les réglages enregistrés deviennent orphelins.
- Oublier `customize_selective_refresh` : le widget fonctionne, mais l'aperçu du personnalisateur se recharge entièrement à chaque frappe, ce qui donne une impression de lenteur.
- Faire des requêtes lourdes dans `widget()` sans mise en cache : le code s'exécute à chaque affichage de chaque page où la zone apparaît.
- Afficher du contenu sans échappement : le titre saisi dans l'administration est une donnée, pas du code de confiance.
- Enregistrer le widget trop tôt : en dehors de `widgets_init`, l'appel à `register_widget()` peut échouer silencieusement.

## Quand ne pas écrire un widget classique

Si votre extension s'adresse à un parc homogène de sites récents, construits avec des thèmes qui gèrent déjà les blocs dans leurs zones, l'investissement se déplace : un bloc dynamique, déclaré côté serveur avec une fonction de rendu, vous servira dans les articles, les pages et, selon l'évolution de l'éditeur, dans les zones de widgets. À la date de cet article, les zones de widgets par blocs ne sont encore qu'une expérimentation du plugin Gutenberg : s'y fier pour une extension distribuée à grande échelle serait prématuré.

Entre les deux, une stratégie prudente consiste à séparer le code : une fonction de rendu unique, un widget classique mince qui l'appelle, et un shortcode qui l'appelle aussi. Le jour où les zones de widgets accepteront les blocs en standard, vous n'aurez qu'à ajouter une couche, sans réécrire la logique.

## Conclusion

Écrire un widget classique en 2020 n'a rien d'archaïque, à condition de le faire pour les bonnes raisons : un parc de thèmes varié, des sites que personne ne reconstruira de sitôt, une API stable depuis des années. Le critère n'est pas la mode de l'éditeur, mais la réalité des installations que vous devez servir. Gardez le widget mince, nettoyez dans `update()`, échappez dans `widget()`, et préparez calmement la suite en isolant votre logique.
