Custom fields pour core blocks

Comme vous le savez sûrement, avec ACF, il est possible de créer des blocs custom. A ces blocs, on peut leur associer des custom fields en sélectionnant dans les règles d’affichage :

block => is equal to => votre bloc

Cependant, acf ne donne pas la possibilité d’associer des custom fields à des bloc natifs.

Avec un peu de code js, cela est possible.
Tout d’abord il faut enqueue un nouveau fichier js (ex: admin.js)

add_action('admin_enqueue_scripts', 'addJsAdmin');

function addJsAdmin() {
    wp_enqueue_script('my_admin_js', get_stylesheet_directory_uri().'/assets/js/admin.js', array(), filemtime(get_stylesheet_directory().'/assets/js/admin.js'), true);
}

Ensuite, il faut préciser dans le fichier admin.js il faut faire 3 hooks.

Le premier pour préciser le custom attribute au bloc (dans cet exemple sur le bloc cover).

function addBlocksCustomAttribute(settings, name) {
    var isAllowedBlock = (settings.name == 'core/cover');

    if (isAllowedBlock) {
        settings.attributes = Object.assign(settings.attributes, {
            myOption: {
                type: 'boolean'
            }
        });
    }
    return settings;
}

wp.hooks.addFilter('blocks.registerBlockType', 'fgh/block-custom-attribute', addBlocksCustomAttribute);

Puis, lors de la sélection du bloc cover, pour ajouter dans la sidebar un bouton de type toggle.

var blockAdvancedControls = wp.compose.createHigherOrderComponent(function (BlockEdit) {

    return function (props) {
        var isAllowedBlock = (props.name == 'core/cover');

        var Fragment = wp.element.Fragment;
        var ToggleControl = wp.components.ToggleControl;

        var PanelBody = wp.components.PanelBody;
        var InspectorControls = wp.blockEditor.InspectorControls;
        var attributes = props.attributes;
        var setAttributes = props.setAttributes;
        var isSelected = props.isSelected;

        var myOption = attributes.myOption;
        return React.createElement(
            Fragment,
            null,
            React.createElement(BlockEdit, props),
            isSelected && isAllowedBlock && React.createElement(
                InspectorControls,
                null,
                React.createElement(
                    PanelBody,
                    'Custom',
                    React.createElement(ToggleControl, {
                        label: 'With my option',
                        checked: !!myOption,
                        onChange: function (newval) {
                            return setAttributes({ myOption: !myOption });
                        },
                        help: !!myOption? 'Cover with my option' : 'Toggle to add my option on cover'
                    })
                )
            )
        );
    };
}, 'blockAdvancedControls');

wp.hooks.addFilter('editor.BlockEdit', 'fgh/block-advanced-control', blockAdvancedControls);

Pour finir, ce code pour enregistrer en base de données, la valeur saisie par l’utilisateur (dans notre exemple, on ajoute un nom de classe à la liste des classes du bloc : my-has-my-option)

function blockApplyExtraClass(extraProps, blockType, attributes) {
    var isAllowedBlock = (blockType.name == 'core/cover');
    var propriety = attributes.myOption;

    if (isAllowedBlock && propriety)
        extraProps['className'] = extraProps['className'] + ' my-has-my-option';

    return extraProps;
}

wp.hooks.addFilter('blocks.getSaveContent.extraProps', 'fgh/block-apply-class', blockApplyExtraClass);

Grâce à cela, en inspectant le bloc wp-block-cover, vous verrez apparaître la nouvelle classe si le toggle est à On.

Il est évidemment possible de créer d’autres types d’options (plutôt qu’un toggle). Ici la liste des types d’options disponibles : https://developer.wordpress.org/block-editor/reference-guides/components/
Par exemple, pour faire un select, il faudra créer un nouvel attribut, un élement de type SelectControl et adapter l’enregistrement de la valeur.

settings.attributes = Object.assign(settings.attributes, {
    mySelect: {
        type: 'string'
    }
});
var SelectControl = wp.components.SelectControl;
var mySelect= attributes.mySelect;

React.createElement(SelectControl, {
    label: 'my select',
    value: mySelect,
    options: [{ label: 'Not set', value: '' }, { label: 'Option A', value: 'option-a' }, { label: Option B', value: 'option-b' }],
    onChange: function (newval) {
        return setAttributes({ mySelect: newval });
    }
}),
var isAllowedBlock = (blockType.name == 'core/cover');
var propriety = attributes.mySelect;

if (isAllowedBlock && propriety)
    extraProps['className'] = extraProps['className'] + ' my-select-' + propriety;

Il est possible de cumuler plusieurs champs custom pour un même type de bloc.

On peut créer des champs custom pour tous les type de blocs sans exception, dans ce cas, il suffit de retirer les conditions dans le code faisant référence à isAllowedBlock.