class WP_HTML_Tag_Processor — cette simple ligne, apparue dans le cœur de WordPress avec la version 6.2, a changé ma façon de corriger de vieux thèmes sans toucher à leurs templates. Avant, modifier le HTML généré par the_content voulait dire manipuler des expressions régulières fragiles ou charger DOMDocument, avec son lot d’avertissements sur du HTML mal formé. Ce n’est plus nécessaire.
Le cas concret : un thème client vieux de plusieurs années, sans aucune gestion de chargement différé sur les images du contenu, hérité d’une génération de sites où cette pratique n’était pas encore un réflexe. Réécrire le moteur de rendu du contenu était hors budget ; injecter l’attribut au bon endroit via un filtre l’était beaucoup moins.
Pourquoi ne pas simplement activer le lazy-load natif du cœur
Le lazy-load natif de WordPress, actif par défaut depuis la 5.5, s’applique aux images insérées via la bibliothèque de médias avec les fonctions de balisage du cœur. Mais dans ce thème hérité, une partie des images du contenu provenait d’un ancien import qui avait figé le HTML sans passer par les fonctions habituelles, et une extension tierce désactivait par ailleurs le filtre natif pour des raisons de compatibilité avec un plugin de accélération de page. Le résultat : des images jamais concernées par le lazy-load automatique.
Plutôt que de démêler ce conflit avec l’extension tierce, j’ai choisi de reprendre la main directement sur le contenu affiché, en amont de l’affichage final.

Parcourir le contenu avec WP_HTML_Tag_Processor
La classe fonctionne comme un curseur qui se déplace de balise en balise dans une chaîne HTML, sans construire d’arbre DOM complet. On la positionne sur chaque balise img avec next_tag(), puis on ajoute l’attribut manquant avec set_attribute().
add_filter( 'the_content', function ( $contenu ) {
$processeur = new WP_HTML_Tag_Processor( $contenu );
while ( $processeur->next_tag( 'img' ) ) {
if ( null === $processeur->get_attribute( 'loading' ) ) {
$processeur->set_attribute( 'loading', 'lazy' );
}
}
return $processeur->get_updated_html();
} );
La vérification get_attribute( 'loading' ) avant l’écriture évite d’écraser un réglage déjà présent sur certaines images (par exemple celles volontairement marquées eager pour l’image mise en avant). C’est ce genre de détail qui distingue un correctif propre d’un correctif qui casse une exception légitime.
Exclure la première image pour ne pas pénaliser le LCP
Ajouter loading="lazy" à toutes les images sans distinction dégrade souvent le Largest Contentful Paint lorsque l’image concernée est visible dès le chargement de la page. J’ai donc ajouté un compteur pour ignorer la première occurrence :
$processeur = new WP_HTML_Tag_Processor( $contenu );
$index = 0;
while ( $processeur->next_tag( 'img' ) ) {
$index++;
if ( 1 === $index ) {
continue;
}
if ( null === $processeur->get_attribute( 'loading' ) ) {
$processeur->set_attribute( 'loading', 'lazy' );
}
}
Cette nuance a suffi à faire remonter le score Core Web Vitals du site sans toucher une seule ligne des templates existants du thème.
Les limites de l’approche
- Le curseur ne traite qu’une balise à la fois : impossible de raisonner sur la hiérarchie parent-enfant comme avec un DOM complet.
- Le filtre s’applique à chaque affichage de
the_content, donc à chaque requête si aucun cache de page n’est en place ; un cache d’objet ou de page reste recommandé pour un site à fort trafic. - Le contenu doit rester un minimum bien formé : des balises jamais fermées peuvent perturber le repérage, même si la classe est tolérante sur ce point.
Une méthode transposable à d’autres attributs
Au-delà du lazy-load, la même classe permet d’ajouter des attributs decoding="async", de nettoyer des classes CSS orphelines laissées par un ancien éditeur, ou d’injecter rel="noopener" sur des liens externes oubliés — toujours sans réécrire les templates concernés.
Sur un thème hérité, je préfère toujours ce type de filtre ciblé à une réécriture complète du moteur de rendu : le risque de régression est bien plus faible, et le correctif tient dans une vingtaine de lignes de
functions.php.
Notre verdict
WP_HTML_Tag_Processor est l’outil qu’il fallait pour ce genre de correctif ciblé sur un vieux thème : pas de dépendance externe, pas de réécriture de gabarit, un comportement prévisible même sur du HTML imparfait. Pour toute modification ponctuelle du balisage généré par the_content, c’est aujourd’hui mon premier réflexe avant d’envisager une extension tierce.