Claude Design est l’outil de maquettes d’Anthropic, inclus dans toutes les offres de Claude, gratuite comprise : vous décrivez une page, un visuel ou un parcours cliquable, et Claude en dessine une première version, exportable en HTML, en PDF ou en PowerPoint. J’ai converti une de ces maquettes en thème de blocs WordPress 7.1 complet, jusqu’à un bloc Gutenberg sur mesure. Interrogé par script, sans activer le thème, WordPress le reconnaît et rend le bloc. Tout repose sur une règle simple, nommer les couleurs et les tailles avant de dessiner.
Pas le temps ? Faites-le analyser par l'IA
Vous me lisez souvent ? Dites-le à Google
J'ajoute WPFormation à mes sourcesClaude Design est l’outil de conception visuelle d’Anthropic, l’éditeur de Claude. Vous lui décrivez ce que vous voulez, une page d’accueil, une plaquette, une présentation ou le parcours d’une application, et il en dessine une première version sur un canevas, aux couleurs de votre marque si vous les lui donnez. Vous l’affinez ensuite en conversant avec lui ou en retouchant directement les planches.
Il est compris dans toutes les offres de Claude, de la gratuite à Enterprise, sans supplément, et puise dans les limites d’usage de votre offre. Vos créations s’exportent en HTML, en PDF ou en PowerPoint, partent vers des outils comme Canva ou Miro, et passent à Claude Code avec la commande /design quand il faut les transformer en vrai site.
Pour un site WordPress, l’intérêt est concret : la maquette ne sort pas en image à retaper, mais en HTML que l’on peut reprendre. Reste à savoir ce que ça donne avec les thèmes de blocs, leurs réglages et leurs gabarits. J’ai donc fait le trajet complet : une maquette de site de menuisier en sept planches, avec un composant réglable et un prototype cliquable, puis un thème de blocs installé sur un vrai WordPress 7.1 et vérifié ligne par ligne.

État de l’outil : Claude Design est inclus dans toutes les offres, gratuite comprise d’après la page produit relue le 31 octobre, dans les limites d’usage de chacune. Il évolue vite. Depuis le 16 septembre 2026, il s’ouvre aussi dans une conversation, dans l’onglet Artifacts et dans Claude Code avec la commande /design. Mon test, fait fin août, s’est déroulé dans l’éditeur autonome, qui ferme le 14 décembre 2026 : il passera alors en lecture seule, et vos nouveaux designs se créent déjà comme des artefacts dans Claude. Son format de composants n’est pas documenté publiquement : ce que je décris ici, je l’ai relevé en manipulant l’éditeur et en lisant son moteur de rendu. Les noms d’attributs peuvent changer d’une mise à jour à l’autre. La méthode de conversion, elle, dépend de WordPress et pas de l’outil de maquette.
Que fabrique Claude Design, au juste ?
Un canevas où chaque écran est une planche indépendante. Chaque planche est un fichier .dc.html : du balisage, des styles en ligne, et un en-tête helmet pour les polices et le CSS global. Vous pouvez l’ouvrir dans un éditeur de texte et le comprendre en trente secondes.
C’est déjà la première différence avec un outil de maquette classique. Ce qui sort n’est pas un rendu vectoriel à retracer, c’est de la matière dans le même langage que la cible. Un menu de navigation dessiné dans le canevas est déjà un <nav> avec ses liens.
Le canevas se pilote par un fichier canvas.json : la position de chaque planche, la taille de son cadre, la page sur laquelle elle vit, et les notes jaunes qu’on colle à côté. J’ai rangé ma maquette en trois pages : le site, le système, les composants.

Attention à un détail qui gâche une réunion : les polices Google se chargent dans le canevas, mais pas dans l’export PDF, qui retombe sur la police de secours. Si vous présentez la maquette en PDF, choisissez des polices de repli aux formes proches. Sinon le rendu de la réunion ne sera pas celui de l’écran… et c’est toujours à ce moment-là que le client trouve que ça fait vieillot.
Le geste qui décide de tout : nommer avant de dessiner
Une maquette ordinaire donne des pixels et des codes hexadécimaux. Un thème WordPress ne veut pas de valeurs, il veut des jetons : des valeurs nommées que l’éditeur proposera ensuite dans ses menus. Tant que votre brun reste "le brun du bouton", personne ne peut le convertir sans interpréter.
D’où la planche que j’ajoute systématiquement, et qui ne se verra jamais en ligne : une page qui montre la palette, l’échelle typographique et les mesures, avec pour chaque valeur le nom qu’elle prendra dans theme.json. Pas "brun foncé" mais accent. Pas "56 pixels" mais x-large.

