samedi 26 septembre 2026

À propos

Contact

Extensions

Deux extensions, une priorité de hook identique : trancher le conflit

Un client s'étonne qu'une remise sur son panier disparaisse un jour sur deux. La cause : deux extensions accrochées au même filtre, à la même priorité, activées dans un ordre qui varie.

Par Clément Hadrot • 23 avril 2021 • 5 min de lecture • Aucun commentaire
Deux extensions, une priorité de hook identique : trancher le conflit

Une boutique en ligne de matériel de sport applique deux traitements sur le total du panier : une extension maison calcule une remise de fidélité, une extension du marché applique un code promotionnel saisi par le client. Les deux sont accrochées au filtre woocommerce_cart_calculate_fees, toutes deux sans argument de priorité explicite, donc toutes deux à la valeur par défaut de 10.

Le comportement observé varie d’un jour à l’autre sans logique apparente : parfois la remise de fidélité s’applique avant le code promo et le calcul est correct, parfois c’est l’inverse et le montant final est légèrement différent de ce qu’attendait le client. Après une semaine d’allers-retours avec le support, l’équipe technique reproduit enfin le problème et en isole la cause exacte.

Ce que dit la documentation, et ce qu’elle ne dit pas

La documentation officielle de add_filter() et add_action() précise que la priorité détermine l’ordre d’exécution des fonctions accrochées à un même hook, les valeurs les plus basses s’exécutant en premier. Elle précise aussi que la priorité par défaut vaut 10. Ce qu’elle n’explicite pas clairement, c’est le comportement à priorité strictement égale entre plusieurs callbacks.

Dans les faits, à priorité égale, WordPress exécute les callbacks dans l’ordre où ils ont été enregistrés en mémoire au cours de la requête, ce qui correspond la plupart du temps à l’ordre de chargement des extensions actives, lui-même déterminé par l’ordre alphabétique des noms de dossier de plugin, sauf modification manuelle de cet ordre par un administrateur dans l’écran plugins.php.

Le fil qui a permis de comprendre

L'essentiel à retenir : À priorité égale, l'ordre d'exécution suit l'ordre d'activation des extensions ; Réactiver une extension change cet ordre sans prévenir personne ; Fixer une priorité explicite et documentée évite ce hasard

L’équipe a d’abord suspecté un cache, puis un problème de session. La piste s’est débloquée en ajoutant un traçage temporaire directement dans les deux callbacks :

add_filter( 'woocommerce_cart_calculate_fees', function( $cart ) {
    error_log( 'Remise fidélité exécutée à ' . microtime( true ) );
    // logique de remise...
} );

En comparant les journaux entre un jour où le calcul était correct et un jour où il ne l’était pas, l’équipe a constaté que l’ordre d’exécution des deux callbacks s’était littéralement inversé entre les deux journées, sans qu’aucun code n’ait changé. La cause : une mise à jour automatique de l’extension de code promo, survenue une nuit, qui avait désactivé puis réactivé le plugin dans le cadre du processus de mise à jour. Cette réactivation avait modifié sa position dans la liste des extensions actives stockée en base, et donc son ordre de chargement, et donc l’ordre d’exécution du filtre à priorité égale.

La correction

La solution retenue a été de fixer explicitement des priorités différentes et documentées pour chaque callback métier sensible à l’ordre, plutôt que de laisser le hasard du chargement décider :

// Remise de fidélité : doit s'appliquer avant tout code promotionnel.
add_filter( 'woocommerce_cart_calculate_fees', 'appliquer_remise_fidelite', 20 );

// Le code promotionnel de l'extension tierce s'exécute par défaut en priorité 10,
// donc bien après la remise de fidélité ci-dessus.

Un commentaire explicite au-dessus de chaque déclaration de priorité rappelle pourquoi ce chiffre a été choisi, pour que le prochain développeur qui touche ce code comprenne l’intention plutôt que de la redécouvrir à la dure.

Comment prévenir ce type de conflit

  • Ne jamais laisser la priorité par défaut sur un hook métier où l’ordre d’exécution a un impact financier ou fonctionnel visible.
  • Lister, pour chaque hook critique de l’application, les extensions qui s’y accrochent, à l’aide d’un outil de débogage comme Query Monitor, qui affiche précisément les callbacks et leur priorité pour chaque hook déclenché.
  • Retester le comportement métier après chaque mise à jour d’une extension tierce connue pour s’accrocher aux mêmes hooks, pas seulement après une mise à jour de son propre code.

Un point souvent mal compris

Beaucoup de développeurs pensent, à tort, que l’ordre d’activation dans l’écran d’administration des extensions est figé une fois pour toutes. En réalité, toute désactivation suivie d’une réactivation, y compris automatique dans le cadre d’une mise à jour, peut modifier cet ordre stocké dans l’option active_plugins. Un code qui dépend implicitement de cet ordre, sans priorité explicite, repose donc sur une hypothèse fragile qui peut se briser à tout moment, y compris sans intervention humaine directe.

Une priorité identique entre deux extensions n’est jamais un accord tacite, c’est une pièce jetée en l’air à chaque nouvelle requête.

En résumé

Ce cas illustre un piège rarement documenté explicitement : deux hooks à priorité égale ne garantissent aucun ordre stable dans le temps, car cet ordre dépend d’un état, la liste des extensions actives, qui peut changer sans avertissement lors d’une mise à jour automatique. Fixer des priorités explicites et documentées reste la seule protection fiable contre ce genre de conflit silencieux entre extensions qui ne se connaissent pas.

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