1

The documentation for InnerBlock has a prop renderAppender which can be used to add a custom button. In the example:

// Fully custom
<InnerBlocks
    renderAppender={ () => (
        <button className="bespoke-appender" type="button">Some Special Appender</button>
    ) }
/>

the custom button does nothing on click. How can open the Block Picker Menu on click of the custom button?

2
  • Your button doesn't have a click handler which may look something like onClick={ ( event ) => console.log( event ) } - just call the appropriate function or whatever is needed on click.
    – Sally CJ
    Commented May 30, 2020 at 18:09
  • @SallyCJ yes I'm aware of that. Do you know which function needs to be called? I couldn't find it in the documentation as well as the source code. Commented May 31, 2020 at 8:05

2 Answers 2

2

So I'm answering the following: How to open the block picker menu via a custom button. I.e. Without using InnerBlocks.ButtonBlockAppender. :)

How can I open the Block Picker Menu on click of the custom button?

There's no (as of writing) "standard" function (like alert()) that you can simply call which then opens the block picker menu; however, you can wrap your button in a Inserter component (wp.blockEditor.Inserter) and call it's onToggle method/function on clicking your button.

Here's a simplified example based on ButtonBlockAppender (the base component that's used by InnerBlocks.ButtonBlockAppender) for the Gutenberg plugin version 8.2.1.

// WordPress dependencies.
import { Inserter, InnerBlocks } from '@wordpress/block-editor';
import { IconButton } from '@wordpress/components';
import { registerBlockType } from '@wordpress/blocks';

function MyButtonBlockAppender( { rootClientId } ) {
    return (
        <Inserter
            rootClientId={ rootClientId }
            renderToggle={ ( { onToggle, disabled } ) => (
                <IconButton
                    className="my-button-block-appender"
                    onClick={ onToggle }
                    disabled={ disabled }
                    label="Add a Block"
                    icon="plus"
                />
            ) }
            isAppender
        />
    );
}

registerBlockType( 'my-plugin/my-block', {
    title: 'My Block',
    category: 'common',

    edit( { className, clientId } ) {
        return (
            <div className={ className }>
                Click the button to add your 1st image/paragraph.
                <InnerBlocks
                    allowedBlocks={ [ 'core/image', 'core/paragraph' ] }
                    renderAppender={ () => (
                        <MyButtonBlockAppender rootClientId={ clientId } />
                    ) }
                />
            </div>
        );
    },

    save() {
        return (
            <div>
                <InnerBlocks.Content />
            </div>
        );
    },
} );

So as I said, that's a simplified example. You can just copy the original ButtonBlockAppender component and modify it to tailor your requirements.

Happy coding!

5

Custom renderAppenders require that you create all of the functionality of inserting blocks yourself. This is one I created a little while ago to only allow a single block to be inserted, you could modify the code as needed for your purposes.

/**
 * WordPress Imports
 */
const { createBlock } = wp.blocks;
const { Button } = wp.components;
const { withSelect, withDispatch } = wp.data;
const { compose } = wp.compose;
const { __ } = wp.i18n;


/**
 * Custom Appender meant to be used when there is only one type of block that can be inserted to an InnerBlocks instance.
 *
 * @param buttonText
 * @param onClick
 * @param clientId
 * @param allowedBlock
 * @param innerBlocks
 * @param {Object} props
 */
const SingleBlockTypeAppender = ( { buttonText = __( 'Add Item' ), onClick, clientId, allowedBlock, innerBlocks, ...props } ) => {
    return(
        <Button onClick={ onClick } { ...props} >
            {buttonText}
        </Button>
    );
};


export default compose( [
    withSelect( ( select, ownProps ) => {
        return {
            innerBlocks: select( 'core/block-editor' ).getBlock( ownProps.clientId ).innerBlocks
        };
    } ),
    withDispatch( ( dispatch, ownProps ) => {
        return {
            onClick() {
                const newBlock = createBlock( ownProps.allowedBlock );
                dispatch( 'core/block-editor' ).insertBlock( newBlock, ownProps.innerBlocks.length, ownProps.clientId );
            }
        };
    } )
] )( SingleBlockTypeAppender );

You can then use it like this:

<InnerBlocks
    renderAppender={
        () =>
            <SingleBlockTypeAppender
                isDefault
                isLarge
                buttonText="Add Block"
                allowedBlock="block/slug"
                clientId={ this.props.clientId }
            />
    }
/>

Hope this helps!

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.