📍 Guide principal : Développement WordPress : plugins, thèmes et blocs. Ce tutoriel aborde la partie JavaScript de WordPress.
Introduction
Vos artisans sont en base de données, mais pour l’instant la seule façon de les afficher dans une page serait d’écrire du code dans un gabarit. Or vos clients veulent insérer une « liste d’artisans » eux-mêmes, depuis l’éditeur, comme ils insèrent un paragraphe ou une image. Cela suppose de créer un bloc Gutenberg. Et là, changement de décor : l’éditeur de blocs est une application React, et développer un bloc, c’est écrire du JavaScript moderne. Pour un développeur habitué au PHP, ce passage intimide. Ce tutoriel le dédramatise. À la fin, Annuaire Quartier proposera un bloc « Liste d’artisans » avec ses réglages dans la barre latérale, et un rendu calculé côté serveur pour rester toujours à jour.
🎯 Ce que vous allez apprendre
- Échafauder un bloc avec l’outil officiel
@wordpress/create-block. - Comprendre le rôle de
block.json, fiche d’identité du bloc. - Écrire le composant React de l’éditeur dans
edit.js. - Ajouter des réglages dans la barre latérale avec
InspectorControls. - Choisir un rendu dynamique en PHP via
render.php.
🛠️ Ce que vous allez construire
Un bloc insérable depuis l’éditeur, qui affiche une liste d’artisans. Dans la barre latérale, deux réglages : le nombre d’artisans à afficher et, en option, un filtre par métier. Côté visiteur, la liste sera générée à chaque affichage à partir des données réelles — ajoutez un artisan, il apparaît, sans rééditer la page.
Prérequis
- Le type « artisan » en place (voir types de contenu et métadonnées) et quelques fiches saisies.
- Node.js 20 ou plus récent et npm installés, car le code React doit être compilé.
- Des bases de JavaScript (variables, fonctions, objets). React s’apprend en chemin.
- Test express : si vous savez ouvrir un terminal et lancer une commande
npm, vous franchirez l’échafaudage sans peine. - ⏱️ Temps estimé : ~55 minutes.
Le modèle mental : statique contre dynamique
Un bloc a deux vies. Dans l’éditeur, c’est un composant React qui dessine une prévisualisation et propose des réglages : c’est le rôle d’edit.js. Côté visiteur, le bloc doit produire le HTML final. Deux stratégies existent. Un bloc statique fige son HTML au moment de l’enregistrement (fonction save). Un bloc dynamique ne fige rien : il exécute un bout de PHP à chaque affichage pour calculer son HTML. Pour une liste d’artisans qui s’allonge, le dynamique s’impose : on veut que la liste reflète toujours les données du jour, pas un instantané pris le jour de l’édition. C’est pourquoi notre bloc aura un render.php plutôt qu’une fonction save.
Étape 1 — Échafauder le bloc
On ne crée pas un bloc moderne à la main : l’outil officiel @wordpress/create-block génère toute la structure et la configuration de compilation. On demande la variante dynamique pour obtenir d’emblée un render.php. Placez-vous dans un dossier de travail et lancez la commande.
npx @wordpress/create-block@latest aq-liste-artisans --variant dynamic
L’outil télécharge ses dépendances et crée un dossier aq-liste-artisans/ contenant une extension complète : un fichier PHP d’enregistrement, un dossier src/ avec le code source (dont block.json, edit.js, render.php), et un package.json avec les scripts de compilation. À ce stade, vous avez déjà un bloc fonctionnel — basique, mais réel. L’idée n’est pas de tout garder, mais de comprendre chaque pièce et d’adapter la logique à nos artisans.
✅ Point d’étape — Le dossier
aq-liste-artisans/existe avec un sous-dossiersrc/. La commande s’est terminée sans erreur ; si elle a échoué, vérifiez votre version de Node.js (20 minimum).
Étape 2 — Lire block.json, la fiche d’identité
Le fichier src/block.json décrit le bloc de façon déclarative. WordPress le lit pour connaître le nom du bloc, sa catégorie dans l’insertion, ses réglages et les fichiers à charger. C’est le pivot du bloc moderne : on y déclare presque tout, et WordPress se charge du reste.
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "annuaire-quartier/liste-artisans",
"title": "Liste d'artisans",
"category": "widgets",
"icon": "groups",
"description": "Affiche une liste d'artisans de l'annuaire.",
"attributes": {
"nombre": { "type": "number", "default": 5 },
"metier": { "type": "string", "default": "" }
},
"supports": { "html": false },
"textdomain": "annuaire-quartier",
"editorScript": "file:./index.js",
"render": "file:./render.php"
}
L’apiVersion: 3 indique la génération actuelle de l’API des blocs. Le name doit suivre le format espace/bloc. Les attributes sont l’état du bloc : ici, un nombre d’artisans et un metier optionnel, avec leurs valeurs par défaut. Ce sont ces attributs que les réglages de la barre latérale modifieront, et que render.php lira. La ligne "render": "file:./render.php" est ce qui fait de notre bloc un bloc dynamique : pas de fonction save, c’est PHP qui produira le rendu public.
Étape 3 — Enregistrer le bloc côté JavaScript
Le fichier src/index.js est le point d’entrée JavaScript. Il importe les métadonnées du block.json, le composant d’édition, et appelle registerBlockType() pour déclarer le bloc auprès de l’éditeur. C’est volontairement minimal : la logique vit dans edit.js.
import { registerBlockType } from '@wordpress/blocks';
import Edit from './edit';
import metadata from './block.json';
registerBlockType( metadata.name, {
edit: Edit,
} );
On reconnaît la syntaxe d’import des modules JavaScript modernes. registerBlockType() reçoit le nom du bloc (lu dans les métadonnées) et un objet décrivant son comportement dans l’éditeur — ici, seulement la propriété edit, puisqu’un bloc dynamique n’a pas de save. Tout le travail d’affichage de l’éditeur se concentre donc dans le composant Edit.
Étape 4 — Écrire le composant d’édition
Voici le cœur React. Le fichier src/edit.js exporte une fonction qui renvoie l’interface affichée dans l’éditeur. Pour un développeur PHP, l’essentiel à saisir : cette fonction reçoit les attributs du bloc et une fonction setAttributes pour les modifier. Modifier un attribut redessine automatiquement le bloc — c’est le principe de React, l’interface suit l’état.
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, RangeControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
export default function Edit( { attributes, setAttributes } ) {
const { nombre } = attributes;
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<InspectorControls>
<PanelBody title={ __( 'Réglages', 'annuaire-quartier' ) }>
<RangeControl
label={ __( "Nombre d'artisans", 'annuaire-quartier' ) }
value={ nombre }
onChange={ ( v ) => setAttributes( { nombre: v } ) }
min={ 1 }
max={ 20 }
/>
</PanelBody>
</InspectorControls>
<p>{ __( 'Liste de', 'annuaire-quartier' ) } { nombre } { __( 'artisans', 'annuaire-quartier' ) }</p>
</div>
);
}
Décortiquons. useBlockProps() fournit les attributs HTML que WordPress attend sur l’élément racine du bloc — on les répand avec { ...blockProps }. InspectorControls est un conteneur magique : tout ce qu’on y place apparaît dans la barre latérale de droite, pas dans le corps du bloc. Le RangeControl est un curseur ; à chaque déplacement, son onChange appelle setAttributes qui met à jour nombre, et la prévisualisation (« Liste de 5 artisans ») se rafraîchit aussitôt. Vous tenez là tout le modèle React de Gutenberg : des attributs, une fonction pour les changer, une interface qui suit.
Étape 5 — Le rendu dynamique en PHP
Côté visiteur, c’est src/render.php qui parle. WordPress l’exécute à chaque affichage du bloc et expose une variable $attributes contenant les réglages choisis dans l’éditeur. On y retrouve notre code PHP familier : une requête WP_Query sur le type « artisan », limitée au nombre demandé.
<?php
$nombre = isset( $attributes['nombre'] ) ? (int) $attributes['nombre'] : 5;
$query = new WP_Query( array(
'post_type' => 'aq_artisan',
'posts_per_page' => $nombre,
) );
if ( $query->have_posts() ) :
echo '<ul ' . get_block_wrapper_attributes() . '>';
while ( $query->have_posts() ) : $query->the_post();
$tel = get_post_meta( get_the_ID(), 'aq_telephone', true );
echo '<li><strong>' . esc_html( get_the_title() ) . '</strong> — '
. esc_html( $tel ) . '</li>';
endwhile;
echo '</ul>';
wp_reset_postdata();
endif;
Deux points méritent l’attention. get_block_wrapper_attributes() ajoute sur l’élément racine les classes et styles que l’éditeur a pu définir — à ne pas oublier, sous peine de styles manquants côté public. Et l’on échappe chaque sortie avec esc_html() : le titre et le téléphone viennent de la base, on ne les affiche jamais bruts. Comme le rendu est recalculé à chaque visite, la liste reste fidèle aux données : c’est tout l’intérêt du bloc dynamique.
Étape 6 — Compiler et tester
Le code de src/ n’est pas exécutable tel quel par le navigateur : il faut le compiler. Les scripts fournis par @wordpress/scripts s’en chargent. Depuis le dossier du bloc, on installe les dépendances puis on lance le mode développement, qui recompile à chaque sauvegarde.
# Installer les dépendances (une fois)
npm install
# Mode développement : recompile à chaque modification
npm start
# Version finale optimisée, prête pour la production
npm run build
npm start surveille vos fichiers et reconstruit le dossier build/ en continu — idéal pendant le développement. Quand tout fonctionne, npm run build produit la version compacte à livrer. Ouvrez l’éditeur, insérez le bloc « Liste d’artisans » : la prévisualisation s’affiche, le curseur de la barre latérale change le nombre, et l’aperçu côté visiteur liste vos vraies fiches. Pour intégrer ce bloc à Annuaire Quartier, il suffit d’enregistrer le dossier compilé depuis le PHP de l’extension avec register_block_type( AQ_PATH . 'build/aq-liste-artisans' ) sur le hook init.
✅ Point d’étape — Le bloc apparaît dans l’insertion, son curseur fonctionne, et la page publique affiche la liste réelle des artisans. Si le bloc est introuvable après
npm run build, vérifiez que le dossierbuild/est bien enregistré côté PHP.
🐞 Pièges fréquents
| Symptôme / erreur | Cause probable | Correctif |
|---|---|---|
| Le bloc n’apparaît pas dans l’insertion | Dossier build/ non enregistré ou non compilé |
Lancer npm run build et enregistrer le dossier build/ côté PHP |
| « Ce bloc contient un contenu inattendu » | Sauvegarde statique invalidée après modification | Préférer le rendu dynamique (render.php), sans fonction save |
| Les styles du bloc manquent côté public | get_block_wrapper_attributes() oublié |
L’ajouter sur l’élément racine dans render.php |
npm start échoue |
Version de Node.js trop ancienne | Installer Node.js 20 ou plus récent |
| Le curseur ne change rien à l’aperçu public | L’attribut n’est pas lu dans render.php |
Lire $attributes['nombre'] dans la requête |
✅ Récapitulatif
Vous avez échafaudé un bloc avec @wordpress/create-block, lu sa fiche d’identité block.json, enregistré le bloc côté JavaScript, écrit le composant React d’édition avec des réglages dans la barre latérale via InspectorControls, et produit un rendu public dynamique en PHP avec render.php. Vous avez surtout saisi le modèle de Gutenberg : des attributs, une fonction pour les changer, une interface qui suit. Annuaire Quartier dispose désormais d’un bloc que n’importe quel rédacteur peut insérer.
🧾 Aide-mémoire
| Élément | Rôle |
|---|---|
npx @wordpress/create-block@latest [slug] --variant dynamic |
Échafaude un bloc dynamique |
block.json |
Fiche d’identité déclarative du bloc |
registerBlockType() |
Déclare le bloc auprès de l’éditeur |
useBlockProps() |
Attributs HTML attendus sur l’élément racine |
InspectorControls |
Conteneur des réglages de la barre latérale |
render.php + get_block_wrapper_attributes() |
Rendu public dynamique |
npm start / npm run build |
Compilation développement / production |
💪 À vous de jouer
Ajoutez dans la barre latérale un sélecteur de métier (composant SelectControl) qui met à jour l’attribut metier, puis exploitez-le dans render.php pour filtrer la requête sur la taxonomie.
Voir une solution
// Dans render.php, après avoir lu $metier :
$args = array( 'post_type' => 'aq_artisan', 'posts_per_page' => $nombre );
if ( ! empty( $attributes['metier'] ) ) {
$args['tax_query'] = array( array(
'taxonomy' => 'aq_metier',
'field' => 'slug',
'terms' => sanitize_title( $attributes['metier'] ),
) );
}
$query = new WP_Query( $args );
Côté edit.js, un SelectControl dont l’onChange appelle setAttributes( { metier: v } ) alimente cet attribut.
Tutoriels de la série
- Types de contenu et métadonnées — les données que ce bloc affiche.
- L’API REST WordPress — l’autre façon d’exposer ces artisans.
Pour aller plus loin
- 🔝 Retour au guide principal : Développement WordPress : plugins, thèmes et blocs.
- Documentation officielle : Block Editor Handbook.
- Tutoriel suivant conseillé : exposer les artisans via une API REST sur mesure.
FAQ
Dois-je vraiment apprendre React pour faire un bloc ?
Pour un bloc d’édition riche, oui, mais seulement une petite partie : composants, attributs, setAttributes. L’outil d’échafaudage et les composants prêts à l’emploi (RangeControl, PanelBody) vous épargnent l’essentiel. On peut être très productif avec une connaissance limitée de React.
Pourquoi un bloc dynamique plutôt qu’un bloc statique ?
Parce que les données évoluent. Un bloc statique fige son HTML à l’enregistrement ; si vous ajoutez un artisan, il n’apparaîtra pas. Le bloc dynamique recalcule à chaque affichage et reste toujours à jour. Pour du contenu figé (un encadré), le statique reste pertinent.
Faut-il installer Node.js sur le serveur de production ?
Non. La compilation se fait sur votre machine de développement. Sur le serveur, on déploie uniquement le dossier build/ compilé. C’est pratique sur un hébergement mutualisé sans accès à la ligne de commande.
Mon bloc peut-il afficher l’image de l’artisan ?
Oui. Dans render.php, get_the_post_thumbnail() renvoie le HTML de l’image mise en avant. On l’ajoute dans la boucle, en choisissant une taille d’image adaptée pour ne pas alourdir la page.
Comment déboguer un bloc qui ne se charge pas ?
Ouvrez la console JavaScript du navigateur dans l’éditeur : une erreur de compilation ou d’import s’y affiche. Côté PHP, vérifiez que le dossier build/ est enregistré avec register_block_type() et que WP_DEBUG est actif pour voir les erreurs de render.php.