Chapitre 5.2 — Hooks : actions & filtres
⏱️ TL;DR — Les hooks sont le mécanisme d’extension de WordPress, et le concept le plus important de tout le cours. Deux types : les actions (« à ce moment, fais quelque chose » — on exécute du code) et les filtres (« avant d’utiliser cette valeur, laisse-moi la modifier » — on transforme une donnée et on la retourne). Vous vous attachez à un hook avec
add_action()/add_filter(). Le cœur, les thèmes et les plugins déclenchent des hooks (do_action()/apply_filters()) à des points clés. Maîtriser ce système, c’est pouvoir tout étendre sans jamais toucher au cœur.
🎯 Objectifs
- Distinguer action et filtre et savoir quand utiliser lequel.
- Écrire
add_action/add_filteravec priorité et nombre d’arguments. - Comprendre
do_action/apply_filters(déclencher ses propres hooks). - Éviter les pièges classiques (filtre qui ne retourne rien, priorité, retrait de hook).
1. L’idée : un système de publication/abonnement
WordPress, en s’exécutant, annonce des moments (« je suis à l’init », « je vais afficher le titre », « j’enregistre un article »). Votre code s’abonne à ces annonces pour réagir. C’est un patron observateur / événementiel.
💡 Pour un dev React — Les actions sont des event listeners :
on('init', callback)→ on réagit à un événement, sans valeur de retour. Les filtres sont des middlewares de transformation :value = filters.reduce((v, fn) => fn(v), initial)→ chaque abonné reçoit la valeur, la transforme, et retourne la nouvelle. Toute la personnalisation de WordPress passe par ces deux primitives. Si vous ne devez retenir qu’une chose du cours : action = faire, filtre = transformer-et-retourner.
2. Les actions : faire quelque chose à un moment
Une action exécute du code à un point donné. Aucune valeur retournée.
// S'abonner : « quand WordPress arrive à init, exécute ma fonction »
add_action( 'init', 'mon_prefixe_demarrer' );
function mon_prefixe_demarrer() {
// enregistrer un CPT, un shortcode, etc.
}Le cœur déclenche l’action ainsi (vous ferez pareil dans vos plugins) :
do_action( 'init' ); // « j'y suis » → tous les callbacks abonnés s'exécutentExemples d’actions du cœur : init, wp_enqueue_scripts, save_post (un article vient d’être enregistré), admin_menu, wp_footer.
3. Les filtres : transformer une donnée
Un filtre reçoit une valeur, la modifie, et doit la retourner.
// « avant d'afficher le titre, laisse-moi le modifier »
add_filter( 'the_title', 'mon_prefixe_suffixe_titre' );
function mon_prefixe_suffixe_titre( $title ) {
return $title . ' ✨'; // ⚠️ TOUJOURS retourner la valeur
}Le cœur applique le filtre ainsi :
$title = apply_filters( 'the_title', $title ); // la valeur passe par tous les callbacksExemples de filtres du cœur : the_title, the_content, body_class, wp_nav_menu_items, pre_get_posts (technique : modifie l’objet query), rest_prepare_post (Partie 9).
⚠️ Piège n°1 — un filtre qui ne retourne rien. Oublier le
returndans un filtre écrase la valeur parnull: le titre disparaît, le contenu devient vide. Un filtre retourne TOUJOURS (au minimum la valeur reçue inchangée). C’est l’erreur la plus fréquente du débutant.
4. Priorité et nombre d’arguments
add_action/add_filter acceptent deux paramètres supplémentaires :
add_filter( 'the_content', 'mon_cb', 20, 1 );
// hook callback ^^ ^
// priorité --´ `-- nombre d'arguments passés au callback- Priorité (défaut
10) : ordre d’exécution. Plus petit = plus tôt. Deux callbacks à10s’exécutent dans l’ordre d’ajout ; un à5passe avant un à20. - Nombre d’arguments (défaut
1) : combien d’arguments le hook transmet à votre callback. Si un hook fournit 3 infos et que vous en voulez 2, il faut le déclarer :
// save_post transmet ($post_id, $post, $update)
add_action( 'save_post', 'mon_cb', 10, 3 );
function mon_cb( $post_id, $post, $update ) { /* … */ }⚠️ Piège n°2 — l’argument manquant. Si votre callback attend
$postmais que vous n’avez pas déclaré3(ou au moins2) comme nombre d’arguments, WordPress ne vous passe que le premier →$postestnull. Alignez toujours le 4ᵉ paramètre sur ce que votre fonction consomme.
5. Déclencher ses propres hooks (rendre son code extensible)
Vos plugins/thèmes peuvent exposer leurs propres hooks, pour que d’autres (ou vous-même plus tard) les étendent — c’est une marque de code pro :
// Dans votre plugin : offrir un point d'extension
do_action( 'wpr_books_apres_import', $livre_id );
$prix = apply_filters( 'wpr_books_prix_affiche', $prix, $livre_id );Ainsi, un autre développeur peut faire add_action('wpr_books_apres_import', …) sans modifier votre code. C’est exactement ce que fait WooCommerce (des centaines de hooks) pour être si extensible (Partie 10).
6. Retirer, vérifier, contexte
remove_action( 'wp_head', 'wp_generator' ); // retirer un callback du cœur
remove_filter( 'the_content', 'wpautop' ); // idem pour un filtre
has_action( 'init', 'mon_cb' ); // vérifier
current_action(); doing_action('init'); // introspectionPour retirer un hook, il faut le même nom de callback et la même priorité que lors de l’ajout — d’où l’intérêt de fonctions nommées (plutôt que des closures anonymes, difficiles à retirer).
⚠️ Piège n°3 — la closure impossible à retirer.
add_action('init', function(){ … });fonctionne, mais est impossible àremove_action(pas de référence nommée). Pour du code que d’autres pourraient devoir désactiver, préférez une fonction nommée ou une méthode de classe avec une référence stable.
7. Où placer ses hooks
- Dans un plugin (Partie 7) ou le
functions.phpdu thème (Partie 6), chargés au bootstrap (ch. 5.1). - On enregistre les hooks au chargement (pas dans une condition tardive) ; le callback, lui, s’exécutera au bon moment.
- Bonne pratique : préfixer ses fonctions (
monprefixe_…) pour éviter les collisions de noms dans l’espace global de PHP (pas de namespaces imposés par WordPress, Partie 7).
✏️ Exercices
- Vous voulez ajouter « (Lecture : 3 min) » à la fin du contenu de chaque article. Action ou filtre ? Sur quel hook ? Écrivez le squelette.
- Vous voulez envoyer un e-mail à chaque publication d’article. Action ou filtre ? Quel hook ?
- Un développeur se plaint que le titre de ses articles est devenu vide après avoir ajouté un filtre
the_title. Quelle est la cause la plus probable ?
✅ Solution
- Filtre (on transforme une valeur, le contenu) sur
the_content:
add_filter( 'the_content', 'monprefixe_temps_lecture' );
function monprefixe_temps_lecture( $content ) {
return $content . '<p><em>Lecture : 3 min</em></p>'; // retourne la valeur modifiée
}- Action (on fait quelque chose, envoyer un mail, sans transformer de valeur) sur
save_post(oupublish_post/transition_post_statuspour cibler la publication). - Le filtre ne retourne pas la valeur (
returnoublié) → le titre est écrasé parnull. Un filtre doit toujours retourner (au moins la valeur reçue).
🧠 Quiz de révision
1. Différence entre une action et un filtre ?
Une action exécute du code à un moment (sans retour) ; un filtre reçoit une valeur, la modifie et la retourne.
2. Comment s’abonne-t-on à un hook ?
Avec add_action( $hook, $callback, $priorite, $nb_args ) ou add_filter( … ).
3. Que signifie une priorité de 5 vs 20 ?
Plus petit = plus tôt : la priorité 5 s’exécute avant la 20 (défaut : 10).
4. Que se passe-t-il si un filtre ne retourne rien ?
Il écrase la valeur par null (contenu/titre vide) : un filtre doit toujours retourner.
5. Comment rendre son propre plugin extensible ?
En déclenchant ses propres hooks avec do_action() / apply_filters() aux points clés.
Chapitre suivant : La Boucle (The Loop).