vendredi 25 septembre 2026

À propos

Contact

Blocs Gutenberg

Code de blocs : les anti-patterns que nous refusons en revue

Attributs sourcés fragiles, save() dépendant de données externes, CSS global, dépendances non déclarées : la liste des refus systématiques, avec le correctif à chaque fois.

Par Clément Hadrot • 22 mars 2022 • 5 min de lecture • Aucun commentaire
Code de blocs : les anti-patterns que nous refusons en revue

Ce qu’on voit régulièrement en revue de code sur des blocs soumis par des prestataires externes ou des développeurs juniors : quatre erreurs reviennent avec une régularité frappante, chacune avec des conséquences concrètes qui n’apparaissent souvent qu’une fois le bloc en production depuis plusieurs mois.

Ce qu’on voit : des attributs sourcés en HTML fragile

"attributes": {
	"titre": {
		"type": "string",
		"source": "html",
		"selector": "h3.mon-titre"
	}
}

Pourquoi c’est un problème : cet attribut extrait sa valeur en cherchant un sélecteur CSS précis dans le HTML sauvegardé. Si un jour la classe mon-titre est renommée, ou si la balise passe de h3 à h4, tous les articles existants qui utilisent ce bloc deviennent invalides d’un coup, sans avertissement préalable.

Ce qu’on fait à la place : privilégier un attribut de type rich-text relié directement à un composant RichText, ou, si la source HTML est vraiment nécessaire, l’associer systématiquement à une stratégie de déprécation testée avant chaque changement de structure du save().

Ce qu’on voit : un save() qui dépend de données externes

L'essentiel à retenir : Un save() qui dépend de la base de données casse tôt ou tard ; Les attributs sourcés en HTML sont fragiles au moindre changement de balisage ; Le CSS global sans portée finit toujours par entrer en collision
// À éviter : le prix change en base, mais pas dans le contenu déjà sauvegardé
export default function save( { attributes } ) {
	return <p>{ attributes.prixAuMomentDeLaSauvegarde } €</p>;
}

Pourquoi c’est un problème : la fonction save() s’exécute une seule fois, au moment de l’enregistrement de l’article, et son résultat est figé dans le contenu HTML stocké en base. Elle n’a aucun accès à une base de données ou une API au moment où le navigateur affichera ensuite la page. Un prix qui change dans la fiche produit reste affiché à son ancienne valeur tant que l’article n’est pas rouvert et réenregistré manuellement.

Ce qu’on fait à la place : pour toute donnée susceptible de changer indépendamment du contenu de l’article, un bloc dynamique avec render_callback côté PHP reste la seule option fiable, puisqu’il recalcule le rendu à chaque affichage à partir de la source de vérité réelle, plutôt que depuis une valeur figée à l’écriture.

Ce qu’on voit : du CSS global sans portée

/* style.css d'un bloc, sans portée */
.titre {
	color: #1a1a1a;
	font-weight: 700;
}

Pourquoi c’est un problème : un sélecteur générique comme .titre s’applique à n’importe quel élément portant cette classe ailleurs sur le site, y compris dans le thème ou dans une autre extension. Le résultat est une collision silencieuse : un style pensé pour un bloc précis modifie l’apparence d’éléments complètement étrangers, souvent découvert bien après la mise en production.

Ce qu’on fait à la place : préfixer systématiquement les sélecteurs avec la classe générée par le bloc lui-même (.wp-block-mon-projet-encart .titre), ou utiliser un module CSS si la chaîne de build le permet, pour garantir que le style ne déborde jamais du périmètre du bloc.

Ce qu’on voit : des dépendances non déclarées

// index.js d'un bloc, avec une bibliothèque tierce importée
import { format } from 'date-fns';

Pourquoi c’est un problème : sans passer par @wordpress/scripts et son fichier .asset.php généré automatiquement, cette dépendance se retrouve simplement regroupée (« bundlée ») dans le fichier final du bloc, sans partage possible avec un autre bloc qui utiliserait la même bibliothèque. Sur un site avec plusieurs blocs, chacun embarquant sa propre copie de la même dépendance, le poids total du JavaScript chargé gonfle inutilement.

Ce qu’on fait à la place : vérifier systématiquement, après un build, la taille du fichier généré et son fichier .asset.php associé. Pour les dépendances déjà présentes dans @wordpress/* (comme @wordpress/date à la place de date-fns dans de nombreux cas), les préférer évite d’ajouter un poids supplémentaire déjà couvert par le cœur de WordPress.

  • Un attribut sourcé en HTML doit rester simple, ou passer par un composant natif comme RichText qui gère la source de manière robuste.
  • Un save() reste une fonction pure : mêmes attributs en entrée, même HTML en sortie, sans effet de bord ni dépendance externe.
  • Tout style de bloc doit être scoppé à la classe générée par le bloc, jamais à un sélecteur générique.
  • Toute dépendance tierce mérite une vérification de son poids réel une fois le build terminé.

Un bloc qui fonctionne parfaitement en local, sur un contenu de test unique, ne dit rien de sa robustesse une fois publié sur des centaines d’articles réels, avec des variantes de contenu que personne n’a anticipées en développement.

En résumé

Ces quatre anti-patterns partagent un point commun : ils fonctionnent tous parfaitement au moment où le bloc est livré, et ne posent problème que plus tard, au moment d’une modification de structure, d’une mise à jour de prix, ou d’un ajout de bloc supplémentaire sur le même site. Une revue de code qui se concentre sur ces quatre points évite l’essentiel des régressions observées en production.

Partager :

À propos de l'auteur

Clément Hadrot

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

Voir tous ses articles

Dans la même veine

À lire aussi