Ces noms sont ceux des thèmes par défaut de WordPress, et sa documentation recommande base et contrast pour le fond et le texte. Ils ne sont pas imposés : WordPress demande seulement un identifiant unique par valeur. Je les reprends tels quels :
base,base-2,base-3pour les fonds et le filetcontrastetcontrast-2pour les textesaccentpour l’unique couleur d’actionsmall,medium,large,x-largepour la typographiecontentSizeetwideSizepour les largeurs de lecture, deux clés detheme.json, au nom imposé
Une maquette qui porte ces noms se traduit presque mécaniquement. Une maquette qui ne les porte pas oblige à décider, au moment de l’intégration, ce qui est une couleur de marque et ce qui est un accident de rendu. C’est là que les journées partent, et j’en ai livré, des sites où la question s’est posée trop tard.
La planche à poser avant les écrans : faites la planche "système" en premier, avec les noms WordPress déjà écrits à côté des valeurs. Elle prend vingt minutes et c’est elle qui rend la conversion mécanique. Elle sert aussi de contrat avec le client, qui valide un système plutôt que trois écrans.
Une planche peut être un composant, avec ses réglages
C’est la partie que j’avais ratée à mon premier essai, et c’est pourtant celle qui change tout pour WordPress. Une planche n’est pas forcément un écran figé. Elle peut déclarer ses propres propriétés, typées, avec un panneau de réglages qui apparaît au-dessus d’elle dans le canevas.
La déclaration se fait dans un attribut data-props, en JSON, au bas du fichier. Voici celle de ma carte de réalisation, qui couvre les sept types disponibles :
<script data-dc-script data-props='{
"$preview": { "width": 340, "height": 420 },
"titre": { "editor": "text", "default": "Bibliotheque toute hauteur", "section": "Contenu" },
"essence": { "editor": "enum", "default": "Chene",
"options": ["Chene", "Noyer", "Frene", "Merisier"], "section": "Contenu" },
"annee": { "editor": "int", "default": 2026, "section": "Contenu" },
"surface": { "editor": "float", "default": 4.2, "section": "Contenu" },
"miseEnAvant": { "editor": "boolean", "default": true, "section": "Affichage" },
"accent": { "editor": "color", "default": "#8A4B24", "section": "Affichage" },
"arrondi": { "editor": "range", "default": 4, "min": 0, "max": 24, "section": "Affichage" }
}'>
Sept types d’éditeurs, donc : text, enum, int, float, boolean, color et range. La clé section regroupe les réglages en panneaux. Le $preview donne la taille d’aperçu du composant.

Si vous connaissez Gutenberg, vous avez déjà reconnu quelque chose. Ces sept éditeurs sont exactement les contrôles de l’inspecteur WordPress : un champ texte, une liste déroulante, un nombre, une bascule, un sélecteur de couleur, un curseur. La correspondance est si directe qu’on peut la poser en tableau, et j’y reviendrai plus bas.
Un composant s’appelle ensuite depuis une autre planche, avec ses valeurs :
<dc-import name="CarteRealisation" hint-size="340px,420px"
titre="Bibliotheque toute hauteur" essence="Chene" annee="2026"
surface="4.2" miseEnAvant="true"></dc-import>
J’ai appelé la même carte trois fois, avec trois essences. Modifier le fichier de la carte les change toutes les trois. C’est le contrat d’un bloc WordPress, obtenu avant même d’avoir ouvert WordPress.

Un piège vous attend dès le premier appel : un attribut HTML est toujours une chaîne de caractères. En écrivant miseEnAvant="false", vous transmettez le texte "false", qui vaut vrai en JavaScript. Mes trois cartes portaient donc toutes le bandeau "pièce signature". Le panneau de réglages, lui, envoie le vrai type. Il faut donc convertir dans le composant :
// Le panneau envoie un booleen, un dc-import envoie du texte.
const bool = (v, def) => typeof v === "boolean" ? v
: v === undefined ? def
: v !== "false" && v !== "0" && v !== "";
Et cette planche peut être réellement cliquable
Le composant accepte un bloc de logique, sous la forme d’une classe qui étend DCLogic. Elle porte un état, des gestionnaires d’événements, et une méthode renderVals() dont le résultat alimente les trous {{ }} du gabarit. Sous le capot, on retrouve React, avec setState, componentDidMount et le reste. Vous n’écrivez pas de React, mais vous en avez les capacités.
J’en ai profité pour construire un estimateur de devis : trois choix, un prix qui se recalcule. Le client peut cliquer dedans avant qu’une seule ligne de PHP existe.
class Component extends DCLogic {
state = { essence: "Chene", surface: 4, pose: true };
renderVals() {
const coef = { Chene: 1, Noyer: 1.45, Frene: 0.9, Merisier: 1.2 };
const total = Math.round(
(this.props.tarifBase ?? 780) * coef[this.state.essence] * this.state.surface
+ (this.state.pose ? (this.props.tarifPose ?? 320) : 0)
);
return {
prix: total.toLocaleString("fr-FR"),
cher: this.state.surface > 8,
basculerPose: () => this.setState({ pose: !this.state.pose })
};
}
}
Deux directives complètent le gabarit. sc-for boucle sur un tableau, sc-if affiche selon une condition :
<sc-for list="{{essences}}" as="e" hint-placeholder-count="4">
<button onClick="{{choisirEssence}}" data-valeur="{{e.nom}}" style="{{e.style}}">{{e.nom}}</button>
</sc-for>
<sc-if value="{{cher}}">
<p>Au-dela de 8 m2, je passe systematiquement par une visite avant de chiffrer.</p>
</sc-if>
Retenez bien les noms d’attributs : list pour la boucle, value pour la condition. J’avais écrit each et cond, par réflexe. Le premier m’a valu un avertissement dans la console, le second n’a rien dit du tout : une condition dont l’attribut n’est pas reconnu vaut faux, donc le contenu disparaît en silence. Mon bandeau "pièce signature" avait disparu sans un mot, et j’aurais pu chercher longtemps du côté de la donnée.
Une fois corrigé, le prototype répond. J’ai piloté les clics par script pour vérifier les calculs plutôt que de les croire : départ à 3 440 euros, puis 4 844 après bascule sur le noyer, puis 10 499 à neuf mètres carrés, avec l’avertissement conditionnel qui apparaît au passage du seuil.


