Blocs Creator
by Yanis Singer · github.com/yanissgr/blocs-creator---plugin-wordpress · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/yanissgr/blocs-creator---plugin-wordpress/archive/refs/heads/main.zipCréez vos blocs Gutenberg en déclarant leurs champs, puis dessinez-les dans un fichier PHP de votre thème.
Auteur : Yanis Singer — Licence GPL-2.0-or-later — WordPress 6.5+, PHP 8.0+
Le principe
Le plugin tient une frontière, et rien d'autre :
| Ce que le bloc contient | Ce à quoi il ressemble |
|---|---|
| Se déclare dans le back-office : un nom, des champs, un type par champ. | S'écrit dans un fichier PHP du thème. |
| Devient les attributs Gutenberg du bloc et son formulaire dans l'éditeur. | Reçoit les valeurs saisies, et produit le balisage que vous voulez. |
| Vit en base, s'exporte en JSON. | Vit dans le thème, se versionne avec lui. |
Aucun constructeur visuel ne génère de HTML à votre place. C'est délibéré : le balisage d'un site est la partie qu'on retouche le plus, et la moins automatisable.
Démarrer
- Blocs Creator → Ajouter un bloc. Donnez-lui un nom.
- Ajoutez des champs. Un libellé, un type. La clé se déduit du libellé.
- Publiez. Le fichier de rendu est créé dans
wp-content/themes/<thème>/blocs/<identifiant>.php, avec un point de départ pour chaque champ. - Ouvrez ce fichier et écrivez votre balisage. Le plugin n'y retouchera jamais.
Si ce n'est pas vous qui dessinez. L'écran du bloc porte une boîte « Fiche du bloc » : identifiant, fichier à écrire, et chaque champ avec la ligne qui va le chercher. Elle se copie d'un bouton et se lit telle quelle — c'est le pont entre les deux moitiés du plugin quand elles ne sont pas faites par la même personne.
Écrire un gabarit
Le gabarit reçoit quatre variables :
/**
* @var array $attributes Les valeurs brutes, telles qu'enregistrées.
* @var string $content Les blocs imbriqués, déjà rendus.
* @var WP_Block $block L'instance du bloc.
* @var array $champs Les valeurs prêtes à l'emploi, par clé.
*/
Et une quinzaine de fonctions :
| Fonction | Ce qu'elle rend |
|---|---|
bc_champ( $cle, $defaut = null ) |
La valeur du champ, prête à l'emploi. |
bc_brut( $cle, $defaut = null ) |
La valeur telle qu'enregistrée (pour une image, son identifiant). |
bc_a_champ( $cle ) |
Le champ est-il rempli ? |
bc_attributs( $classes, $extra ) |
Les attributs de la balise racine. Indispensable. |
bc_contenu() |
Les blocs imbriqués, rendus. |
bc_image( $cle, $attrs, $taille ) |
La balise <img>, ou une surface d'attente. |
bc_url( $cle, $taille ) |
L'URL d'une image ou d'un fichier. |
bc_lien_rempli( $cle ) |
Le lien a-t-il une destination ? |
bc_lien_attrs( $cle ) |
href, target et rel, déjà échappés. |
bc_lien_titre( $cle, $defaut ) |
Le libellé du lien. |
bc_lien_url( $cle ) |
L'URL seule. |
bc_boucle( $cle ) |
Les lignes d'un répéteur — toujours un tableau. |
bc_compte( $cle ) |
Le nombre de lignes d'un répéteur. |
bc_couleur( $cle, $defaut ) |
Une couleur utilisable en CSS. |
bc_niveau( $cle, $minimum = 2 ) |
Un niveau de titre borné. |
bc_rappel( $message ) |
Un rappel visible des seuls rédacteurs. |
bc_bloc() |
La définition du bloc en cours. |
Ce qui sort échappé sort échappé — bc_image(), bc_lien_attrs() et
bc_attributs() rendent du HTML prêt à poser. Les valeurs de texte sortent
brutes : le gabarit choisit son échappement, parce que lui seul sait s'il écrit
dans un attribut, dans une balise ou dans une URL.
Exemple
<?php
defined( 'ABSPATH' ) || exit;
?>
<section <?php echo bc_attributs( 'temoignages' ); ?>>
<?php if ( bc_a_champ( 'titre' ) ) : ?>
<?php printf(
'<h%1$d class="temoignages__titre">%2$s</h%1$d>',
bc_niveau( 'niveau' ),
esc_html( bc_champ( 'titre' ) )
); ?>
<?php endif; ?>
<ul class="temoignages__liste">
<?php foreach ( bc_boucle( 'lignes' ) as $ligne ) : ?>
<li>
<blockquote><?php echo wp_kses_post( $ligne['citation'] ); ?></blockquote>
<cite><?php echo esc_html( $ligne['auteur'] ); ?></cite>
</li>
<?php endforeach; ?>
</ul>
<?php if ( bc_lien_rempli( 'cta' ) ) : ?>
<a class="temoignages__lien" <?php echo bc_lien_attrs( 'cta' ); ?>>
<?php echo esc_html( bc_lien_titre( 'cta' ) ); ?>
</a>
<?php endif; ?>
</section>
Une feuille de style par bloc
Posez un <identifiant>.css à côté du gabarit : il est chargé automatiquement,
et seulement sur les pages qui portent le bloc.
Les types de champs
| Famille | Types |
|---|---|
| Texte | texte, texte long, texte enrichi, nombre |
| Choix | oui/non, liste déroulante, groupe de boutons, cases à cocher, niveau de titre, couleur, icône |
| Médias | image, galerie, fichier |
| Liens | lien, publication, publications, terme |
| Structure | groupe, répéteur, blocs imbriqués, note |
Ce que bc_champ() rend, par type :
| Type | Rend |
|---|---|
| texte, texte long, texte enrichi | string |
| nombre | float |
| oui/non | bool |
| liste, boutons, couleur, icône | string |
| cases à cocher | string[] |
| niveau de titre | int (1-6) |
| image, fichier | array (id, url, alt, largeur, hauteur, legende…) ou null |
| galerie | array[] |
| lien | array (url, titre, nouvelOnglet, attrs, rempli) |
| publication | WP_Post ou null |
| publications | WP_Post[] |
| terme | WP_Term ou WP_Term[] |
| groupe | array |
| répéteur | array[] — une entrée par ligne |
| blocs imbriqués | rien : passe par $content / bc_contenu() |
La structure ne s'imbrique qu'un cran. Un répéteur contient des champs simples, jamais un autre répéteur. C'est arbitraire, et c'est ce qui garde l'interface lisible et les gabarits écrivables.
Les blocs codés
Blocs Creator découvre et enregistre tout dossier portant un block.json,
dans l'ordre :
blocs-creator/packs/*/blocs/*/— les packs livrés avec le plugin ;<thème enfant>/blocs/*/;<thème parent>/blocs/*/;wp-content/blocs-creator/blocs/*/.
Ces blocs apparaissent dans la même liste que les blocs générés, marqués « Codés ». Le plugin ne fait que les enregistrer : leur rendu et leur éditeur restent leur affaire.
Les packs
Un pack est un dossier de packs/ portant un pack.php. Ce fichier est inclus
avant init, peut charger ce qu'il veut, et retourne ses métadonnées :
return array(
'nom' => 'Mon pack',
'description' => "Ce qu'il apporte.",
'auteur' => 'Vous',
'version' => '1.0.0',
);
Supprimer le dossier suffit à retirer le pack. Aucune trace en base.
Où le gabarit est cherché
Du plus spécifique au plus général :
<thème enfant>/blocs/<espace>-<identifiant>.php<thème enfant>/blocs/<identifiant>.php<thème parent>/blocs/…wp-content/blocs-creator/gabarits/<identifiant>.php- le rendu de secours du plugin, qui affiche les champs bruts.
Le point 4 survit au changement de thème. Le point 5 fait qu'un bloc tout juste créé montre quelque chose plutôt qu'un vide.
Reprendre la main sur un bloc codé
Un bloc écrit à la main est un dossier : un block.json, un rendu.php, du
JavaScript. On ne peut ni lui ajouter un champ ni lui changer son icône sans
ouvrir un éditeur de code.
Tous les blocs → Reprendre la main traduit ce dossier en définition et
recopie son rendu.php dans le thème comme gabarit. Trois promesses tiennent
l'opération :
- Le nom ne bouge pas.
mon-pack/banniererestemon-pack/banniere: les pages qui le portent ne voient pas la différence. - Le dessin ne bouge pas. Le
rendu.phpest recopié tel quel — il lit$attributes, que le plugin lui passe sous le même nom — et les feuilles de style que leblock.jsondéclarait restent attachées. - Rien ne se perd. Un attribut qu'aucun type de champ ne sait porter sans en changer la forme — un point focal, une structure à soi — est conservé tel quel. Les variantes, les styles de bloc et l'exemple d'inséreur aussi.
L'écran de confirmation montre la traduction avant de la faire : quel attribut devient quel type de champ, ce qui est conservé, ce qui change.
Rendre au code défait tout : la définition est supprimée, le dossier reprend la main. Le dossier n'a jamais été touché ; le gabarit recopié reste dans le thème, où il ne gêne pas.
Le bandeau de l'écran « Tous les blocs » propose de tout reprendre d'un coup : c'est le geste qu'on fait une fois, au début, après quoi il n'y a plus de blocs codés sur le site — seulement des blocs qui se modifient.
Ce que la reprise remplace, c'est l'éditeur sur mesure du bloc : un sélecteur maison, une barre d'outils dessinée pour lui. Le bloc se règle ensuite par le formulaire commun, et son aperçu passe par le rendu serveur.
Une reprise exacte : la clé blocsCreator
Deviner le type d'un attribut à son nom marche souvent, et pas toujours : un
pointFocal finirait en champ de texte, un sens aussi. Un bloc codé peut donc
dire lui-même ce que ses attributs doivent devenir, dans son block.json :
"blocsCreator": {
"animation": "cascade",
"champs": [
{ "cle": "titre", "libelle": "Titre", "type": "texte-riche",
"emplacement": "bloc", "options": { "placeholder": "Titre de la page" } },
{ "cle": "imageId", "libelle": "Image", "type": "image",
"emplacement": "panneau", "options": { "taille": "full" } },
{ "cle": "pointFocal", "libelle": "Point de cadrage", "type": "point-focal",
"emplacement": "panneau", "options": { "image": "imageId" } }
]
}
Les clés sont celles d'un champ de définition : cle (le nom de l'attribut,
casse comprise), libelle, type, emplacement, largeur, aide, options.
animation donne au bloc son apparition de départ.
Avec cette clé, la reprise est totale : chaque attribut devient un champ qu'on peut modifier, et il ne reste rien de « conservé tel quel ». Les douze blocs d'un pack devraient la porter : c'est ce qui rend la reprise exacte.
Les blocs disponibles
Réglages → Blocs disponibles liste tous les blocs enregistrés, groupés par provenance — WordPress, vos blocs, chaque extension — avec une case à cocher.
Deux règles tiennent l'écran :
- On range en négatif. C'est la liste de ce qu'on retire qui est enregistrée. Un bloc qui arrive demain avec une nouvelle extension est donc disponible d'emblée.
- On ne se coupe pas un bras. Vos propres blocs et les blocs qui n'existent qu'à l'intérieur d'un autre ne se décochent pas.
Décocher un bloc ne touche à aucune page : les blocs déjà posés continuent de s'afficher et de se modifier. C'est l'inséreur qui ne les propose plus.
Les apparitions
Deux décisions tiennent cette partie, et elles se voient à l'usage.
L'apparition appartient au bloc, pas à la page. Elle se choisit une fois : sur l'écran du bloc pour ceux que vous créez, dans Réglages → Apparitions pour ceux de WordPress et des autres extensions. Toutes ses occurrences entrent donc de la même façon, sur toutes les pages. Un réglage posé page par page finit toujours par diverger — trois bannières, trois entrées différentes, et un site qui a l'air improvisé. Un aperçu joue la scène au moment du choix.
Une apparition est une scène, pas un geste. Un bloc n'est pas une boîte : c'est un titre, un chapô, une image, des cartes. Chacune des dix scènes dit ce que fait le bloc ET ce que font ses parties, avec un décalage entre elles.
| Scène | Ce qui se passe |
|---|---|
| Montée | Le bloc entier monte et se fond. Le plus sobre. |
| Cascade | Le bloc reste en place ; son contenu monte l'un après l'autre. |
| Croisement | Les parties arrivent alternativement de la gauche et de la droite. |
| Déploiement | Le bloc se dévoile du bas, son contenu monte derrière. |
| Signature | Un balayage découvre le bloc, comme un coup de pinceau. |
| Pastilles | Chaque partie apparaît petite et se pose, en cascade rapide. |
| Souffle | Le bloc arrive flou et trop grand, puis se pose net. |
| Bascule | Le bloc pivote vers vous depuis sa base, en perspective. |
| Ressort | Le bloc dépasse sa place et y revient. |
| Composée | Chaque partie entre à sa façon, celle que le dessin lui donne. |
Les parties sont désignées par le script : les enfants directs du bloc, et
si l'un n'est qu'un conteneur — un div, une ul — ses propres enfants à sa
place. Une grille de cartes donne donc ses cartes, et une colonne de texte donne
son titre, son paragraphe et son bouton. Un élément qui porte déjà une
transformation ou un filtre est laissé tranquille : les lui reprendre le ferait
sauter de sa place.
Leur rang — le décalage entre elles — repart à chaque conteneur, et à chaque rangée d'une grille. Deux moitiés qui doivent se croiser partent donc ensemble, et la quatrième carte d'une grille à trois colonnes n'hérite pas du retard d'une quatrième.
Composer une scène depuis le gabarit
Les neuf premières scènes appliquent un même geste à toutes les parties. C'est ce qu'il faut la plupart du temps, et c'est insuffisant dès qu'un bloc est fait de moitiés qui n'entrent pas de la même façon — un texte qui monte pendant qu'une image s'installe, un trait qui se peint.
La scène Composée rend la main au gabarit : chaque partie porte sa variante
dans la valeur de data-bc-part, et le script s'en tient à cette liste au lieu
de deviner.
<section <?php echo bc_attributs( 'ma-banniere' ); ?>>
<div class="ma-banniere__texte">
<h2 data-bc-part="haut"><?php echo esc_html( bc_champ( 'titre' ) ); ?></h2>
<p data-bc-part="haut"><?php echo esc_html( bc_champ( 'chapo' ) ); ?></p>
</div>
<div class="ma-banniere__media">
<?php echo bc_image( 'image', array( 'data-bc-part' => 'zoom' ) ); ?>
</div>
</section>
| Variante | L'état de départ |
|---|---|
haut / bas |
décalé verticalement |
gauche / droite |
décalé horizontalement |
zoom |
légèrement réduit — pour une image qui s'installe |
pastille |
réduit et décalé d'un rien — pour une grille de cartes |
fondu |
l'opacité seule, sans déplacement |
pinceau |
une découpe inclinée qui balaie la largeur |
Un data-bc-part posé par le gabarit est toujours respecté, quelle que soit la
scène ; un --bc-anim-rang posé en style en ligne l'est aussi. Une scène qui ne
déplace pas le bloc et ne trouve aucune partie animable bascule sur « Montée »
plutôt que de ne rien jouer.
Trois garde-fous :
- La classe est posée au rendu, pas dans le balisage enregistré. Un bloc statique garde donc exactement le HTML qu'il avait : changer une apparition ne rend jamais un contenu « inattendu », et retirer le plugin ne laisse aucune classe orpheline.
- Rien ne se cache sans JavaScript. Le CSS ne masque que sous une classe posée par un script d'en-tête, muet quand l'appareil demande moins d'animations. Un filet démasque la page si le script principal ne se charge pas.
- L'éditeur ne joue rien. On règle l'apparition à la création du bloc, on ne la subit pas à chaque frappe.
Un thème peut ajouter une scène : le filtre blocs_creator_scenarios_animation
la déclare, des règles CSS sur [data-bc-anim="…"] la dessinent.
Réglages
| Réglage | Par défaut |
|---|---|
| Espace de noms des nouveaux blocs | déduit du nom du site |
| Catégorie dans l'inséreur | « Mes blocs », choisie parmi les sections existantes |
| Dossier des gabarits | blocs, relatif au thème actif |
| Créer le gabarit à la publication | oui |
| Supprimer les données à la désinstallation | non |
| Blocs retirés de l'inséreur | aucun |
| Apparition d'un bloc | aucune, jusqu'à ce que vous en choisissiez une |
Une seule catégorie. Le plugin n'ajoute sa section à l'inséreur que si personne ne l'a déjà déclarée — ni sous ce slug, ni sous ce titre. Deux sections du même nom ne sont pas deux rangements : c'est le même, coupé en deux.
L'enregistrement, et son diagnostic
Le formulaire ne passe pas par options.php. L'API des réglages de WordPress
fait dépendre une écriture de quatre choses qu'on ne voit pas — groupe autorisé,
capacité filtrée, jeton, transitoire de trente secondes pour le message — et
quand l'une lâche, elle renvoie l'écran à l'identique, sans un mot. Le bouton
passe alors pour mort.
Le plugin écrit donc lui-même, relit, compare, et annonce le résultat. Si la
relecture ne rend pas ce qu'on vient d'écrire, la ligne est écrite directement
en base : un filtre pre_update_option posé par une autre extension ou un cache
d'objets qui ne se vide pas ne sont pas des raisons d'abandonner en silence.
L'onglet Blocs disponibles n'envoie pas un champ par bloc — cent trente
dépasseraient max_input_vars sur bien des hébergements, et le formulaire
arriverait tronqué, c'est-à-dire avec des blocs qu'on croirait cochés. Il envoie
la liste des blocs écartés en un seul champ, composé à l'envoi, et un envoi
tronqué ne touche à rien.
Enfin, un diagnostic repliable, atteignable depuis la barre d'enregistrement : limites de PHP, présence de la ligne en base, cache d'objets, extensions actives, et le journal des huit dernières tentatives. S'il reste vide après un clic, la requête n'est jamais arrivée jusqu'au plugin — et l'on cherche du côté de l'hébergement, pas du code.
Import et export
Blocs Creator → Outils. L'export produit un JSON qui ne contient que les définitions — les gabarits sont des fichiers de thème, qu'on copie comme le reste du thème. Le JSON importé repasse entièrement par la normalisation : un fichier trafiqué ne peut déclarer que des champs du catalogue.
Crochets
| Crochet | Ce qu'il permet |
|---|---|
blocs_creator_champs |
Les valeurs, juste avant qu'elles n'arrivent au gabarit. |
blocs_creator_args_bloc |
Les arguments passés à register_block_type(). |
blocs_creator_candidats_gabarit |
Les chemins où le gabarit est cherché. |
blocs_creator_code_depart |
Le code du fichier de rendu généré. |
blocs_creator_catalogue_champs |
Ajouter un type de champ. |
blocs_creator_emplacements_blocs |
Les dossiers où les blocs codés sont découverts. |
blocs_creator_donnees_editeur |
Les données passées à l'éditeur. |
blocs_creator_charger_pack |
Désactiver un pack sans supprimer son dossier. |
blocs_creator_definition_enregistree |
Après l'enregistrement d'une définition. |
blocs_creator_blocs_proteges |
Les blocs qu'on refuse de retirer de l'inséreur. |
blocs_creator_scenarios_animation |
Ajouter une scène d'apparition. |
blocs_creator_animation_concerne |
L'accès d'un bloc au réglage d'apparition. |
Organisation du code
blocs-creator.php En-tête, constantes, point d'entrée
includes/
class-bc-plugin.php Bootstrap : chargement, packs, activation
class-bc-champs.php Le catalogue des types de champs
class-bc-definition.php Une définition de bloc : lecture, nettoyage, écriture
class-bc-registre.php Découverte et enregistrement de tous les blocs
class-bc-rendu.php Appel du gabarit, pile de contexte
class-bc-gabarits.php Résolution des chemins, génération du fichier
class-bc-usage.php Où un bloc est-il utilisé
class-bc-adoption.php Reprendre en main un bloc codé, et le rendre
class-bc-disponibilite.php Ce que l'inséreur a le droit de proposer
class-bc-animations.php Les apparitions : réglage, rendu, assets
class-bc-reglages.php Les réglages
class-bc-diagnostic.php Journal des enregistrements, relevé de la machine
class-bc-rest.php Deux routes pour l'éditeur
fonctions.php L'API des gabarits (bc_*)
admin/
class-bc-admin.php Menu, écrans, actions
class-bc-liste-table.php L'écran « Tous les blocs »
class-bc-ecran-definition.php L'écran d'édition d'un bloc
class-bc-outils.php Import et export
js/constructeur.js Le constructeur de champs
js/reglages.js Onglets et tri de l'écran des réglages
js/apercu-animation.js L'aperçu d'une apparition, au moment du choix
js/copier.js Les boutons « Copier » (fiche, diagnostic)
vues/ Les gabarits des écrans
assets/
js/editeur.js L'éditeur générique des blocs générés
js/animations.js Révéler un bloc et ses parties quand il entre à l'écran
css/editeur.css Ce que l'éditeur ajoute autour d'un bloc
css/blocs.css Le strict minimum côté site
css/animations.css Les dix scènes d'apparition, et l'aperçu
gabarits/secours.php Le rendu d'un bloc sans gabarit
packs/ Les blocs codés livrés avec le plugin
Aucun outil de build : le JavaScript est écrit en natif
(wp.element.createElement plutôt que du JSX), pour que le plugin s'installe
partout sans npm install.
Ajouter un type de champ
Trois endroits, et pas un de plus :
BC_Champs::catalogue()— ou le filtreblocs_creator_catalogue_champs— déclare le type : son attribut Gutenberg, sa valeur par défaut, ses réglages.BC_Champs::assainir_valeur()etBC_Champs::preparer()disent comment il se nettoie et ce qu'il rend au gabarit.assets/js/editeur.js(fonctioncontrole) etadmin/js/constructeur.js(fonctionreglagesDuType) fournissent ses contrôles.