Search code examples
wordpresswordpress-gutenberg

WordPress Gutenberg Register Multiple Custom Blocks


I am trying to create several custom blocks within Gutenberg. It is only allowing me to register one at a time.

I have tried combining recipe_card_block() and first_block() but that doesn't help.

Both blocks work correctly individually. If I remove recipe_card_block(), first_block() will appear in the inserter (and vice versa). However, when both are present only the first one will show up. Changing the order in which they are registered affects which one appears.

It seems to me they are somehow overwriting each other, but I don't see how that's happening.

Here is the code in functions.php.

function recipe_card_block(){
    wp_register_script(
        'recipe-card-script', // name of script
        get_template_directory_uri() . '/js/recipe-card.js', // path to script
        array( 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ) // dependencies
    );

    wp_register_style(
        'recipe-card-style',
        get_template_directory_uri() . '/css/recipe-card-style.css',
        array( 'wp-edit-blocks' )
    );

    register_block_type('gadam/recipe-card', array(
        'editor_script' => 'recipe-card-script', // default script / script to define behavior within the editor
        'style'         => 'recipe-card-style' // default styles
    ) );
}
add_action( 'init', 'recipe_card_block' );

function first_block(){
    wp_register_script(
        'first-block-script', // name of script
        get_template_directory_uri() . '/js/first-block.js', // path to script
        array( 'wp-blocks', 'wp-element', 'wp-editor' ) // dependencies
    );
    // styles for editor view
    wp_register_style(
        'first-block-editor-style',
        get_template_directory_uri() . '/css/first-block-editor-style.css',
        array( 'wp-edit-blocks' )
    );
    // default styles
    wp_register_style(
        'first-block-style',
        get_template_directory_uri() . '/css/first-block-style.css',
        array( 'wp-edit-blocks' )
    );

    register_block_type('gadam/first-block', array(
        'editor_script' => 'first-block-script', // default script / script to define behavior within the editor
        'editor_style'  => 'first-block-editor-style', // styles for editor view
        'style'         => 'first-block-style' // default styles
    ) );
}
add_action( 'init', 'first_block' );

This is the code in first-block.js

const { registerBlockType } = wp.blocks;
const { RichText, BlockControls, InspectorControls, AlignmentToolbar, FontSizePicker } = wp.editor;
const { Fragment } = wp.element;

registerBlockType( 'gadam/first-block', {
    title: 'First Block',
    icon: 'welcome-learn-more',
    category: 'custom-blocks',

    attributes: {
        content: {
            type: 'string',
            source: 'html',
            selector: 'p'
        },
        alignment: {
            type: 'string'
        },
        fontSize: {
            type: 'number',
            default: 18
        }
    },

    edit( { attributes, className, setAttributes } ) {
        const { content, alignment, fontSize } = attributes;
        const fontSizes = [
            {
                name: 'Small',
                slug: 'small',
                size: 14
            },
            {
                name: 'Normal',
                slug: 'normal',
                size: 18
            },
            {
                name: 'Large',
                slug: 'large',
                size: 24
            }
        ];

        function onChangeContent( newContent ) {
            setAttributes( { content: newContent } );
        }

        function onChangeAlignment( newAlignment ) {
            setAttributes( { alignment: newAlignment } );
        }

        function onChangeFontSize( newFontSize ) {
            setAttributes( { fontSize: newFontSize } );
        }

        return (
            <Fragment>
                <BlockControls>
                    <AlignmentToolbar
                        value={ alignment }
                        onChange={ onChangeAlignment }
                    />
                </BlockControls>
                <InspectorControls>
                    <AlignmentToolbar
                        value={ alignment }
                        onChange={ onChangeAlignment }
                    />
                    <FontSizePicker
                        fontSizes={ fontSizes }
                        value={ fontSize }
                        onChange={ onChangeFontSize }
                    />
                </InspectorControls>
                <RichText
                    key="editable"
                    tagName="p"
                    className={ className }
                    style={ { textAlign: alignment, fontSize: fontSize } }
                    onChange={ onChangeContent }
                    value={ content }
                />
            </Fragment>
        );
    },

    save( { attributes } ) {
        const { content, alignment, fontSize } = attributes;
        const baseClass = 'wp-block-gadam-first-block';

        return (
            <div class="container">
                <div class={ baseClass }>
                    <RichText.Content
                        style={ { textAlign: alignment, fontSize: fontSize } }
                        value={ content }
                        tagName="p"
                    />
                </div>
            </div>
        );
    },
} );

And finally, this is recipe-card.js

const { registerBlockType } = wp.blocks;
const { RichText, BlockControls, InspectorControls, AlignmentToolbar, FontSizePicker } = wp.editor;
const { Fragment } = wp.element;

