< Retour au blog

Ajouter des options et contrôles à un bloc Gutenberg existant

Publié le

dans la catégorie

,

Cet article explique comment ajouter des options et contrôles aux blocs existants de l’éditeur de WordPress, Gutenberg, et les sauvegarder dans les attributs.

La procédure est différente de l’ajout de contrôles lorsqu’on créé des blocs sur mesure, puisque nous utiliserons uniquement des filtres pour nous greffer à des blocs existants. Les filtres disponibles dans l’éditeur fonctionnent comme les filtres PHP (add_filter, apply_filters).

Il est préférable que vous ayez des bases dans l’utilisation de React et/ou JavaScript pour comprendre ce tutoriel. Je n’entrerai pas dans les détails des concepts liés aux composants, etc.

Je vous invite à consulter la documentation sur les filtres avant de lire cet article.

L’ensemble du code fonctionnel est disponible sous la forme d’une extension.

Les étapes pour ajouter un contrôle

L’ajout d’un contrôle personnalisé se compose de quatre étapes :

  1. Déclarer un attribut personnalisé afin d’enregistrer la valeur du contrôle
  2. Ajouter le contrôle à l’emplacement voulu
  3. Manipuler le rendu du bloc
  4. Enregistrer le bloc

Pour ce premier exemple, nous ajouterons un bouton à la Toolbar du bloc paragraphe. L’ensemble du code est visible sur le dépôt de l’extension.

Déclarer un attribut personnalisé

Si vous souhaitez ajouter un contrôle à un bloc, c’est probablement que vous souhaitez enregistrer sa valeur en même temps que les autres valeurs du bloc.

Au même titre que les champs personnalisés d’une publication, les attributs d’un bloc doivent être déclarés au préalable. Lorsqu’on créé un bloc sur mesure, on le fait au moment de la déclaration du bloc.
En revanche, si on souhaite ajouter un attribut à un bloc existant (natif ou non), nous devons utiliser un filtre : blocks.registerBlockType.

const enableToolbarButtonOnBlocks = [ 'core/paragraph' ]; const setToolbarButtonAttribute = ( settings, name ) => { // Do nothing if it's another block than our defined ones. if ( ! enableToolbarButtonOnBlocks.includes( name ) ) { return settings; } return Object.assign( {}, settings, { attributes: Object.assign( {}, settings.attributes, { paragraphAttribute: { type: 'string' } } ), } ); }; wp.hooks.addFilter( 'blocks.registerBlockType', 'custom-attributes/set-toolbar-button-attribute', setToolbarButtonAttribute );
Langage du code : JavaScript (javascript)

Dans le code ci-dessus, dans setToolbarButtonAttribute nous ajoutons l’attribut paragraphAttribute, en spécifiant que c’est une chaîne (string). Vous personnaliserez paragraphAttribute en fonction de votre contrôle.

Ensuite, nous venons ajouter ceci au bloc paragraphe en nous branchant sur wp.hooks.addFilter, blocks.registerBlockType, qui est un filtre joué sur chaque déclaration de bloc.

Un mot sur la condition présente en début de code :

if ( ! enableToolbarButtonOnBlocks.includes( name ) ) { return settings; }
Langage du code : JavaScript (javascript)

Elle permet simplement de vérifier que le bloc courant fait partie d’une liste autorisée et qui est déclarée dans enableToolbarButtonOnBlocks.

À noter que si votre contrôle personnalisé doit être sauvegardé au niveau d’un attribut existant (par exemple l’attribut align), vous pouvez ignorer cette première étape.

Ajouter le contrôle au bloc

Une fois l’attribut déclaré, on ajoute le contrôle au bloc afin que l’attribut soit modifiable dans l’éditeur. Dans ce premier exemple, on ajoute un bouton à la Toolbar :

const withToolbarButton = createHigherOrderComponent( ( BlockEdit ) => { return ( props ) => { // If current block is not allowed if ( ! enableToolbarButtonOnBlocks.includes( props.name ) ) { return ( <BlockEdit { ...props } /> ); } const { attributes, setAttributes } = props; const { paragraphAttribute } = attributes; return ( <Fragment> <BlockControls group="block"> <ToolbarGroup> <ToolbarButton icon="format-status" label={ __( 'Custom Button', 'core-block-custom-attributes' ) } isActive={ paragraphAttribute === 'custom' } onClick={ () => { if ( paragraphAttribute === 'custom' ) { setAttributes( { paragraphAttribute: false } ) } else { setAttributes( { paragraphAttribute: 'custom' } ) } } } /> </ToolbarGroup> </BlockControls> <BlockEdit { ...props } /> </Fragment> ); }; }, 'withToolbarButton' ); wp.hooks.addFilter( 'editor.BlockEdit', 'custom-attributes/with-toolbar-button', withToolbarButton );
Langage du code : JavaScript (javascript)

Tout d’abord, non utilisons createHigherOrderComponent, qui permet de modifier un composant existant et d’accéder à ses propriétés, afin de modifier la Toolbar.

Ensuite, nous utilisons BlockControls afin de nous positionner dans la Toolbar, puis ToolbarGroup, et enfin nous créons notre bouton avec le composant ToolbarButton. C’est ici que l’ajout de la valeur custom de l’attribut, et sa suppression sont gérés, dans la méthode onClick.

Cette fois, nous utilisons le filtre editor.BlockEdit, qui est joué dans les fonctions Edit des blocs.

À propos de l’attribut group="block" sur le BlockControls : il permet de se positionner au même niveau que les contrôles ajoutés au niveau du bloc (dans sa déclaration).

Si vous le retirez, votre contrôle sera ajouté dans un container suivant ces contrôles.

Manipuler le rendu du bloc dans l’éditeur

À ce stade, notre contrôle s’affiche et l’attribut est bien ajouté ou supprimé lorsqu’on clic sur le bouton.

Ce n’est pas visible, car en lui même, l’attribut ne change rien. Si vous souhaitez utiliser l’attribut via le HTML, il faut par exemple ajouter une classe CSS au bloc en fonction de l’attribut.

Pour cela, nous utiliserons le filtre editor.BlockListBlock qui permet de modifier les propriétés (props) du wrapper du bloc, et donc d’y ajouter une classe CSS, ou un attribut HTML, par exemple.

const withToolbarButtonProp = createHigherOrderComponent( ( BlockListBlock ) => { return ( props ) => { // If current block is not allowed if ( ! enableToolbarButtonOnBlocks.includes( props.name ) ) { return ( <BlockListBlock { ...props } /> ); } const { attributes } = props; const { paragraphAttribute } = attributes; if ( paragraphAttribute && 'custom' === paragraphAttribute ) { return <BlockListBlock { ...props } className={ 'has-custom-attribute' } /> } else { return <BlockListBlock { ...props } /> } }; }, 'withToolbarButtonProp' ); wp.hooks.addFilter( 'editor.BlockListBlock', 'custom-attributes/with-toolbar-button-prop', withToolbarButtonProp );
Langage du code : JavaScript (javascript)

Dans ce code, nous vérifions simplement que notre attribut paragraphAttribute contient bien la valeur « custom », et si oui, nous ajoutons une classe CSS has-custom-attribute. Si non, on retourne les propriétés originales du bloc.

Enregistrer le bloc

C’est la dernière étape, il nous faut maintenant enregistrer le bloc.

Cela ressemble pas mal à l’étape précédente : si notre attribut est présent et contient la valeur « custom », on ajoute la classe has-custom-attribute au wrapper.

Cette fois-ci, nous sommes sur le filtre blocks.getSaveContent.extraProps, qui permet d’enregistrer des propriétés personnalisées (ici, une classe CSS) pour le bloc.

const saveToolbarButtonAttribute = ( extraProps, blockType, attributes ) => { // Do nothing if it's another block than our defined ones. if ( enableToolbarButtonOnBlocks.includes( blockType.name ) ) { const { paragraphAttribute } = attributes; if ( paragraphAttribute && 'custom' === paragraphAttribute ) { extraProps.className = classnames( extraProps.className, 'has-custom-attribute' ) } } return extraProps; }; wp.hooks.addFilter( 'blocks.getSaveContent.extraProps', 'custom-attributes/save-toolbar-button-attribute', saveToolbarButtonAttribute );
Langage du code : JavaScript (javascript)

Pour résumer : nous avons ajouté un bouton à la Toolbar du bloc Paragraphe. Ce bouton permet d’ajouter ou de supprimer la valeur « custom » de l’attribut nommé paragraphAttribute, et quand il possède cette valeur, le Paragraphe aura la classe CSS « has-custom-attribute ».

Deuxième exemple

Dans ce deuxième exemple, nous ajoutons un sélecteur dans la Sidebar du bloc Image. Le but étant d’avoir une liste d’options disponible, et que la valeur de l’option soit utilisée pour contruire une classe CSS dynamique.

À nouveau le code complet est visible sur le dépôt.

La déclaration de l’attribut ne change pas par rapport au premier exemple, mis à part le nom des méthodes et la clé de l’attribut.

En revanche, l’ajout du contrôle varie, puisque cette fois nous ajoutons notre contrôle dans la Sidebar et non dans la Toolbar :

return ( <Fragment> <BlockEdit { ...props } /> <InspectorControls> <PanelBody title={ __( 'Image Custom Attributes' ) } > <SelectControl label={ __( 'Custom Attribute' ) } value={ imageAttribute } options={ [ { label: __( 'None' ), value: '' }, { label: __( 'One' ), value: 'one' } ] } onChange={ ( value ) => { setAttributes( { imageAttribute: value, } ); } } /> </PanelBody> </InspectorControls> </Fragment> );
Langage du code : JavaScript (javascript)

Pour cela nous utilisons le composant InspectorControls, qui permet de se positionner donc dans la Sidebar, puis nous ajoutons un composant Panel et enfin notre Select. C’est dans ce dernier que la valeur de l’attribut est définie en fonction de l’option choisie.

La gestion de l’édition du wrapper du bloc et sa sauvegarde ne changent pas beaucoup par rapport au premier exemple, nous attribuons toujours une classe au wrapper du bloc, et elle se compose d’une partie dynamique : l’option choisie dans le Select.

className={ 'has-option-' + imageAttribute }
Langage du code : JavaScript (javascript)

Ainsi lorsqu’on choisira l’option « One », le bloc Image aura la classe « has-option-one ».

Pour aller plus loin

Si vous souhaitez modifier l’extension créée pour ce tutoriel, pour développer vos propres contrôles par exemple, téléchargez le dossier de l’extension, installez les dépendances (npm install) et utilisez la documentation pour connaître les commandes disponibles.

Enfin, n’hésitez pas à laisser votre commentaire sur cet article !

4 réponses à “Ajouter des options et contrôles à un bloc Gutenberg existant”

  1. Bonjour,

    Merci grâce a votre tuto, j’ai réussi a créer des réglages pour un bloc paragraphe
    une partie avec la toolbar ( ex ajout d’un icône) une autre avec l’inspecteur comme dans votre
    2ème exemple (ex régler la largeur du paragraphe).
    Tout ceci en modifiant uniquement les fichiers du dossier attributes de votre extension

    Un problème demeure, la classe attribué par l’inspecteur est prioritaire par rapport a celle de la toolbar
    Si j’ajoute un icône via la toolbar, alors la classe est appliquée mais disparait dés que j’applique une classse de largeur via l’inspecteur.

    Ma question est donc comment faire coexister les classes via la toolbar & l’inpecteur pour un même bloc?

  2. Bonjour,

    Ce tutorial m’a été vraiment utile mais dans une situation particulière j’ai rencontré une petit bug lors de la manipulation pour le rendu dans l’éditeur :
    if ( paragraphAttribute && ‘custom’ === paragraphAttribute ) {
    return
    } else {
    return
    }

    Cela empeche l’ajout de plusieurs classes, il faudrait plutot faire (comme dans saveToolbarButtonAttribute ) :
    if ( paragraphAttribute && ‘custom’ === paragraphAttribute ) {
    return
    } else {
    return
    }

    Je ne sais pas si la solution est parfaite mais cela a fonctionné pour moi, si jamais d’autres sont intéressés.

    • WordPress filtre le code visiblement 🙂
      Il faudrait plutot faire un classnames pour l’ajout de la classe
      : ( props.className, ‘has-custom-attribute’ )

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.