Le design pattern Observer et WordPress : pourquoi les hooks, c'est (presque) génial
Si tu bosses sur WordPress depuis un moment, tu as forcément utilisé des actions (add_action()
) et des filtres (add_filter()
). C’est grâce à eux que tu peux modifier le comportement du CMS sans toucher au core. Ce système est super puissant, mais est-ce que tu savais qu’il repose sur un design pattern bien connu en dev : le pattern Observer ?
Aujourd’hui, on va voir ensemble :
- C'est quoi ce pattern Observer ?
- Pourquoi WordPress l'utilise ?
- Comment ça marche dans le code ?
- Les limites et problèmes des hooks (parce que oui, il y a des choses à redire).
- Comment on pourrait améliorer tout ça.
Bref, on va décortiquer ce système pour mieux comprendre pourquoi WordPress a choisi cette approche… et comment ils auraient pu faire autrement.
Le design pattern Observer en deux mots
Imagine une newsletter. Tu veux envoyer un mail à tes abonnés dès qu’un nouvel article est publié. Le problème, c’est que tu ne veux pas savoir à l’avance combien de personnes sont abonnées. Tu veux juste leur envoyer un mail dès qu’il y a un nouvel article.
En gros, tu as un sujet (Observable) : la newsletter. Et plusieurs [observateurs (Observers) : les abonnés. Quand le sujet change (nouvel article), il notifie tous les observateurs.
Exemple en PHP
class Newsletter {
private $subscribers = [];
public function subscribe(Subscriber $subscriber) {
$this->subscribers[] = $subscriber;
}
public function notify($articleTitle) {
foreach ($this->subscribers as $subscriber) {
$subscriber->update($articleTitle);
}
}
}
interface Subscriber {
public function update($articleTitle);
}
class User implements Subscriber {
private $email;
public function __construct($email) {
$this->email = $email;
}
public function update($articleTitle) {
echo "Email envoyé à {$this->email} : Nouvel article publié - {$articleTitle}\n";
}
}
Ici, la newsletter ne sait pas combien de personnes sont abonnées. Elle balance juste l’info aux observateurs.
C’est exactement comme ça que marchent les hooks dans WordPress.
Comment WordPress implémente le pattern Observer avec les hooks
WordPress a un système qui permet d’exécuter du code sans modifier le cœur du CMS. Deux types de hooks existent :
- Les actions (
do_action()
) : elles déclenchent du code à un moment donné. - Les filtres (
apply_filters()
) : elles permettent de modifier une valeur avant qu’elle ne soit utilisée.
Exemple : le hook init
add_action('init', function() {
error_log('WordPress est initialisé');
});
Là, on dit juste à WordPress : “Quand init
est appelé, exécute cette fonction”.
Analyse du fonctionnement interne
Quand add_action()
est appelé, WordPress enregistre l’action dans $wp_filter
, une variable globale qui stocke tous les hooks sous forme de tableau associatif.
-
Enregistrement du callback
add_action('init', 'ma_fonction_personnalisee');
Cela ajoute
ma_fonction_personnalisee
à la liste des fonctions à exécuter lorsquedo_action('init')
est appelé. -
Déclenchement de l’action
do_action('init');
Quand WordPress atteint ce point dans son cycle d’exécution, il va :
- Chercher toutes les fonctions enregistrées pour
init
dans$wp_filter
. - Exécuter chaque fonction dans l’ordre de leur priorité.
- Chercher toutes les fonctions enregistrées pour
-
Gestion des priorités
add_action('init', 'fonction_prioritaire', 5); add_action('init', 'fonction_normale', 10);
Plus le nombre est petit, plus la fonction est exécutée tôt.
Ce mécanisme permet une grande flexibilité, mais il présente aussi des limites que nous allons explorer.
Le problème du système de hooks de WordPress
Bon, maintenant qu’on a vu comment ça marche, parlons des défauts. Parce que oui, tout n’est pas rose dans WordPress.
1. Tout est stocké dans une globale ($wp_filter
)
WordPress utilise $wp_filter
, une grosse variable globale qui contient tous les hooks.
Problèmes :
- Aucune encapsulation : n’importe quel plugin peut modifier cette variable, ce qui rend le debug et la maintenance compliqués.
- Absence de validation : impossible de vérifier les types de callbacks enregistrés.
- Dépendance aux globales : ce qui empêche une gestion plus fine des événements.
Solution : utiliser une classe encapsulée
class HookManager {
private static $hooks = [];
public static function addHook($hookName, $callback) {
self::$hooks[$hookName][] = $callback;
}
public static function trigger($hookName, $args) {
if (!array_key_exists($hookName, self::$hooks)) {
return;
}
foreach (self::$hooks[$hookName] as $callback) {
call_user_func($callback, $args);
}
}
}
Avec ça, on vire la dépendance aux globales et on structure mieux les hooks.
Je vous laisserais juger par vous même de l’implémentation avec des méthodes statiques.
2. Pas d’autocomplétion, galère à déboguer
Quand tu bosses sur WordPress, impossible de savoir tous les hooks existants sans checker la doc. Tu dois deviner… et souvent c’est frustrant.
Problèmes :
-
Pas d’auto-complétion : il faut chercher dans la documentation ou fouiller dans le code.
-
Manque de typage strict : aucune garantie que les arguments passés aux hooks soient valides.
Solution : une énumération des hooks
class CoreHooks {
public const INIT = 'init';
public const WP_HEAD = 'wp_head';
}
Avec ça, fini les fautes de frappe ('init' vs 'initt'). Et ton IDE te propose des suggestions directes.
3. Un nombre variable de paramètres sans typage clair
Dans WordPress, lorsqu’on attache une fonction à un hook, on peut lui passer un nombre variable d’arguments via le quatrième paramètre d’add_action
et add_filter
. Cela entraîne des problèmes de lisibilité et d’intelligibilité du code.
Problèmes :
- Les signatures de fonctions ne sont pas explicites : il faut connaître le contexte exact pour comprendre quels paramètres sont passés.
- Impossible d’utiliser l’autocomplétion et le typage strict.
Solution : passer un Data Transfer Object comme paramètre unique
class InitArgs {
public function __construct(
public string $context,
public array $data
) {}
}
add_action('init', function(InitArgs $args) {
error_log('Contexte : ' . $args->context);
});
Avec cette approche, on a toujours un seul paramètre typé et on évite de devoir compter sur des arguments variables mal définis.
Conclusion : un système puissant mais vieillissant
Le système de hooks de WordPress est une excellente application du pattern Observer, mais il date d’une époque où PHP n’avait ni typage strict, ni autoloading standardisé. Aujourd’hui, une refonte avec moins de globales, plus de typage, une meilleure gestion des priorités et une documentation plus rigoureuse améliorerait grandement la maintenabilité.
Que penses-tu du système de hooks de WordPress ? As-tu déjà rencontré ses limites en développement ?