Ce prototype ne partira jamais en production tel quel, et ce n’est pas son rôle. Il sert à faire trancher : est-ce qu’on veut un curseur ou trois paliers, est-ce que la pose se coche ou se choisit, est-ce que le prix s’affiche avant ou après le formulaire. Ces arbitrages-là coûtent bien plus cher à corriger quand ils arrivent en recette.
Dimensionner les cadres sans deviner
Le canvas.json donne à chaque planche une position et un cadre. Ce cadre ne redimensionne rien et ne recadre rien : si votre contenu est plus large, il déborde, et si le cadre est trop grand, vous voyez du vide.
J’avais écrit mes dimensions au jugé. Toutes étaient fausses, et pas de peu. Ma page d’accueil était déclarée à 1 160 pixels de large alors qu’elle en occupe 1 440, et 1 640 de haut pour 2 259 réels. Mon estimateur débordait de 80 pixels, ce qui coupait le prix en plein milieu du chiffre.
La cause est bête : un conteneur en width: 560px avec padding: 40px occupe 640 pixels, pas 560. Plutôt que de recompter à la main, j’ai ouvert le canevas dans un navigateur piloté et mesuré chaque planche rendue, puis reporté les valeurs. Trois minutes, et plus aucun débordement.
Le débordement ne prévient pas : rien dans le canevas ne signale qu’une planche dépasse son cadre. Vous le découvrez à l’export, ou pire, en réunion. Mesurez le rendu réel plutôt que d’additionner vos largeurs de tête.
Le fichier accepte aussi des pages, pour ranger les planches par famille, des notes libres, et un drapeau is_interactive qui marque les planches cliquables d’un repère visible. Sur la capture ci-dessous, l’estimateur porte un triangle plein là où les autres ont un contour vide.

Le theme.json traduit la maquette presque mot pour mot
À partir de la planche système, le fichier s’écrit tout seul. Voici l’extrait qui porte la palette et l’échelle, en version 3 du format :
{
"$schema": "https://schemas.wp.org/wp/7.1/theme.json",
"version": 3,
"settings": {
"appearanceTools": true,
"useRootPaddingAwareAlignments": true,
"layout": { "contentSize": "680px", "wideSize": "1280px" },
"color": {
"defaultPalette": false,
"palette": [
{ "slug": "base", "color": "#F7F2EA", "name": "Fond" },
{ "slug": "contrast", "color": "#2A2018", "name": "Encre" },
{ "slug": "accent", "color": "#8A4B24", "name": "Accent bois" }
]
},
"typography": {
"fluid": true,
"defaultFontSizes": false,
"fontSizes": [
{ "slug": "medium", "size": "18px", "name": "Courant" },
{ "slug": "x-large", "size": "56px", "name": "Page",
"fluid": { "min": "38px", "max": "56px" } }
]
}
}
}
Trois réglages méritent qu’on s’y arrête. defaultPalette à false retire les couleurs livrées par WordPress : sans lui, votre client se retrouve avec votre palette et une vingtaine de teintes qui n’ont rien à faire là. Même logique pour defaultFontSizes.
appearanceTools ouvre d’un coup les réglages de bordure, d’espacement et de typographie dans l’éditeur, au lieu de les activer un par un. Et useRootPaddingAwareAlignments fait que vos blocs pleine largeur débordent proprement des marges de page, au lieu de rester coincés dedans. Celui-là s’oublie souvent, et le symptôme est déroutant : une image censée faire toute la largeur qui garde 80 pixels de blanc de chaque côté.
Les tailles de police que WordPress calcule à votre place
J’ai déposé le thème sur un WordPress 7.1, sans l’activer, et je lui ai demandé ce qu’il comprenait. La feuille de styles produite fait 8 150 octets. Voici quelques-unes des variables qui en sortent :
--wp--preset--color--accent = #8A4B24
--wp--preset--color--base = #F7F2EA
--wp--preset--font-family--display = "Instrument Serif", Georgia, "Times New Roman", serif
--wp--preset--font-size--x-large = clamp(38px, 2.375rem + ((1vw - 3.2px) * 1.875), 56px)
--wp--preset--font-size--large = clamp(28px, 1.75rem + ((1vw - 3.2px) * 0.625), 34px)
--wp--preset--font-size--medium = clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.417), 18px)
--wp--preset--spacing--60 = 80px
Regardez la dernière taille de police. J’avais écrit 18px pour le texte courant, sans rien demander d’autre. WordPress a rendu une plage qui descend jusqu’à 14 pixels sur petit écran. Je n’avais déclaré de bornes que pour les deux grandes tailles ; le fluid global s’applique à toutes, et il calcule lui-même les bornes manquantes.
C’est une bonne chose, à condition de la voir venir. Si vous comparez au pixel près votre maquette et le rendu sur un écran étroit, vous allez croire à un raté d’intégration alors que c’est le comportement demandé. Et si votre texte courant descend à 14 pixels sans que vous l’ayez voulu, vous venez de perdre en lisibilité sur mobile sans le savoir.
Ma planche mobile prend ici tout son sens : elle donne la borne basse. Le titre y est écrit à 38 pixels, contre 56 sur la planche large. Ce sont exactement les deux valeurs que WordPress réunit dans une seule déclaration.

