Ajouter des options personnalisées

Il est très facilement possible d’ajouter des options personnalisées dans la sidebar d’un bloc natif.

Le code est écrit en jsx (Javascript Syntax Extension) et doit être compilé en javascript.

Dans cette exemple, nous souhaitons ajouter une option nous permettant de cacher un bloc sur mobile.

Pour cela, nous allons ajouter un bouton radio appelé “toggleControl”. Sa valeur est un boolean ou indéfini.

import classnames from 'classnames';

( function( wp ) {
    const { __ } = wp.i18n;
    const { addFilter } = wp.hooks;
    const { Fragment, useState } = wp.element;
    const { InspectorControls } = wp.blockEditor;
    const { createHigherOrderComponent } = wp.compose;
    const { PanelBody, ToggleControl } = wp.components;

    // Seuls les blocs de type "paragraph" et "group" auront ce nouveau attribut
    const allowedBlocks = [ 'core/paragraph', 'core/group' ];

    function addAttributes( settings, name ) {

        // Si on n'est pas sur un type de blocs autorisés, on retourne les settings initiaux
        if (!allowedBlocks.includes(name)) {
            return settings;
        }

        // On ajoute notre attribut custom à notre type de bloc
        settings.attributes = Object.assign( settings.attributes, {
            hiddenOnMobile: {
                type: 'boolean',
            },
        });

        // On retourne les settings mis à jour
        return settings;
    }

    const addAdvancedControls = createHigherOrderComponent( ( Block ) => {
        return ( props ) => {

            const { name, attributes, setAttributes, isSelected } = props;

            // Si on n'est pas sur un type de blocs autorisés, on retourne le bloc initial
            if(!allowedBlocks.includes(name)) {
                return(
                    <Block {...props} />
                )
            }

            // On récupère l'attribut
            const { hiddenOnMobile } = attributes;
            const [ , setHiddenOnMobile ] = useState( hiddenOnMobile );

            // On retourne le code html de l'élément à ajouter
            // Dans notre exemple, on ajoute un PanelBody avec un ToggleControl à l'intérieur
            return (
                <Fragment>
                    <Block { ...props } />
                    { isSelected &&
                        <InspectorControls>
                            <PanelBody title={ __('Block hidden on mobile', 'flu') } >
                            <ToggleControl
                                label="Hidden on mobile"
                                help={
                                    hiddenOnMobile
                                        ? 'Is hidden.'
                                        : 'Is visible.'
                                }
                                checked={ hiddenOnMobile }
                                onChange={ (hiddenOnMobile) => {
                                    // On enregistre l'état du toggleControl
                                    setHiddenOnMobile( ( state ) => ! state );

                                    // On modifie la valeur de l'attribut
                                    setAttributes( { hiddenOnMobile } )
                                } }
                            />
                            </PanelBody>
                        </InspectorControls>
                    }
                </Fragment>
            );
        };
    }, 'addAdvancedControls');

    const addCustomClassToBlock = createHigherOrderComponent( ( Block ) => {
        return ( props ) => {

            const { name } = props;

            // Si on n'est pas sur un type de blocs autorisés, on retourne le bloc initial
            if(!allowedBlocks.includes(name)) {
                return(
                    <Block {...props} />
                )
            }

            // On récupère l'attribut
            const { hiddenOnMobile } = props.attributes;

            // Si l'attribut du bloc hiddenOnMobile est à true
            if(hiddenOnMobile != undefined && hiddenOnMobile === true) {
                const className = 'sserpdrow-is-hidden-on-mobile';

                // On retourne le bloc avec une classe personnalisée "sserpdrow-is-hidden-on-mobile"
                return (
                    <Block { ...props } className={className} />
                );
            }
            else {
                // On retourne le bloc original
                return(
                    <Block {...props} />
                )
            }
        };
    }, 'addAdvancedControls');

    function applyExtraClass( extraProps, blockType, attributes ) {

        // Si on n'est pas sur un type de blocs autorisés, on retourne les extra propriétés originales
        if(!allowedBlocks.includes(blockType.name)) {
            return extraProps;
        }

        // On récupère l'attribut
        const { hiddenOnMobile } = attributes;

        // Si l'attribut du bloc hiddenOnMobile est à true
        if(hiddenOnMobile != undefined && hiddenOnMobile === true) {

            // On retourne les extra propriétés avec une classe personnalisée "sserpdrow-is-hidden-on-mobile"
            let myClasses = 'sserpdrow-is-hidden-on-mobile';

            return lodash.assign( 
                extraProps, 
                { 
                    className: classnames( extraProps.className, myClasses )
                } 
            );
        }

        return extraProps;
    }


    // Ce filtre permet d'ajouter les attributs d'un type de bloc
    addFilter(
        'blocks.registerBlockType',
        'flu/custom-attributes-hiddenOnMobile',
        addAttributes
    );

    // Ce filtre permet d'ajouter de nouvelles options dans la sidebar
    addFilter(
        'editor.BlockEdit',
        'flu/custom-advanced-control-hiddenOnMobile',
        addAdvancedControls
    );

    // Ce filtre permet de modifier le bloc avant de l'afficher dans l'éditeur
    addFilter(
        'editor.BlockListBlock',
        'flu/custom-block-class-hiddenOnMobile',
        addCustomClassToBlock
    );

    //Ce filtre permet de charger et enregistrer les extra propriétés
    addFilter(
        'blocks.getSaveContent.extraProps',
        'flu/applyExtraClass-hiddenOnMobile',
        applyExtraClass
    );

} ) ( wp );

La documentation sur wordpress.org :
https://developer.wordpress.org/block-editor/reference-guides/components/

Tous les types d’éléments :
https://wordpress.github.io/gutenberg/

Syntaxe des fonctions :
https://www.w3schools.com/react/react_es6_arrow.asp

Comprendre le hook d’état “useState” :
https://fr.reactjs.org/docs/hooks-state.html