vendredi 25 septembre 2026

À propos

Contact

Extensions

Hooks WordPress : comprendre enfin l’ordre d’exécution des actions et filtres

Priorités, nombre d'arguments, exécution une seule fois : ce qui se passe réellement quand deux extensions accrochent la même action au même moment.

Par Clément Hadrot • 19 mai 2020 • 6 min de lecture • Aucun commentaire
Hooks WordPress : comprendre enfin l'ordre d'exécution des actions et filtres

« J’ai ajouté mon add_action mais rien ne se passe. » C’est probablement la phrase la plus tapée dans les forums de support WordPress depuis quinze ans. Neuf fois sur dix, le problème n’est pas dans la fonction accrochée mais dans la compréhension de l’ordre d’exécution : à quel moment le hook se déclenche, avec quelle priorité, et avec quels arguments.

Cet article revient sur les mécanismes du système de hooks de WordPress, actions et filtres, avec une attention particulière portée aux subtilités qui piègent même des développeurs expérimentés : la gestion de la priorité, le nombre d’arguments, et les hooks qui ne se déclenchent qu’une seule fois par requête.

Actions et filtres : une distinction qui a un sens

Une action, déclenchée par do_action(), exécute du code sans attendre de retour. Elle sert à « faire quelque chose » : enregistrer un type de contenu, envoyer un e-mail, écrire un log. Un filtre, déclenché par apply_filters(), transforme une valeur et attend systématiquement un retour :

// Action : on ne retourne rien
add_action( 'init', function () {
    register_post_type( 'produit', [ /* ... */ ] );
} );

// Filtre : on DOIT retourner la valeur, même inchangée
add_filter( 'the_title', function ( $title ) {
    if ( is_singular( 'produit' ) ) {
        $title .= ' — en stock';
    }
    return $title;
} );

Oublier le return dans un filtre est une erreur fréquente chez les développeurs qui débutent : la fonction retourne alors null par défaut, et la valeur filtrée disparaît purement et simplement pour tous les filtres exécutés après le vôtre.

La priorité : un ordre d’exécution, pas une importance

Le troisième argument de add_action() et add_filter() est la priorité, avec une valeur par défaut de 10. Plus le nombre est bas, plus le callback s’exécute tôt :

add_action( 'init', 'ma_fonction_precoce', 5 );
add_action( 'init', 'ma_fonction_normale' );      // priorité 10 implicite
add_action( 'init', 'ma_fonction_tardive', 20 );

Un cas d’usage classique : retirer un hook ajouté par le cœur de WordPress ou par une autre extension. Si cette dernière a accroché sa fonction avec la priorité 10, votre remove_action doit préciser exactement la même priorité, sinon WordPress ne trouvera rien à retirer :

// Ne fonctionne que si l'extension tierce a utilisé la priorité 10
remove_action( 'wp_head', 'wp_generator' );

// Si l'extension a utilisé une priorité différente, il faut la connaître
remove_action( 'wp_head', [ $instance_extension_tierce, 'afficher_meta' ], 15 );

Ce deuxième cas révèle une vraie difficulté : retirer un hook attaché en tant que méthode d’objet nécessite d’avoir accès à la même instance d’objet que celle qui a fait l’ajout. Si cette instance a été créée dans une closure sans être exposée, il est tout simplement impossible de retirer le hook depuis l’extérieur. C’est un argument fort pour, en tant qu’auteur d’extension, toujours documenter et si possible exposer les instances de classes qui s’accrochent aux hooks.

L'essentiel à retenir : La priorité par défaut est 10, pas 0 ; Un filtre doit toujours retourner une valeur ; remove_action exige les mêmes arguments qu'à l'ajout

Le nombre d’arguments, souvent oublié

Le quatrième paramètre d’add_action précise combien d’arguments WordPress doit transmettre au callback. Par défaut, il vaut 1, ce qui provoque une erreur silencieuse fréquente :

// save_post transmet normalement 3 arguments : $post_id, $post, $update
add_action( 'save_post', function ( $post_id, $post, $update ) {
    // $post et $update seront TOUJOURS null ici
    if ( $update ) {
        // ce code ne s'exécute jamais
    }
} );

// Correction : préciser le nombre d'arguments attendus
add_action( 'save_post', function ( $post_id, $post, $update ) {
    if ( $update ) {
        // fonctionne correctement
    }
}, 10, 3 );

PHP n’émet aucune erreur dans ce cas : les paramètres surnuméraires de la closure reçoivent simplement leur valeur par défaut ou null. C’est un bug silencieux qui peut rester en production pendant des mois avant d’être détecté, en général le jour où la logique conditionnée par le troisième argument doit enfin se déclencher.

Un hook peut se déclencher plusieurs fois par requête

Certains hooks, comme the_content ou wp_footer, ne s’exécutent qu’une fois. D’autres, comme save_post ou pre_get_posts, peuvent se déclencher plusieurs fois dans une même requête HTTP : un enregistrement en cascade dans l’administration, une requête secondaire lancée par un widget. Sans garde-fou, une fonction accrochée à save_post qui déclenche elle-même une sauvegarde (par exemple via wp_update_post) peut provoquer une boucle infinie.

add_action( 'save_post', function ( $post_id ) {
    // Retirer temporairement le hook évite la boucle infinie
    remove_action( 'save_post', __FUNCTION__ );

    update_post_meta( $post_id, '_derniere_maj', current_time( 'mysql' ) );

    add_action( 'save_post', __FUNCTION__ );
} );

Ce schéma « désaccrocher, agir, raccrocher » est un classique du développement d’extensions WordPress et mérite d’être connu par cœur, car l’oubli provoque des ralentissements difficiles à diagnostiquer plutôt qu’un plantage franc.

Vérifier qu’un hook est bien enregistré

Deux fonctions natives aident au diagnostic sans installer d’extension de debug supplémentaire :

  • has_action( 'save_post', 'ma_fonction' ) retourne la priorité si le hook est enregistré, false sinon.
  • did_action( 'init' ) retourne le nombre de fois qu’une action a déjà été déclenchée, utile pour éviter une double exécution.

Avant de suspecter WordPress ou une extension tierce, on commence toujours par vérifier la priorité et le nombre d’arguments déclarés : dans notre expérience, ces deux points expliquent l’immense majorité des « hooks qui ne se déclenchent pas ».

Tableau récapitulatif

ParamètreValeur par défautPiège fréquent
Priorité10Oubli lors d’un remove_action ciblant une autre priorité
Nombre d’arguments1Arguments supplémentaires silencieusement à null
Retour d’un filtreaucun par défautAbsence de return qui efface la valeur

En résumé

Le système de hooks est d’une simplicité trompeuse. Sa puissance vient justement de règles précises — priorité, nombre d’arguments, obligation de retour pour les filtres — qu’il faut connaître pour éviter des heures de débogage. Avant de conclure qu’un hook « ne marche pas », vérifiez systématiquement ces trois points : ils résolvent l’écrasante majorité des cas.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi