On va maintenant donner de l’interactivité à nos blocs en ajoutant des options et paramètres, qui trouveront leur place dans l’inspecteur Gutenberg, c’est-à-dire la barre latérale à droite de l’éditeur.
Sommaire du cours
L’inspecteur Gutenberg
L’inspecteur est la barre latérale de Gutenberg, située à droite de l’écran, et qui permet à la base de définir la catégorie, les mots-clés, et les paramètres de publication de l’article.
Mais lorsque vous sélectionnez un élément de votre contenu, elle se transforme et fait apparaitre, selon le bloc sélectionné, tout un tas d’options le concernant.
C’est notamment le cas du bloc paragraphe, qui dispose de nombreux réglages sympathiques :
On voit pas mal de choses intéressantes dans cet inspecteur :
- Des zones de réglages en accordéon que l’on peut ouvrir / fermer ;
- Des groupes de boutons ;
- Une glissière (range) pour définir la taille du texte ;
- Un bouton On / Off ;
- Un sélecteur de couleurs plutôt sexy…
Et comme vous pouvez l’imaginer ce sont des composants prêts-à-l’emploi que l’on va pouvoir réutiliser à volonté pour nos propres blocs !
Ajouter des réglages à l’inspecteur
Dans ce cours je vais me baser sur l’exemple 11 situé dans src/12-inspector
. Je n’affiche pas le code en entier car il commence à se faire un peu long et on ne va d’ailleurs pas tarder à remédier à cela.
Cet exemple est un dérivé de notre bloc « Titre de chapitre » vu dans le cours sur CSS et Sass. C’était le candidat idéal pour lui ajouter toute une série de nouvelles options.
Pour rappel voici à quoi ressemble le bloc :
Jusqu’à maintenant il n’était pas personnalisable. Mais il y a pleins de réglages qu’on peut ajouter afin de le rendre plus sympa :
- Le signe du chapitre ;
- La couleur des textes et du fond ;
- L’arrondi des bordures…
Et voici maintenant le bloc avec ses nouveaux réglages :
Comme vous pouvez vous en douter, tous ces éléments sont proposés par Gutenberg et je m’en suis servi allègrement pour les réutiliser à ma manière.
En réalité les cas où vous aurez besoin de créer vos propres composants devraient rester tout de même rares. Ça m’est arrivé pour mon bloc « Plugin » où j’ai créé un champ de recherche, qui affiche une liste de résultats. J’en ai fait un composant que je peux du coup facilement réutiliser dans mes prochains blocs. Je vous présenterai cela dans un prochain cours.
Revenons-en à mon Inspecteur. Voici le découpage des composants de Gutenberg que j’ai utilisés :
Tous ces composants sont à charger en début de fichier, soit via @wordpress/components
, soit via @wordpress/block-editor
:
Le composant <PanelBody>
vous permet de créer des sections entre vos réglages, qui pourront être réduites par l’utilisateur. Votre inspecteur fonctionnera donc comme un accordéon.
Son cousin, le PanelColorSettings
fait la même chose, mais affichera en plus les couleurs sélectionnées dans la ou les palettes (et dont les couleurs par défaut sont personnalisables en PHP).
J’utilise ensuite des éléments d’interface comme le groupe de boutons <ButtonGroup>
, l’interrupteur on/off <ToggleControl>
et le <RangeControl>
pour choisir une valeur numérique grâce à une glissière.
Si vous avez besoin de faire un champ de formulaire tout simple, sachez qu’il existe des composants pour faire des champs classiques comme <TextControl>
.
Il existe également un composant <PanelRow>
qui permet de faire une colonne pour afficher le libellé à côté du champ et non au dessus.
Afficher des composants dans l’inspecteur
Pour afficher des données dans l’inspecteur, il suffit d’appeler le composant <InspectorControls>
, tout comme on appelle <BlockControls>
lorsque l’on veut personnaliser la barre d’outils de texte.
Au niveau de la méthode edit
, si je simplifie j’obtiens ceci :
Rappel : on utilise <Fragment>
car React n’aime pas que l’on retourne 3 éléments de même niveau en même temps. Le fragment nous évite d’ajouter un conteneur sous forme de <div>
qui n’aurait aucune utilité ici.
Mais si je regarde mon code complet, c’est tout de suite moins lisible : on commence à avoir beaucoup de lignes pour un seul fichier. Heureusement pour nous, on va apprendre à optimiser tout ça dans les prochains cours et notamment créer des sous-composants, ce qui permettra de séparer le code en plusieurs fichiers !
Les attributs
Comme vous vous en doutez très probablement, chaque paramètre est enregistré dans un attribut, et la liste vient donc s’agrandir :
J’ai ajouté un attribut pour le signe du chapitre, qui par défaut est # et dont la valeur sera stockée dans le HTML directement. J’ai donc ajouté la classe .sign
pour la localiser (et qui est situé à l’endroit où j’affichais déjà auparavant mon sigle).
La couleur du texte et du fond seront appliqués en style CSS dans le HTML, mais leur valeur va être stockée dans le commentaire HTML. Idem pour la valeur de l’arrondi du bloc.
Enfin, je donne la possibilité d’appliquer ou non un arrondi, et c’est la valeur booléenne withRadius
qui va stocker cette information.
Grâce à cette valeur je vais pouvoir mettre un interrupteur dans l’inspecteur « Activer l’arrondi » : si activé, j’affiche le champ glissière (le range) qui me permet de choisir la valeur de l’arrondi, sinon je le laisse caché.
Mais j’aurais pu tout aussi bien m’en passer et laisser tout le temps le champ de réglage de l’arrondi affiché. L’utilisateur qui n’en voudrait pas n’aurait qu’à passer la valeur à 0. J’ai cependant opté pour l’approche de la « logique conditionnelle » afin de simplifier l’interface.
Une fois que j’ai touché à tous les réglages, si je regarde mon code HTML généré j’obtiens quelque chose comme ceci :
Les couleurs, la présence de l’arrondi et sa valeur sont enregistrés en commentaires alors que le sigle, le titre et le numéro sont enregistrés en HTML.
Les composants en détails
Voyons maintenant comment chaque composant fonctionne :
Le PanelBody
Aucun mystère autour de ce composant, il suffit de l’appeler et de mettre tout ce que l’on souhaite dedans. Seul l’attribut title
est nécessaire pour donner un titre. Ensuite il marche de lui même comme tout bon composant React qui se respecte. Le fait de cliquer sur la petite flèche à droite fera apparaitre ou disparaitre le contenu.
En consultant son code, on voit qu’il existe un paramètre initialOpen
qui permet de mettre le panneau en position fermée par défaut. Pour cela ajoutez initialOpen={ false }
dans votre balise.
Le ButtonGroup
Le groupe de boutons est un composant tout simple permettant de regrouper visuellement des boutons. Il est utilisé conjointement avec le composant bouton.
Je l’utilise pour permettre à l’utilisateur de choisir le sigle de chapitre qui est par défaut #.
J’aurais très bien pu mettre mes 3 boutons à la main dedans, mais histoire de voir un peu de Javascript en action j’ai décidé d’optimiser mon code pour éviter les répétitions (et ainsi respecter le principe DRY : Don’t Repeat Yourself).
Voici mon code et celui que l’on peut trouver dans le bloc paragraphe par défaut de Gutenberg :
Dans les 2 cas on peut utiliser la fonction map
, qui a plein d’utilités en JS donc notamment d’itérer sur une liste ou un objet, un peu à la manière d’une boucle for ou forEach.
Dans mon cas je veux créer un bouton par sigle possible : #, n° ou §. Je crée donc une liste simple à laquelle j’attache la fonction map. A chaque occurence je récupère le sigle suivant qui s’appelle sign
le temps de la boucle.
Dans l’autre cas, c’est un peu la même chose sauf que cette fois map
itère sur un objet { clé: 'valeur' }
au lieu d’une liste ['a', 'b', 'c']
. La clé est la valeur de la taille du texte (qui sera enregistré) et la valeur le libellé affiché dans l’interface.
Attention à la syntaxe ! Ici on referme 2 parenthèses : d’abord le bout de template HTML puis la fin de fonction map, et enfin l’accolade qui ouvrait la partie script.
C’est toujours un peu galère de s’y retrouver entre les parenthèses et les accolades, alors voici un petit pense bête :
Quand je suis en JS, j’ouvre les parenthèses pour afficher du HTML. Et dans le HTML j’ouvre une accolade si j’ai besoin d’ajouter un petit bout de JS (par exemple un test ternaire).
C’est pour cela qu’il est essentiel de garder un code clair, et avoir une bonne imbrication. Rassurez-vous, au bout d’un moment on s’y fait et on ne fait (presque) plus d’erreur.
Et enfin pour finir sur ce groupe de boutons, voyons les paramètres intéressants :
- isLarge : permet d’afficher une apparence grise au lieu de transparent (oui je sais, aucun rapport avec le nom)
- isPrimary : permet de colorer le bouton en bleu pour dire qu’il est actif
Enfin notez que l’on a rien besoin de faire d’autre : lorsqu’on est dans le <ButtonGroup>
, un seul bouton peut-être cliqué. Le composant se comporte donc comme des boutons radios.
La ColorPalette et le PanelColorSettings
Venons-en aux palettes de couleurs, il faut dire que je les adore car elles sont super bien conçues ! Elles proposent par défaut un set de couleurs, mais chaque thème peut bien entendu proposer le sien.
De plus, vous pourrez même bloquer le bouton de couleur « personnalisée » afin que votre client ne transforme par le site en une guirlande de Noël. On verra d’ailleurs comment personnaliser la palette un peu plus tard dans la formation.
Afin de proposer des couleurs, on a deux solutions : soit utiliser le composant <ColorPalette>
, soit le composant <PanelColorSettings>
. Ce dernier est pratique lorsque vous souhaitez utiliser plusieurs sélecteurs de couleurs en même temps. C’est bien notre cas puisque l’on propose de changer la couleur du texte, ainsi que celle du fond.
Alors lequel choisir ? De manière plus générale on ne va pas s’embêter : que l’on utilise un ou plusieurs sélecteurs de couleurs, on va opter en priorité pour le <PanelColorSettings>
. Le seul moment où vous utiliseriez la <ColorPalette>
est lorsque vous voulez placer un sélecteur de couleur avec d’autres réglages, et pas dans une section à part entière de l’inspecteur.
Petit détail sympa au passage : lorsque l’on ferme le panneau, on a un aperçu des couleurs sélectionnées dans l’en-tête.
Pour utiliser ce panneau, il faut jouer avec le paramètre colorSettings
dans lequel on indique, sous forme d’objets, les attributs à manipuler. Notez du coup que l’on n’a pas besoin d’appeler les palettes manuellement.
C’est dans ces moments là que l’on se rend compte que l’approche React est puissante et incroyablement utile pour Gutenberg dans le sens où c’est une application web facilement extensible par les développeurs. Et que lorsque l’on a fait un beau composant comme la palette, on peut facilement la réutiliser ailleurs.
Le ToggleControl
Si comme moi vous aimez bien les interrupteurs on/off, vous allez adorer utiliser <ToggleControl>
. Plus sexy qu’une case à cocher, il permet de retourner simplement un true ou un false.
C’est là où je vais utiliser mon attribut withRadius
. Ici pas de paramètre value
mais à la place checked
.
Autre petit changement : dans la fonction onChange
, je vais simplement appliquer l’inverse de la valeur actuellement enregistrée (si c’est true, je false, et si c’est false, je true) et je le fais tout simplement avec un point d’exclamation qui me donne l’inverse :
Du coup cette valeur va me servir à plusieurs choses :
Dans l’inspecteur
Si j’ai activé ce bouton, alors j’affiche le champ me permettant de définir la valeur de l’arrondi. Pour cela il me suffit juste après d’entourer mon prochain champ de ce simple test :
Pour rappel ça revient à dire : si withRadius
est vrai alors j’affiche mon <RangeControl>
, sans utiliser un if (car indisponible ici) !
Dans mon bloc
Dans mon bloc cela va me permettre d’appliquer l’arrondi de props.attributes.radius
seulement si withRadius
est vrai :
J’aime la simplicité de l’approche ici : React va automatiquement comprendre qu’il ne doit pas appliquer le CSS s’il reçoit un « false ». Cela évite des gymnastiques de code, comme par exemple faire le test et stocker les styles en amont du template.
En fait ce genre de tests « raccourcis » servent réellement à ça : éviter de devoir tester des choses en amont et le faire à l’instant précis où c’est nécessaire. Malin !
Le RangeControl
Et enfin, le <RangeControl>
, très utile pour tout ce qui concerne la définition d’une valeur numérique : taille du texte, valeur de l’arrondi, largeur ou hauteur…
Il propose quelques options sympathiques :
Tout d’abord la valeur de l’attribut à appliquer, dans notre cas radius
. L’évènement onChange
dont on commence à avoir l’habitude, mais aussi les valeurs minimum et maximum autorisées pour ce champ, pratique pour créer des contraintes.
Enfin, les paramètres beforeIcon
et afterIcon
vous permettent de définir des Dashicons ou SVG personnalisés affichés avant et après la glissière. Dans cet exemple j’ai mis des flèches. Concernant le paragraphe, comme il s’agit de la taille du texte, ce sont un petit A et un plus grand A qui sont affichés.
Bien, on a découvert de nouveaux composants Gutenberg à réutiliser sans modération, ainsi que comment manipuler l’inspecteur pour ajouter ses propres paramètres.
Ce cours est très important car il vient de vous ouvrir un nouvel univers de possibilités concernant vos blocs.
Avec ces nouvelles compétences on commence à être pas mal, mais avant d’aller plus loin on va essayer dans le prochain cours d’optimiser un peu tout cela.
Fred - FLQ
Le 23 mai 2024
J’essaie de refaire un peu tous les exemples proposés. Pour celui-ci, le {textColor} n’est appliqué qu’au numéro de chapitre et au signe qui le précède. Je me suis demandé comment appliquer la même couleur à tout le texte du bloc (number et titre). J’ai fini par ajouter un avec un attribut « style » qui englobe le (sans tagName) et cela semble fonctionner.
Est-ce la bonne approche ou il y aurait plus pertinent ?
Merci encore pour tous ces contenus !
Maxime BJ
Le 23 mai 2024
Il suffit d’appliquer le type dans la
avec la classe first-line !
Fred - FLQ
Le 23 mai 2024
Yes mais ça écrase tout le reste des styles. Je sens que c’est tout bête, je regarderai ça à nouveau à la fraîche ! Merci pour ta réponse. 🙂
Maxime BJ
Le 23 mai 2024
C’est vrai ! Du coup pour tout ce qui est appliquable à l’intégralité du bloc maintenant tu as une option pour activer les couleurs pour le bloc nativement, sans créer d’attribut. Je montrerai ça dans la version mise à jour de la formation.