5

I would like to extend the default image block and add an option to it.

enter image description here

The idea is to have an extra option to download the image locally if it is a remote image.

Is this possible and how ? Thanks.

4 Answers 4

4

WordPress provides a JS filter for adjusting the components used with the edit state called editor.BlockEdit. Passing a callback to said filter with a BlockControls fill allows you to inject whatever components you need.

The components returned from your callback will show up on every block by default. You can limit the return to your targeted block(s) by using the name of the block which is passed as name to the callback.

Putting it all together.

import {addFilter} from '@wordpress/hooks';
import {BlockControls} from '@wordpress/block-editor';
import {ToolbarButton} from '@wordpress/components';


const Download = BlockEdit => {
    return props => {
        if ( props.name !== 'core/image' ) {
            return <BlockEdit {...props} />;
        }

        return (
            <>
                <BlockControls>
                    <ToolbarButton
                        icon={'download'}
                        label="Download"
                        onClick={() => alert( props.attributes?.url )}
                    />
                </BlockControls>
                <BlockEdit {...props} />
            </>
        );
    };
};


addFilter( 'editor.BlockEdit', 'your-namespace', Download );

If you need custom attributes because you are saving data to the block you are extending, you may use the blocks.registerBlockType filter.

Assuming you are adding a custom downloadFile attribute, it could look like this.

function addAttribute( settings ) {
    if ( settings.name !== 'core/table' ) {
        return settings;
    }

    settings.attributes = {
        ...settings.attributes,
        downloadFile: {
            type: 'string',
        },
    };
    return settings;
}

addFilter( 'blocks.registerBlockType', 'your-namespace', addAttribute );

You can set the value of the attribute using setAttributes which is passed to your callback above.

<ToolbarButton
    icon={'download'}
    label="Download"
    onClick={() => props.setAttribute( {
        downloadFile: 'this is the new value',
    } )}
/>
1

While the slotfill might not be available in WP >= 5.9 any more (I didn't check that) as @mat-lipe mentioned in his answer there is another approach that should work for any block:

Using the editor.BlockEdit filter you can add a <ToolbarButton> to a block.

1
  • 1
    Thanks for the prompt to update my answer! I had been meaning to finish it.
    – Mat Lipe
    Commented Sep 16, 2022 at 19:28
0

Using the approach below you can create a custom block toolbar to your Gutenberg block.

First, create the custom component, save this as controls.js.

const { __ } = wp.i18n;
const { BlockControls } = wp.blockEditor;
const { DropdownMenu, MenuGroup, MenuItem, ToolbarGroup } = wp.components;

const Controls = (props) => {
    const { attributes, setAttributes } = props;
    const { theme } = attributes;

    const themes = [
        {
            key: '',
            label: __('Default', 'custom-domain'),
        },
        {
            key: 'dark',
            label: __('Dark', 'custom-domain'),
        },
        {
            key: 'retro',
            label: __('Retro', 'custom-domain'),
        },
        {
            key: 'vintage',
            label: __('Vintage', 'custom-domain'),
        },
    ];

    return (
        <BlockControls group="other">
            <ToolbarGroup>
                <DropdownMenu
                    icon={<span>{__('Theme', 'custom-domain')}</span>}
                    label={__('Switch Theme', 'custom-domain')}
                >
                    {({ onClose }) => (
                        <MenuGroup>
                            {themes.map((themeData) => {
                                return (
                                    <MenuItem
                                        icon={theme === themeData.key ? 'yes' : ''}
                                        onClick={() => {
                                            setAttributes({ theme: themeData.key });
                                            onClose();
                                        }}
                                    >
                                        {themeData.label}
                                    </MenuItem>
                                );
                            })}
                        </MenuGroup>
                    )}
                </DropdownMenu>
            </ToolbarGroup>
        </BlockControls>
    );
};

export default Controls;

Then, use to code approach below to add the custom toolbar to the existing block. I used Group block in this example:

/**
 * Add Custom Block Control to Existing Block
 */

import Controls from './controls';

const { createHigherOrderComponent } = wp.compose;
const { Fragment } = wp.element;

const allowedBlocks = ['core/group']; // Enable control to existing Group block

/**
 * Add custom attribute
 */
function addAttributes(settings) {
    // Check if attributes exists and compare the block name
    if (typeof settings.attributes !== 'undefined' && allowedBlocks.includes(settings.name)) {
        settings.attributes = Object.assign(settings.attributes, {
            theme: {
                type: 'string',
                default: '',
            },
        });
    }

    return settings;
}
wp.hooks.addFilter('blocks.registerBlockType', 'example/add-atttibutes', addAttributes);

/**
 * Add Custom Block Controls
 */
const addBlockControls = createHigherOrderComponent((BlockEdit) => {
    return (props) => {
        const { name, isSelected } = props;

        if (!allowedBlocks.includes(name)) {
            return <BlockEdit {...props} />;
        }

        return (
            <Fragment>
                {isSelected && <Controls {...props} />}
                <BlockEdit {...props} />
            </Fragment>
        );
    };
}, 'addBlockControls');

wp.hooks.addFilter('editor.BlockEdit', 'example/add-block-controls', addBlockControls);

You can follow this full instructions to create and extend the block toolbar in the Gutenberg block editor.

-2

I found this tutorial, How to Add a Button to The Gutenberg Editor, and its example on Github.

1
  • This example only works on RichText blocks and not the block requested in the question.
    – Mat Lipe
    Commented Nov 29, 2021 at 21:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.