Masquer n’est pas retirer
Simplifier l’administration d’un client passe souvent par la réduction des widgets natifs proposés, quand certains — Méta, Calendrier, RSS — n’ont aucune utilité sur le site. La solution la plus rapide, mais la moins fiable, consiste à masquer ces entrées par une règle CSS. Ce masquage reste visuel : le widget demeure enregistré et réapparaît dès qu’une mise à jour modifie la structure HTML que vise la règle.
Retirer réellement le widget du registre

La fonction unregister_widget( $widget ), définie dans wp-includes/widgets.php, retire une classe de widget du registre tenu par l’objet global $wp_widget_factory (classe WP_Widget_Factory). Elle s’appelle dans une fonction accrochée au hook widgets_init, comme le précise sa propre documentation :
<?php
add_action( 'widgets_init', function () {
unregister_widget( 'WP_Widget_Meta' );
unregister_widget( 'WP_Widget_RSS' );
unregister_widget( 'WP_Widget_Calendar' );
} );
L’argument attendu est le nom exact de la classe PHP du widget, celui que le cœur passe à register_widget() : WP_Widget_Pages, WP_Widget_Archives, WP_Nav_Menu_Widget, etc., chacune dans son fichier de wp-includes/widgets/. Depuis WordPress 4.6, une instance de WP_Widget est aussi acceptée.
Le bon hook, et la seule priorité qui pose problème
Les widgets natifs ne sont pas enregistrés sur widgets_init, mais juste avant. La fonction wp_widgets_init(), accrochée à init avec la priorité 1, appelle register_widget() pour chacun d’eux, puis déclenche do_action( 'widgets_init' ) en dernière ligne. Au premier rappel de ce hook, tous les widgets du cœur figurent donc déjà dans le registre : unregister_widget() fonctionne avec la priorité par défaut 10, comme avec 1 ou 50.
La vraie limite est plus loin : WP_Widget_Factory accroche sa méthode _register_widgets() à widgets_init avec la priorité 100. C’est elle qui inscrit chaque classe restante dans $wp_registered_widgets, que lisent l’écran Widgets et les zones du thème. Après ce passage, le retrait n’enlève plus que la classe de la fabrique : le widget reste visible.
<?php
// init, priorité 1 : wp_widgets_init() enregistre les widgets natifs,
// puis déclenche widgets_init.
// widgets_init, priorités 1 à 99 : unregister_widget() est efficace.
// widgets_init, priorité 100 : WP_Widget_Factory::_register_widgets()
// inscrit les widgets restants dans $wp_registered_widgets.
add_action( 'widgets_init', 'mon_extension_retirer_widgets' );
- priorité inférieure à 100, y compris la valeur par défaut : le retrait est pris en compte ;
- priorité 100 : le résultat dépend de l’ordre d’ajout des rappels, à éviter ;
- priorité supérieure à 100 : trop tard, le widget est déjà inscrit ;
add_action()lancé depuis un rappel d’init:widgets_initest déjà passé, rien ne s’exécute. Placez-le dans le fichier principal de l’extension ou dansfunctions.php.
Une faute de casse échoue tout aussi silencieusement : le registre est indexé par le nom de classe, et unregister_widget( 'wp_widget_meta' ) ne retire rien.
Le pendant symétrique : register_widget
unregister_widget() retire simplement une entrée ajoutée par register_widget( $widget ), que le cœur comme les extensions utilisent pour déclarer un widget : même registre, même signature, même fichier source.
L’éditeur de widgets en blocs n’est pas concerné
Depuis WordPress 5.8, l’écran Widgets utilise par défaut l’éditeur de blocs. Les widgets classiques y passent par le bloc Ancien widget, qui masque déjà ceux dotés d’un bloc équivalent (Calendrier, RSS, Recherche…) via le filtre widget_types_to_hide_from_legacy_widget_block. Ce que l’utilisateur voit sous le nom Calendrier ou RSS dans l’inserteur, ce sont les blocs core/calendar et core/rss, que unregister_widget() ne touche pas. Pour les retirer de cet écran (contexte core/edit-widgets ; core/customize-widgets dans le Customizer), on filtre les blocs autorisés :
<?php
add_filter( 'allowed_block_types_all', function ( $autorises, $contexte ) {
if ( 'core/edit-widgets' !== $contexte->name ) {
return $autorises;
}
if ( true === $autorises ) {
$autorises = array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() );
}
return array_values( array_diff( (array) $autorises, array( 'core/calendar', 'core/rss' ) ) );
}, 10, 2 );
Ce que deviennent les instances déjà placées
Sur un site en production, le retrait a un effet immédiat en façade : dynamic_sidebar() ignore toute instance dont l’identifiant (calendar-2, par exemple) n’existe plus dans $wp_registered_widgets. Un Calendrier placé dans une barre latérale disparaît, sans erreur. Sa référence disparaît de la zone au prochain enregistrement de la configuration des widgets, tandis que ses réglages restent dans l’option widget_calendar. Mieux vaut donc relever les zones concernées avant d’intervenir. Les blocs déjà insérés ne sont pas affectés.
Conclusion
Le CSS masque, unregister_widget() retire : appelé sur widgets_init à une priorité inférieure à 100, il supprime le widget de l’écran classique, du bloc Ancien widget et des zones du thème. Restent à vérifier les instances placées et, dans l’éditeur en blocs, les blocs équivalents.