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 attributrole="figure"
ourole="group"
- La balise
<figure>
doit avoir un attributaria-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 unerender_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
- Implémenter le filtre PHP ciblé pour une solution technique propre
- Ajouter le CSS de secours pour une couverture complète
- Documenter la dérogation en citant l’absence d’impact utilisateur (source Access42)
- 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.