Le WordPress d'aujourd'hui, décodé pour les développeurs

Éditeur de site (FSE)

Des résultats inattendus dans un tri de gabarits, faute d’un === en PHP

Un gabarit toujours relégué en fin de liste, alors que son ordre déclaré le plaçait en premier : la cause tenait à une comparaison PHP trop permissive, pas au tri lui-même.

Par WordPress Développement • 19 août 2024 • 4 min de lecture • Aucun commentaire
Des résultats inattendus dans un tri de gabarits, faute d'un === en PHP

« Le gabarit d’accueil personnalisé s’affiche toujours en dernier dans le sélecteur, jamais en premier comme prévu » : ce signalement, remonté par une cliente qui gérait elle-même l’ordre d’affichage de plusieurs gabarits personnalisés dans un menu déroulant du thème, a mis plusieurs jours à être reproduit de façon fiable, avant qu’un test isolé ne révèle un comportement systématique lié à un seul indice précis.

Symptôme : un ordre correct pour tous, sauf un

Le thème proposait un tableau $ordre_gabarits, déclaré dans functions.php, qui fixait l’ordre d’affichage souhaité des gabarits personnalisés dans un menu de navigation secondaire. Chaque gabarit devait apparaître à la position définie par cet ordre, sauf celui placé explicitement en première position, qui se retrouvait systématiquement relégué en toute fin de liste, quel que soit le contenu réel du tableau.

Diagnostic : un retour de fonction confondu avec un booléen

L'essentiel à retenir : array_search peut renvoyer 0, une valeur parfaitement valide mais faussement falsy ; Une condition if sur ce retour doit toujours vérifier !== false ; Le bug ne se manifeste que pour le premier élément d'une liste, ce qui retarde sa découverte

Le code responsable du tri s’appuyait sur array_search() pour retrouver la position déclarée d’un gabarit, avant de l’utiliser comme clé de tri :

foreach ( $gabarits as $gabarit ) {
    $position = array_search( $gabarit->slug, $ordre_gabarits );

    if ( $position ) {
        $gabarit->ordre = $position;
    } else {
        $gabarit->ordre = 999;
    }
}

array_search() renvoie l’indice de l’élément trouvé dans le tableau, ou false si l’élément est absent. Pour le premier élément du tableau $ordre_gabarits, cet indice vaut 0 — une valeur entière parfaitement valide, mais que PHP considère comme fausse dans un contexte booléen, exactement comme false lui-même. La condition if ( $position ) traitait donc ce cas comme un échec de recherche, et affectait au gabarit concerné l’ordre par défaut réservé aux éléments non trouvés.

Correctif : une comparaison stricte au type

Le correctif consiste à remplacer la comparaison implicite par une comparaison stricte, explicitement au type, pour distinguer 0 (une position valide) de false (une absence réelle) :

foreach ( $gabarits as $gabarit ) {
    $position = array_search( $gabarit->slug, $ordre_gabarits );

    if ( $position !== false ) {
        $gabarit->ordre = $position;
    } else {
        $gabarit->ordre = 999;
    }
}

Après ce changement, le gabarit d’indice 0 dans $ordre_gabarits retrouvait sa position réelle, et le tri final produisait l’ordre attendu pour l’ensemble des gabarits, sans exception.

Pourquoi ce bug est resté invisible aussi longtemps

La condition fautive fonctionnait correctement pour tous les indices supérieurs à zéro, qui restent évalués comme vrais dans un contexte booléen. Seul l’élément placé en première position du tableau déclenchait le comportement incorrect, ce qui explique pourquoi les tests menés en modifiant l’ordre des autres gabarits ne révélaient jamais le problème : il fallait spécifiquement placer un gabarit en tout premier pour l’observer.

Prévention pour la suite

  • traiter systématiquement le retour de array_search(), strpos() ou array_key_first() avec une comparaison stricte au type, jamais avec une simple condition implicite ;
  • ajouter un test unitaire dédié qui place explicitement un élément en position 0, précisément parce que ce cas limite échappe facilement à une relecture rapide du code ;
  • activer un niveau d’analyse statique du code qui signale les comparaisons implicites sur des fonctions dont le retour peut valoir zéro ou une chaîne vide en cas de succès.

Nous relisons systématiquement tout usage de array_search(), strpos() ou array_search() dans une revue de code, en cherchant explicitement l’absence d’un !== false : c’est l’un des rares réflexes de relecture qui a un rapport temps investi contre bugs évités aussi favorable.

Ce qu’il faut retenir

Ce bug n’avait rien d’exotique : il s’agit d’une des confusions les plus documentées du langage PHP, entre une valeur falsy légitime et une absence de résultat. Sa discrétion tenait uniquement au fait qu’il ne se manifestait que pour un seul indice précis d’un tableau, ce qui l’a rendu difficile à isoler tant que personne n’avait pensé à tester spécifiquement ce cas limite.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

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

Voir tous ses articles

Dans la même veine

À lire aussi