Comment afficher, dans l’éditeur, exactement ce que verra le visiteur d’un bloc dont tout le rendu est calculé en PHP ? C’est la question que se pose tôt ou tard quiconque développe un bloc dynamique un peu élaboré : une liste d’articles filtrée, un widget météo, un comparateur de prix. Écrire deux fois la même logique, une fois en PHP pour le front, une fois en JavaScript pour l’éditeur, revient à maintenir deux vérités qui finissent toujours par diverger.
Le composant ServerSideRender, fourni par le paquet @wordpress/server-side-render, règle ce problème d’une façon élégante : il envoie les attributs du bloc à une requête REST interne qui exécute le render_callback PHP déclaré dans block.json, puis affiche le HTML renvoyé directement dans le canevas de l’éditeur. Aucune traduction de logique, aucun risque de décalage entre les deux rendus.
Pourquoi save() ne convient pas à un bloc entièrement dynamique
Pour un bloc dynamique, la fonction save() ne doit renvoyer qu’un espace réservé, souvent null, ou au mieux un balisage minimal mis en cache côté serveur via les attributs sérialisés dans le commentaire de bloc. Le vrai rendu se produit à l’exécution, côté PHP, via render_callback ou la clé render de block.json pointant vers un fichier render.php. Sans aide particulière, l’éditeur ne peut donc rien montrer de représentatif : il faudrait soit reproduire la requête et la mise en forme en JavaScript, soit se contenter d’un aperçu générique peu informatif, ce qui dégrade l’expérience d’édition et multiplie les allers-retours vers l’aperçu du site.
Le compromis que beaucoup de développeurs tentent d’abord
La première tentation consiste à reproduire une version simplifiée de la requête WP_Query en JavaScript avec apiFetch, puis à formater le résultat à la main dans edit(). Cela fonctionne un temps, jusqu’au jour où une règle métier change côté PHP (un filtre sur le statut de publication, une condition d’affichage liée à une taxonomie) sans que personne ne pense à répercuter le changement dans l’éditeur. Le bloc affiche alors deux réalités différentes selon qu’on l’édite ou qu’on le consulte.

Mettre en place ServerSideRender pas à pas
- Installer la dépendance si elle n’est pas déjà présente via
wordpress-scripts:@wordpress/server-side-renderfait partie des paquets officiels et n’a pas besoin d’installation séparée si votre bloc est généré avec@wordpress/create-block. - Importer le composant dans
edit.js:import ServerSideRender from '@wordpress/server-side-render';. - Retourner le composant dans la fonction
Edit, en lui passant le nom de bloc et les attributs courants. - Vérifier que
block.jsondéclare bien un rendu serveur (clérenderou enregistrement PHP avecrender_callback). - Tester chaque attribut modifiable depuis l’inspecteur pour confirmer que le rendu se met à jour sans rechargement de page.
Le code minimal ressemble à ceci :
import ServerSideRender from '@wordpress/server-side-render';
import { useBlockProps } from '@wordpress/block-editor';
export default function Edit( { attributes } ) {
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<ServerSideRender
block="mon-agence/derniers-articles"
attributes={ attributes }
/></serversiderender>
</div>
);
}
Passer les bons attributs et éviter les appels inutiles
ServerSideRender relance automatiquement la requête REST à chaque changement de l’objet attributes. C’est pratique, mais cela peut aussi déclencher une avalanche de requêtes si un champ texte déclenche un nouvel appel à chaque frappe. Deux précautions limitent ce phénomène.
- Ne passer dans
attributesque ce qui influence réellement le rendu PHP, pas des réglages purement visuels gérés côté éditeur. - Débattre légèrement la saisie côté
edit()(par exemple avec un court délai avant de committer la valeur danssetAttributes) pour les champs texte libres qui déclenchent un recalcul serveur coûteux. - Prévoir, côté PHP, un cache transitoire pour les requêtes lourdes (nombre d’articles important, tri complexe) afin que l’aperçu reste réactif même en cas de rafales de rendus.
Gérer le chargement, les erreurs et l’absence de contenu
Le composant expose des propriétés optionnelles utiles en production : LoadingResponsePlaceholder et EmptyResponsePlaceholder permettent de personnaliser respectivement l’état d’attente et le cas où la requête renvoie un contenu vide. Sans personnalisation, l’affichage par défaut reste correct mais générique ; pour un bloc destiné à être utilisé par des rédacteurs peu familiers du jargon technique, un message clair du type « Aucun article ne correspond à ces critères pour le moment » évite bien des questions au support.
Sur nos projets, nous ajoutons systématiquement un
EmptyResponsePlaceholderpersonnalisé dès qu’un bloc dépend d’un filtre ou d’une taxonomie : un aperçu vide sans explication ressemble trop souvent à un bloc cassé aux yeux d’un rédacteur.
Limites à connaître avant de généraliser l’approche
ServerSideRender n’est pas gratuit en performance : chaque bloc affiché dans l’éditeur déclenche sa propre requête REST, ce qui peut ralentir sensiblement le chargement d’une page contenant de nombreuses instances du même bloc dynamique. Pour un bloc rarement dupliqué (un bandeau d’alerte, un widget météo unique), l’impact reste négligeable. Pour un bloc répété des dizaines de fois sur une même page (une carte produit dans une boucle), mieux vaut envisager un rendu partiel côté JavaScript avec un rafraîchissement plus ponctuel, ou accepter un aperçu simplifié dans l’éditeur au profit de la fluidité de rédaction.
En résumé
ServerSideRender reste la solution la plus directe pour garantir la fidélité entre ce qu’un rédacteur voit dans l’éditeur et ce que verra le visiteur, sans dupliquer la moindre ligne de logique métier. Son coût principal est le nombre de requêtes REST déclenchées, qu’il convient de surveiller sur les blocs à fort taux de répétition. Pour un bloc dynamique unique par page, c’est aujourd’hui l’option la plus fiable et la plus rapide à mettre en œuvre.