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

Accessibilité

wp_unique_id() pour générer un identifiant fiable reliant un champ à son erreur

Pour relier un champ de formulaire à son message d'erreur via aria-describedby, il faut un identifiant stable. La fonction cœur wp_unique_id() remplace avantageusement le compteur maison.

Par WordPress Développement • 16 juin 2025 • 5 min de lecture • Aucun commentaire
wp_unique_id() pour générer un identifiant fiable reliant un champ à son erreur

wp_unique_id( 'champ-erreur-' ) renvoie une chaîne du type champ-erreur-3, garantie unique tant que le process PHP est en vie. C’est peu de choses en apparence, mais c’est exactement ce qu’il manque à la majorité des formulaires personnalisés pour relier correctement un champ à son message d’erreur avec l’attribut aria-describedby.

Sans identifiant fiable, les développeurs improvisent : un compteur statique dans une variable globale, un rand() optimiste, ou pire, l’ID du champ recopié tel quel pour former l’ID du message d’erreur. Ces solutions tiennent tant que le formulaire n’apparaît qu’une fois par page. Dès qu’un même bloc de formulaire se répète — un composant produit affiché en boucle, une modale de contact dupliquée par un constructeur de pages — les identifiants entrent en collision et l’attribut aria-describedby pointe vers le mauvais message, ou vers rien du tout.

Le problème du compteur maison

Un compteur maison ressemble en général à ceci : une variable statique incrémentée à chaque appel d’une fonction de rendu. Cela fonctionne dans un contexte simple, linéaire, où le développeur contrôle entièrement le nombre d’appels. Mais WordPress ne garantit rien de tel. Un shortcode peut être exécuté deux fois par un thème mal écrit qui appelle do_shortcode() en prévisualisation puis en rendu final. Un bloc dynamique peut être rendu côté serveur puis re-rendu côté client par l’Interactivity API. Le compteur repart alors de zéro, ou saute des valeurs, et deux champs distincts se retrouvent avec le même identifiant.

Le symptôme est presque toujours silencieux visuellement : la page s’affiche normalement, seul un lecteur d’écran révèle que le message d’erreur annoncé ne correspond pas au bon champ, ou n’est jamais annoncé du tout parce que le navigateur ne trouve pas l’élément ciblé par aria-describedby.

La fonction wp_unique_id() du cœur

WordPress expose depuis longtemps la fonction wp_unique_id( string $prefix = '' ) dans wp-includes/functions.php. Elle maintient un compteur interne au processus, protégé des collisions inter-appels, et accepte un préfixe explicite pour garder des identifiants lisibles dans le code source généré. Contrairement à un identifiant basé sur un hachage ou un timestamp, elle reste courte et déterministe pour la durée de la requête, ce qui suffit très largement : l’identifiant n’a besoin d’être unique que le temps où le navigateur affiche la page.

L'essentiel à retenir : Un identifiant unique par requête, sans collision entre instances ; Remplace les compteurs statiques fragiles en cas de rendu multiple ; Fonctionne aussi bien en PHP classique qu'en rendu de bloc dynamique

Le snippet commenté

Voici l’implémentation typique pour un champ de formulaire personnalisé, en dehors de tout framework de validation :

function afficher_champ_avec_erreur( $label, $name, $valeur, $erreur = '' ) {
    $id_champ  = wp_unique_id( 'champ-' );
    $id_erreur = wp_unique_id( 'erreur-' );

    $html  = '<label for="' . esc_attr( $id_champ ) . '">' . esc_html( $label ) . '</label>';
    $html .= '<input type="text" id="' . esc_attr( $id_champ ) . '" name="' . esc_attr( $name ) . '"';
    $html .= ' value="' . esc_attr( $valeur ) . '"';

    if ( $erreur ) {
        $html .= ' aria-invalid="true" aria-describedby="' . esc_attr( $id_erreur ) . '"';
    }

    $html .= ' />';

    if ( $erreur ) {
        $html .= '<p id="' . esc_attr( $id_erreur ) . '" class="champ-erreur">' . esc_html( $erreur ) . '</p>';
    }

    return $html;
}

Deux appels successifs de cette fonction produisent des identifiants distincts, même si le même formulaire est rendu trois fois sur la même page — un cas fréquent avec un bloc « Formulaire de contact » réutilisé dans une bibliothèque de modèles.

Les variantes utiles

  • Préfixer par le nom du champ plutôt que par un terme générique, pour retrouver plus vite l’origine d’un identifiant en inspectant le DOM.
  • Appeler wp_unique_id() une seule fois par champ et stocker le résultat dans une variable locale, plutôt que de le régénérer à chaque endroit où l’identifiant est utilisé — sinon aria-describedby et l’attribut id divergent.
  • Dans un rendu de bloc dynamique via render_callback, générer l’identifiant à l’intérieur de la fonction de rendu, jamais dans un attribut statique du bloc, pour éviter qu’il soit mis en cache par une extension de cache de pages.

Pour les blocs qui s’hydratent ensuite côté client avec l’Interactivity API, il faut garder à l’esprit que l’identifiant généré côté serveur doit rester stable après hydratation : ne recalculez jamais un nouvel identifiant côté client pour un élément déjà présent dans le HTML initial, sous peine de casser la relation établie par aria-describedby au premier rendu.

Ce que cette fonction ne résout pas

Générer un identifiant fiable n’est qu’une brique. Elle ne dit rien sur le moment où le message d’erreur doit apparaître, ni sur la manière de l’annoncer à un lecteur d’écran si le champ est déjà focalisé au moment où l’erreur survient — cela relève d’une région aria-live ou d’un déplacement de focus, traité séparément. wp_unique_id() garantit uniquement que la relation structurelle entre le champ et son texte d’erreur pointe vers le bon élément.

Une astuce éprouvée sur nos projets : centraliser la génération d’identifiants dans une petite fonction utilitaire du thème, appelée partout où un champ et son erreur doivent être reliés. Cela évite qu’un développeur, six mois plus tard, réintroduise un compteur statique par habitude.

En résumé

Remplacer un compteur maison par wp_unique_id() ne demande que quelques minutes et élimine une classe entière de bugs d’accessibilité liés à la duplication de contenu. C’est un des rares cas où la solution la plus simple est aussi la plus robuste : une fonction du cœur, déjà chargée, déjà testée, qui évite d’écrire et de maintenir sa propre logique de génération d’identifiants.

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