Dessinez au moins 2 largeurs : une planche large et une planche mobile suffisent à fixer les bornes de toute votre échelle typographique. Sans la seconde, c’est WordPress qui invente vos tailles mobiles, et il le fait sans vous demander votre avis.
Habiller les blocs natifs sans écrire une ligne de CSS
Votre maquette ne montre pas seulement des couleurs, elle montre une citation avec un filet à gauche, un bloc de code sur fond sombre, un séparateur discret. Le réflexe est d’ouvrir une feuille de style pour reproduire tout ça. Mauvaise pioche : theme.json sait styliser les blocs de WordPress un par un.
"styles": {
"blocks": {
"core/quote": {
"border": { "left": { "color": "var(--wp--preset--color--accent)",
"style": "solid", "width": "3px" } },
"spacing": { "padding": { "left": "var(--wp--preset--spacing--40)" } },
"typography": { "fontFamily": "var(--wp--preset--font-family--display)",
"fontSize": "24px" }
},
"core/separator": { "color": { "text": "var(--wp--preset--color--base-3)" } },
"core/code": {
"color": { "background": "var(--wp--preset--color--contrast)",
"text": "var(--wp--preset--color--base)" }
}
}
}
Notez que les valeurs pointent vers les variables produites par vos propres jetons, jamais vers un code hexadécimal écrit en dur. C’est ce qui fait tenir l’ensemble : le jour où le client change sa couleur d’accent depuis l’éditeur, le filet de ses citations suit tout seul. Avec une feuille de style classique, il ne suivrait pas, et personne ne comprendrait pourquoi.
Même logique pour les éléments transverses, dans styles.elements : les liens et leur survol, les niveaux de titre, les légendes d’image, les boutons. La pseudo-classe s’écrit directement dans le JSON, ce qui surprend la première fois :
"elements": {
"link": {
"color": { "text": "var(--wp--preset--color--accent)" },
":hover": { "color": { "text": "var(--wp--preset--color--contrast)" } }
},
"button": {
"color": { "background": "var(--wp--preset--color--accent)" },
"border": { "radius": "2px" },
":hover": { "color": { "background": "#5E3116" } }
}
}
Tout ce que vous mettez là se retrouve dans l’interface du client, sous forme de réglages qu’il peut modifier. Tout ce que vous mettez dans une feuille de style lui reste invisible et hors de portée. C’est la vraie ligne de partage entre les deux, et elle décide de qui devra intervenir dans six mois.
Les gabarits : ce qui se rejoue et ce qui se refait
Le theme.json se convertit presque littéralement. Les pages, elles, se rejouent. Une planche est du HTML libre ; un gabarit WordPress est une suite de blocs, et tout ce qui n’existe pas comme bloc doit être repensé.
La structure de ma page d’accueil s’est transposée sans douleur, parce que je l’avais dessinée en grilles et en piles plutôt qu’en positions absolues. C’est le seul vrai conseil de dessin que je donnerais à quelqu’un qui vise WordPress : composez comme l’éditeur compose.
<!-- wp:columns {"verticalAlignment":"center"} -->
<!-- wp:column {"width":"55%"} -->
<!-- wp:heading {"level":1} -->
<h1>Vos meubles ne devraient pas ressembler a ceux du voisin.</h1>
<!-- /wp:heading -->
<!-- wp:buttons --> ... <!-- /wp:buttons -->
<!-- /wp:column -->
<!-- /wp:columns -->
J’ai livré huit gabarits, et WordPress les lit tous les huit sans broncher : index, single, page, archive, search, 404, front-page, plus un gabarit de page pleine largeur déclaré en customTemplates pour qu’il apparaisse dans le menu des modèles. Les trois premiers suffisent à un site vitrine ; les autres évitent qu’une page 404 ou une page de recherche tombe sur un rendu par défaut qui n’a rien à voir avec la maquette.
L’en-tête et le pied de page vivent à part, dans parts/, et se déclarent en templateParts. C’est ce qui permet au client de modifier son menu une fois, pour tout le site.
N’oubliez pas les compositions
Voilà ce que j’avais laissé de côté à mon premier passage, et c’est pourtant ce qui décide si votre client saura se servir du site que vous lui livrez.
Un gabarit définit la structure d’un type de page. Une composition désigne un morceau prêt à insérer, que le client retrouve dans son inséreur de blocs, sous l’onglet des motifs. Sans compositions, votre client a un thème magnifique et une page blanche : il doit reconstruire à la main le bandeau que vous avez dessiné.
Une composition est un simple fichier PHP dans patterns/, dont l’en-tête en commentaire porte tout le paramétrage :
<?php
/**
* Title: Bandeau atelier
* Slug: atelier-vasseur/hero-atelier
* Categories: banner, featured
* Description: Le bandeau d'accueil issu de la maquette : titre, promesse, deux appels a l'action.
* Keywords: accueil, bandeau, hero
* Viewport Width: 1400
*/
?>
<!-- wp:group {"align":"full","backgroundColor":"base"} -->
...
Les Keywords comptent plus qu’on ne croit : ce sont les mots que le client tapera dans la recherche de l’inséreur. Un motif qui ne répond pas à "bandeau" ou "accueil" n’existe pas pour lui.
J’en ai livré deux, et WordPress les a bien lus avec leurs catégories. Le second est plus intéressant : il ne contient pas de HTML de carte, il appelle trois fois le bloc que je vais construire dans la section suivante. Le client insère le motif, obtient trois cartes réglables, et modifie chacune par son panneau.
Pendant qu’on y est, une variation de style coûte dix minutes et fait beaucoup d’effet en réunion : un fichier dans styles/ qui redéfinit la palette, sans toucher à un seul gabarit. Le client bascule tout le site en version sombre depuis un menu, et vous n’avez rien dupliqué.
{
"$schema": "https://schemas.wp.org/wp/7.1/theme.json",
"version": 3,
"title": "Atelier de nuit",
"settings": { "color": { "palette": [
{ "slug": "base", "color": "#211A14", "name": "Fond" },
{ "slug": "contrast", "color": "#F7F2EA", "name": "Encre" },
{ "slug": "accent", "color": "#D08A4E", "name": "Accent bois" }
] } }
}
Du composant au bloc Gutenberg : le vrai passage
Nous y voilà. Un composant de maquette porte sept propriétés typées ; un bloc WordPress porte des attributs typés. La correspondance est presque terme à terme, et c’est ce qui rend l’exercice intéressant plutôt que gadget.
| Éditeur dans la maquette | Type d’attribut | Contrôle dans l’inspecteur |
|---|---|---|
text | string | TextControl |
enum | string + enum | SelectControl |
int | number | TextControl en mode nombre |
float | number | TextControl, pas de 0,1 |
boolean | boolean | ToggleControl |
color | string | PanelColorSettings |
range | number | RangeControl |
Côté WordPress, tout part du block.json. Les valeurs par défaut y sont reprises telles quelles depuis la maquette, et la liste fermée des essences devient un enum :
{
"$schema": "https://schemas.wp.org/wp/7.1/block.json",
"apiVersion": 3,
"name": "atelier-vasseur/carte-realisation",
"title": "Carte réalisation",
"category": "design",
"icon": "hammer",
"attributes": {
"titre": { "type": "string", "default": "Bibliothèque toute hauteur" },
"essence": { "type": "string", "default": "Chêne",
"enum": ["Chêne", "Noyer", "Frêne", "Merisier"] },
"annee": { "type": "number", "default": 2026 },
"surface": { "type": "number", "default": 4.2 },
"miseEnAvant": { "type": "boolean", "default": true },
"accent": { "type": "string", "default": "#8A4B24" },
"arrondi": { "type": "number", "default": 4 }
},
"editorScript": "file:./index.js",
"render": "file:./render.php"
}
La ligne render est celle qui vous épargne le plus de travail. Elle désigne un fichier PHP qui produit le rendu public, ce qui veut dire que votre bloc ne stocke aucun HTML en base. Le jour où vous changez le gabarit de la carte, toutes les cartes déjà publiées suivent. Avec un bloc statique, elles seraient restées figées dans leur ancienne version, et vous auriez dû gérer une migration.
Et l’interface d’édition, faut-il compiler quelque chose ? Non. On lit partout qu’il faut une chaîne de compilation pour écrire un bloc, parce que la documentation officielle est écrite en JSX. Le JSX n’est qu’une commodité d’écriture : en appelant createElement directement, un simple fichier index.js suffit, sans npm, sans build, sans package.json.
( function ( wp ) {
var el = wp.element.createElement;
var c = wp.components;
wp.blocks.registerBlockType( 'atelier-vasseur/carte-realisation', {
edit: function ( props ) {
var a = props.attributes, set = props.setAttributes;
var inspecteur = el( wp.blockEditor.InspectorControls, null,
el( c.PanelBody, { title: 'Contenu' },
el( c.TextControl, {
label: 'Titre', value: a.titre,
onChange: function ( v ) { set( { titre: v } ); }
} ),
el( c.SelectControl, {
label: 'Essence', value: a.essence,
options: [ 'Chêne', 'Noyer', 'Frêne', 'Merisier' ].map( function ( n ) {
return { label: n, value: n };
} ),
onChange: function ( v ) { set( { essence: v } ); }
} )
)
);
return el( wp.element.Fragment, null, inspecteur, apercu( a ) );
},
save: function () { return null; } // rendu cote serveur
} );
} )( window.wp );
Le bloc s’enregistre ensuite en une ligne dans le functions.php du thème, puisque register_block_type sait lire un dossier entier :
add_action( 'init', function () {
register_block_type( get_template_directory() . '/blocks/carte-realisation' );
} );
Un fichier de trois lignes complète le tout, à côté de index.js : index.asset.php. WordPress le détecte seul et y lit les scripts dont votre bloc dépend, ce qui garantit leur chargement avant le vôtre. Sans lui, ça marche souvent dans l’éditeur parce que ces scripts y sont déjà, mais rien ne le garantit.
<?php
return array(
'dependencies' => array( 'wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor' ),
'version' => '1.0.0',
);
Le thème n’étant pas activé, mon script de vérification a enregistré le bloc lui-même : WordPress l’a accepté en API 3, avec son rendu serveur. Un détail m’a fait sourire au moment de la vérification : j’avais déclaré sept attributs, WordPress en compte neuf. Il ajoute d’office lock et metadata, qui servent au verrouillage et au nommage des blocs dans l’éditeur. Aucune importance ici, mais si vous bouclez un jour sur la liste des attributs d’un bloc, ne soyez pas surpris d’en trouver deux que vous n’avez pas écrits.
J’ai demandé au serveur de rendre le bloc avec deux jeux d’attributs différents, pour vérifier que le conditionnel fonctionnait vraiment :
[1] 1135 octets | Pièce signature Bibliothèque toute hauteur Chêne massif, 4,2 m2, atelier 2026.
[2] 864 octets | Ilot de cuisine Noyer massif, 2,8 m2, atelier 2025.
271 octets d’écart, soit exactement le bandeau "pièce signature" absent du second. Et la surface s’affiche "4,2" avec une virgule, parce que le rendu passe par number_format_i18n plutôt que par une concaténation. Sur un site français, ce genre de détail se remarque tout de suite quand il manque.
Voici le résultat, rendu par WordPress 7.1 : trois essences, un arrondi à 14 pixels sur la carte du milieu et une couleur d’accent vert sur la troisième, toutes réglées par attributs.