registerBlockType( 'gadam/recipe-card', {
    title: 'Recipe Card',
    icon: 'index-card',
    category: 'custom-blocks',

    attributes: {
        content: {
            type: 'string',
            source: 'html',
            selector: 'p'
        },
        alignment: {
            type: 'string'
        },
        fontSize: {
            type: 'number',
            default: 18
        }
    },

    edit( { attributes, className, setAttributes } ) {
        const { content, alignment, fontSize } = attributes;
        const fontSizes = [
            {
                name: 'Small',
                slug: 'small',
                size: 14
            },
            {
                name: 'Normal',
                slug: 'normal',
                size: 18
            },
            {
                name: 'Large',
                slug: 'large',
                size: 24
            }
        ];

        function onChangeContent( newContent ) {
            setAttributes( { content: newContent } );
        }

        function onChangeAlignment( newAlignment ) {
            setAttributes( { alignment: newAlignment } );
        }

        function onChangeFontSize( newFontSize ) {
            setAttributes( { fontSize: newFontSize } );
        }

        return (
            <Fragment>
                <BlockControls>
                    <AlignmentToolbar
                        value={ alignment }
                        onChange={ onChangeAlignment }
                    />
                </BlockControls>
                <InspectorControls>
                    <AlignmentToolbar
                        value={ alignment }
                        onChange={ onChangeAlignment }
                    />
                    <FontSizePicker
                        fontSizes={ fontSizes }
                        value={ fontSize }
                        onChange={ onChangeFontSize }
                    />
                </InspectorControls>
                <RichText
                    key="editable"
                    tagName="p"
                    className={ className }
                    style={ { textAlign: alignment, fontSize: fontSize } }
                    onChange={ onChangeContent }
                    value={ content }
                />
            </Fragment>
        );
    },

    save( { attributes } ) {
        const { content, alignment, fontSize } = attributes;
        const baseClass = 'wp-block-gadam-recipe-card';

        return (
            <div class="container">
                <div class={ baseClass }>
                    <RichText.Content
                        style={ { textAlign: alignment, fontSize: fontSize } }
                        value={ content }
                        tagName="p"
                    />
                </div>
            </div>
        );
    },
} );

Solution

  • For anyone who may come across this in the future:

    Look at the top of the two js files I posted. The constants declared in one file are shared by all subsequently registered blocks. So what's happening is when I register first-block the constants are defined. When I register recipe-card it tries to define the constants at the top of the file, but they were already defined by first-block.

    The code for recipe-card.js should remove the constants that are already defined by first-block.

    registerBlockType( 'gadam/recipe-card', {
        title: 'Recipe Card',
        icon: 'index-card',
        category: 'custom-blocks',
    
        attributes: {
            content: {
                type: 'string',
                source: 'html',
                selector: 'p'
            },
            alignment: {
                type: 'string'
            },
            fontSize: {
                type: 'number',
                default: 18
            }
        },
    
        edit( { attributes, className, setAttributes } ) {
            const { content, alignment, fontSize } = attributes;
            const fontSizes = [
                {
                    name: 'Small',
                    slug: 'small',
                    size: 14
                },
                {
                    name: 'Normal',
                    slug: 'normal',
                    size: 18
                },
                {
                    name: 'Large',
                    slug: 'large',
                    size: 24
                }
            ];
    
            function onChangeContent( newContent ) {
                setAttributes( { content: newContent } );
            }
    
            function onChangeAlignment( newAlignment ) {
                setAttributes( { alignment: newAlignment } );
            }
    
            function onChangeFontSize( newFontSize ) {
                setAttributes( { fontSize: newFontSize } );
            }
    
            return (
                <Fragment>
                    <BlockControls>
                        <AlignmentToolbar
                            value={ alignment }
                            onChange={ onChangeAlignment }
                        />
                    </BlockControls>
                    <InspectorControls>
                        <AlignmentToolbar
                            value={ alignment }
                            onChange={ onChangeAlignment }
                        />
                        <FontSizePicker
                            fontSizes={ fontSizes }
                            value={ fontSize }
                            onChange={ onChangeFontSize }
                        />
                    </InspectorControls>
                    <RichText
                        key="editable"
                        tagName="p"
                        className={ className }
                        style={ { textAlign: alignment, fontSize: fontSize } }
                        onChange={ onChangeContent }
                        value={ content }
                    />
                </Fragment>
            );
        },
    
        save( { attributes } ) {
            const { content, alignment, fontSize } = attributes;
            const baseClass = 'wp-block-gadam-recipe-card';
    
            return (
                <div class="container">
                    <div class={ baseClass }>
                        <RichText.Content
                            style={ { textAlign: alignment, fontSize: fontSize } }
                            value={ content }
                            tagName="p"
                        />
                    </div>
                </div>
            );
        },
    } );