AccueilBlogDéveloppement WordpressWordPress Gutenberg et RGAA : Comment résoudre le problème des balises <figure> pour l’accessibilité

WordPress Gutenberg et RGAA : Comment résoudre le problème des balises <figure> pour l’accessibilité

Le problème : Gutenberg génère des balises <figure> non conformes RGAA

Depuis l’arrivée de l’éditeur Gutenberg dans WordPress, un problème récurrent se pose pour les sites devant respecter le RGAA (Référentiel Général d’Amélioration de l’Accessibilité) : l’éditeur génère automatiquement des balises <figure> autour des images, mais sans respecter totalement les exigences du critère 1.9.

Qu’est-ce qui pose problème ?

Gutenberg génère ce type de HTML :

<figure class="wp-block-image">
    <img src="image.jpg" alt="Description" />
    <figcaption>Légende de l'image</figcaption>
</figure>

Selon le critère 1.9 du RGAA, une image avec légende doit respecter ces conditions :

  • La balise <figure> doit avoir un attribut role="figure" ou role="group"
  • La balise <figure> doit avoir un attribut aria-label identique au contenu de la légende
  • La légende doit être dans une balise <figcaption>

Le code généré par Gutenberg ne respecte pas ces exigences, notamment l’absence des attributs role et aria-label.

L’impact réel sur l’accessibilité

Bonne nouvelle : selon les experts d’Access42, bien que le code ne respecte pas techniquement le RGAA 4.1, il n’y a aucun impact utilisateur réel. Les lecteurs d’écran restituent correctement l’information.

Cependant, pour un audit RGAA strict, ce point sera signalé comme non conforme.

Solutions techniques

Solution 1 : Filtre PHP pour supprimer les balises <figure>

La solution la plus pragmatique consiste à remplacer automatiquement les balises <figure> par des <div> :

// À ajouter dans functions.php
function remove_figure_from_content_smart($content) {
    // Pour les images dans le contenu des articles (wp-block-image)
    $content = preg_replace_callback(
        '/<figure([^>]*class="[^"]*wp-block-image[^"]*"[^>]*)>(.*?)<\/figure>/is',
        function($matches) {
            $attributes = $matches[1];
            $inner_content = $matches[2];
            
            $inner_content = preg_replace('/<figcaption([^>]*)>/', '<div$1 class="wp-element-caption">', $inner_content);
            $inner_content = str_replace('</figcaption>', '</div>', $inner_content);
            
            return '<div' . $attributes . '>' . $inner_content . '</div>';
        },
        $content
    );
    
    return $content;
}

// Version pour les images à la une dans les templates
function remove_figure_from_featured_images($html) {
    if (strpos($html, '<figure') !== false && strpos($html, '<img') !== false) {
        $html = preg_replace('/<figure([^>]*)>/', '<div$1>', $html);
        $html = preg_replace('/<\/figure>/', '</div>', $html);
        $html = preg_replace('/<figcaption([^>]*)>/', '<div$1 class="wp-element-caption">', $html);
        $html = str_replace('</figcaption>', '</div>', $html);
    }
    return $html;
}

// Application ciblée pour éviter les conflits
add_filter('the_content', 'remove_figure_from_content_smart', 999);
add_filter('post_thumbnail_html', 'remove_figure_from_featured_images', 999);
add_filter('render_block_core/post-featured-image', 'remove_figure_from_featured_images', 999);
add_filter('render_block_core/image', 'remove_figure_from_content_smart', 999);

Solution 2 : CSS pour neutraliser la sémantique

Alternative moins intrusive :

.wp-block-image figure {
    display: contents;
}

Cette approche conserve le HTML mais neutralise visuellement les balises <figure>.

Pièges à éviter

Filtres trop globaux

Évitez d’appliquer les transformations sur tous les blocs avec render_block sans distinction, cela peut casser la mise en page des templates FSE et des pages d’archive.

Solution qui pose problème

// ❌ NE PAS UTILISER - Casse la mise en page
add_filter('render_block', function($block_content, $block) {
    return remove_figure_from_all_content($block_content);
}, 999, 2);

Cette approche trop large peut transformer des éléments de structure (Query Loop, Post Template) et détruire complètement la mise en page de votre site.

Test insuffisant

Vérifiez toujours après implémentation :

  • Pages d’articles individuels (contenu principal)
  • Pages d’archive/blog (mise en page en colonnes)
  • Pages avec images à la une (templates)
  • Éléments de modèle FSE (header, footer)

Cas particuliers à surveiller

Images à la une et éléments de modèle

Les images à la une (featured images) et les éléments de modèle FSE peuvent également générer des balises <figure>. Le filtre proposé couvre ces cas grâce aux hooks spécifiques :

  • post_thumbnail_html pour les images à la une
  • render_block_core/post-featured-image pour les blocs FSE

Contenu existant vs nouveau contenu

Important : Les filtres PHP ne s’appliquent qu’au rendu, pas au contenu stocké. Pour les contenus existants :

  • Les filtres fonctionnent automatiquement à l’affichage
  • Pas besoin de rééditer le contenu existant
  • La solution CSS peut compléter si nécessaire

Recommandations pour la conformité RGAA

  1. Implémenter le filtre PHP ciblé pour une solution technique propre
  2. Ajouter le CSS de secours pour une couverture complète
  3. Documenter la dérogation en citant l’absence d’impact utilisateur (source Access42)
  4. Tester avec des lecteurs d’écran pour confirmer la bonne restitution

Conclusion

Le problème des balises <figure> de Gutenberg illustre parfaitement la complexité de l’accessibilité web : un code techniquement non conforme peut être parfaitement utilisable.

La solution proposée offre un bon compromis entre conformité technique RGAA et pragmatisme, tout en conservant l’expérience utilisateur des contributeurs WordPress. L’approche ciblée évite les écueils des solutions trop globales qui peuvent compromettre la stabilité du site.

Retour d’expérience : Attention aux filtres trop larges qui peuvent casser la mise en page ! Toujours tester sur l’ensemble du site après implémentation.

Ressources utiles

VOUS AVEZ UN PROJET ? CONTACTEZ-MOI POUR EN DISCUTER.