Comparez avec la capture de la maquette plus haut. Ce sont les mêmes cartes, mais celles-ci sont réglables par le client depuis son éditeur, sans vous appeler.
Les polices : le piège qui vous fait livrer un site cassé
Je m’étais trompé sur ce point, et l’erreur mérite d’être racontée parce qu’elle est facile à commettre.
Déclarer une famille de polices dans theme.json ne charge aucun fichier. Il faut embarquer les .woff2 dans le thème et les déclarer en fontFace, avec un chemin en file:./ :
{
"slug": "body",
"name": "Karla",
"fontFamily": "Karla, \"Trebuchet MS\", system-ui, sans-serif",
"fontFace": [
{ "fontFamily": "Karla", "fontStyle": "normal", "fontWeight": "400",
"fontDisplay": "swap", "src": [ "file:./assets/fonts/karla-400.woff2" ] }
]
}
J’ai donc téléchargé les trois fichiers, 47 kilo-octets en tout, et je les ai déclarés. Puis j’ai cherché les règles @font-face dans la feuille de styles produite par le thème. Résultat : zéro.
Pas une erreur, pas un avertissement. Simplement rien. La raison est que les polices ne passent pas par la feuille de styles globale : WordPress les imprime par un chemin séparé, la fonction wp_print_font_faces de wp-includes/fonts.php, accrochée à wp_head en priorité 50. Chercher ses polices dans le mauvais fichier peut vous coûter une heure.
Et il y a plus vicieux. Cette fonction, appelée sans argument, va lire le theme.json du thème actif. J’ai forcé le passage avec mes propres familles, pour voir. Les trois règles sont bien sorties, 634 octets. Sauf que :
@font-face{font-family:Karla;font-style:normal;font-weight:400;font-display:swap;
src:url('https://votre-site.fr/wp-content/themes/astra/assets/fonts/karla-400.woff2') format('woff2');}
L’URL pointe vers /themes/astra/, le thème actif du site, et pas vers le mien. Le file:./ est résolu par rapport au thème activé, même si la police est déclarée par un autre thème. J’ai vérifié les deux adresses en HTTP :
- l’URL du thème déposé répond 200 ;
- l’URL que WordPress a fabriquée répond 404.
Un thème qui n’est pas actif ne peut donc pas être testé sur ses polices : vous obtiendrez toujours des adresses fausses. Le symptôme en production est du même tonneau, mais plus sournois : la page s’affiche, le texte est lisible, personne ne signale rien. C’est simplement la police de secours que voit le visiteur. Et vous ne le verrez jamais depuis votre machine, où la police est installée localement.
Le contrôle à faire avant la livraison : activez le thème sur un site de recette, ouvrez le code source d’une page publique et cherchez le bloc <style class="wp-fonts-local">. Copiez l’URL du premier fichier de police et ouvrez-la dans un onglet. Si elle ne répond pas 200, votre client lira son site en police de secours sans jamais vous le dire.
Le test du thème sur un vrai WordPress
Je n’aime pas les tutoriels qui s’arrêtent au fichier écrit. Le thème a donc été déposé sur un WordPress 7.1 réel, sans activation, et interrogé par script. Extrait de la sortie :
nom : Atelier Vasseur
erreurs : aucune
is_block_theme : OUI
gabarit 404.html 3 blocs de premier niveau
gabarit archive.html 3 blocs de premier niveau
gabarit front-page.html 3 blocs de premier niveau
[... huit gabarits au total ...]
Variations de style
nuit.json titre "Atelier de nuit", 6 couleurs redefinies
Compositions
Bandeau atelier slug atelier-vasseur/hero-atelier categories : banner, featured
Trois realisations slug atelier-vasseur/trois-realisations categories : gallery, featured
Le bloc
nom : atelier-vasseur/carte-realisation
api_version : 3
rendu serveur: OUI (render.php)
Theme actif : Astra
Thème reconnu comme thème de blocs, aucune erreur, huit gabarits lus, deux compositions répertoriées avec leurs catégories, une variation de style détectée, un bloc enregistré par le script et rendu. Et la dernière ligne, que je vérifie toujours quand je travaille sur un serveur qui sert vraiment : le thème actif n’a pas bougé.
Cette sortie ne montre pas le bloc dans l’éditeur. Son inspecteur, ses réglages, l’enregistrement puis le rechargement de la page n’ont pas été essayés ici.
Qu’est-ce qui ne passe pas de la maquette à WordPress ?
Voici la liste honnête de ce que j’ai dû abandonner ou refaire autrement :
- Les textures. Mes aplats de bois étaient des dégradés CSS répétés. Aucun bloc ne fait ça : soit on les recrée en CSS additionnel, soit on met de vraies photos, ce qui est de toute façon le bon choix pour un artisan.
- La colonne latérale collante. Le
position: stickyde ma maquette n’a pas d’équivalent dans les réglages de blocs. Il redescend en CSS. - Les pictogrammes en SVG. Ils survivent, mais dans un bloc de code HTML, ce qui les rend non modifiables par le client. Pour un site livré, mieux vaut une bibliothèque d’icônes.
- L’état du prototype. Le compteur, la bascule, le prix qui se recalcule : rien de tout cela ne traverse. Le prototype sert uniquement à décider. Côté WordPress, ce sera un bloc interactif ou un formulaire, à écrire séparément.
Aucune de ces limites ne vient de Claude Design. Elles viennent de l’écart entre une page libre et un système de blocs, et vous les auriez rencontrées en partant de n’importe quel outil de maquette.
Combien de temps faut-il, et à qui s’adresse ce chemin ?
J’avais déjà comparé sept façons de fabriquer une page WordPress avec ce genre d’outils. Ici, le trajet complet, maquette comprise, m’a pris une journée : sept planches, le theme.json, huit gabarits, deux compositions, une variation de style, le bloc et sa vérification sur un serveur réel. Le thème obtenu pesait 133 kilo-octets pour 22 fichiers.
Le gain n’est pas là. Ce n’est pas l’écriture du code qui va vous coûter. C’est juste la traduction des intentions, à savoir : décider si le beige est un fond ou une carte, si le brun est l’accent ou la bordure. Ainsi, une fois que la maquette est tranchée, l’intégration devient de la transcription.
Alors, pour quel profil ce chemin a-t-il du sens ? Si vous livrez des sites vitrines avec une identité par client, oui : dessiner puis convertir vous évite la double saisie, et le client repart avec un éditeur où sa palette est déjà rangée. Si vous partez d’un thème du commerce que vous personnalisez, ou si Gutenberg vous suffit déjà, non : vous passeriez d’un système déjà cohérent à un système à reconstruire, pour un résultat équivalent.
Le vrai bénéficiaire reste le client, une fois la livraison passée. En passant par les jetons plutôt que par des couleurs codées en dur, tout ce que vous avez dessiné devient réglable depuis son éditeur : la palette, l’échelle, les largeurs, et jusqu’aux sept propriétés de la carte. Un thème intégré à l’ancienne vous rappelle pour chaque changement de teinte. Je passe une bonne partie de mes journées sur WordPress, dont une part croissante à le piloter par des agents. Les sites qui vieillissent le mieux ne sont pas les plus beaux au moment de la livraison : ce sont ceux que leur propriétaire ose modifier.
Ce que vous obtenez en une journée : un socle propre, mais il reste du travail avant d’en faire un thème commercialisable. Il manque encore les traductions, une bibliothèque d’icônes, les réglages d’accessibilité fins et une vraie page de contact. Comptez la journée pour arriver au socle, quelques jours de plus pour le produit fini. Et si vous voulez faire ce premier trajet accompagné, sur votre propre maquette, c’est le genre de chantier que je monte en formation WordPress individuelle.
Le mode opératoire, si vous refaites le trajet
Voici l’ordre dans lequel j’ai procédé, et celui que je reprendrais. Il n’a rien d’évident : la tentation est de commencer par le plus visible, l’écran d’accueil, alors que c’est justement ce qu’il faut faire en deuxième.
- La planche système, avec les noms WordPress écrits à côté des valeurs.
- Les écrans, composés en grilles et en piles, jamais en positions absolues.
- Une planche mobile, pour fixer la borne basse de l’échelle typographique.
- Les composants répétés, avec leurs propriétés typées.
- Le
theme.json, recopié depuis la planche système. - Les gabarits, puis l’en-tête et le pied de page en morceaux séparés.
- Les compositions, pour que le client retrouve vos sections dans son inséreur.
- Les blocs, pour les composants qui portaient des propriétés.
- Les polices, en dernier, et vérifiées sur un site où le thème est actif.
Les trois vérifications que je ne saute jamais, parce que chacune m’a déjà coûté du temps : demander à WordPress s’il reconnaît le thème comme thème de blocs, lister les variables CSS produites pour vérifier qu’aucune couleur ne manque, et ouvrir l’URL d’un fichier de police dans un onglet. Une couleur absente de la liste sera aussi absente de l’éditeur du client, et il s’en apercevra bien après vous.
Testez sans activer, mais pas tout : un thème déposé sans activation se laisse lire (theme.json, gabarits et compositions), et un script peut enregistrer puis rendre ses blocs. Mais WordPress ne charge le functions.php que du thème actif : ce contrôle ne reproduit pas le fonctionnement normal. Le reste demande le thème activé, sur un site de recette : insérer le bloc dans l’éditeur, changer ses réglages, enregistrer, recharger, puis vérifier la page publique et ses polices.
Questions fréquentes
Faut-il savoir coder pour faire cette conversion ?
Pour le theme.json, non : il s’agit simplement d’une liste de valeurs nommées. Pour les gabarits, il faut connaître le balisage des blocs, ou les construire dans l’éditeur de site puis les exporter. Pour le bloc Gutenberg, il faut lire du JavaScript, mais aucune chaîne de compilation n’est nécessaire.
Peut-on convertir une maquette Figma de la même façon ?
Oui, et c’est le point important de cet article : ce qui rend la conversion possible n’est pas l’outil de maquette, c’est le fait que la maquette porte des valeurs nommées. Une maquette Figma avec des styles et des variables bien nommés se convertit aussi bien. Une maquette sans système, quel que soit l’outil, se paie à l’intégration.
Pourquoi mes tailles de police changent-elles toutes seules ?
Parce que le réglage fluid est actif. WordPress convertit chaque taille en une plage qui s’adapte à la largeur de l’écran, avec une fonction clamp(), y compris pour les tailles dont vous n’avez pas fixé les bornes. Vous pouvez les définir vous-même avec "fluid": { "min": ..., "max": ... }, ou désactiver le comportement si vous tenez à des tailles fixes.
Mes polices ne s’affichent pas, où chercher ?
Pas dans la feuille de styles du thème : les règles @font-face n’y sont pas. WordPress les imprime séparément dans un bloc <style class="wp-fonts-local">, dans l’en-tête de la page publique. Vérifiez que ce bloc existe, puis que l’URL du fichier .woff2 répond bien 200. Un thème non activé produit toujours des adresses fausses.
Un bloc personnalisé oblige-t-il à installer Node et npm ?
Non. La documentation officielle utilise du JSX, qui demande une compilation, mais ce n’est qu’une commodité d’écriture. En appelant wp.element.createElement directement, un fichier index.js posé dans le thème suffit. C’est plus verbeux à lire, et ça évite d’embarquer une chaîne de compilation dans un thème qui n’en a pas besoin.
Le thème obtenu est-il utilisable en production ?
Comme socle, oui : il est reconnu comme thème de blocs, sans erreur, avec ses huit gabarits et ses compositions. Comme livrable, il manque les traductions, les icônes, quelques gabarits secondaires et une passe d’accessibilité. Le travail restant se compte en jours plutôt qu’en semaines, mais il existe.
Si vous ne deviez retenir qu’un geste de tout ce trajet, prenez celui du début : nommez vos valeurs avant de dessiner vos écrans. Le reste, gabarits, compositions, bloc et polices, n’est que de la mécanique, et une mécanique qui se vérifie. C’est le nommage qui décide si votre maquette se convertit ou si elle se retape.
La chaîne WordPress + IA de ce site, en 12 étapes. Le guide vous donne la méthode pour la refaire à la main.
De la veille à la mesure, avec Claude Code, sur un WordPress classique.
- La carte des 12 étapes du workflow
- Une checklist et un prompt par étape
- 3 skills de départ à copier
- Les garde-fous nés de vrais incidents
Double opt-in : un email de confirmation à valider pour recevoir le guide. Newsletter max 2/mois. WPFormation utilise les données saisies, via Brevo, pour votre inscription et les emails annoncés, avec votre consentement. Données jamais revendues. Désabonnement en 1 clic. Vos droits et la conservation de vos données
Voir le détail du guide et de la version complète
