Question

I have built two blocks for displaying a list of feature cards.

Block 1: Feature Cards (the container element)

(function (blocks, element, blockEditor) {
    var el = element.createElement;
    var InnerBlocks = blockEditor.InnerBlocks;

    blocks.registerBlockType('feature-cards', {
        title: 'Feature Cards',
        icon: 'universal-access-alt',
        category: 'layout',
        example: {},
        edit: function (props) {
            return el('div', { className: 'feature-cards' },
                    el(InnerBlocks)
            );
        },
        save: function (props) {
            return el('div', { className: 'feature-cards' },
                    el(InnerBlocks.Content)
            );
        },
    });
})(window.wp.blocks, window.wp.element, window.wp.blockEditor);

Block 2: Feature Card (the card itself with editable content)

(function (blocks, editor, element, blockEditor) {
    var el = element.createElement;
    var RichText = editor.RichText;
    var InnerBlocks = blockEditor.InnerBlocks;

    blocks.registerBlockType('feature-card', {
        parent: ['feature-cards'],
        title: 'Feature Card',
        icon: 'universal-access-alt',
        category: 'layout',
        example: {},
        attributes: {
            content: {
                type: 'array',
                source: 'children',
                selector: 'h3',
            },
        },
        edit: function (props) {
            var content = props.attributes.content;
            function onChangeContent( newContent ) {
                props.setAttributes( { content: newContent } );
            }
            
            return el('div', { className: 'feature-card' },
                        el('div', { className: 'feature-card__icon' }, el(InnerBlocks)),
                        el( RichText, {
                            tagName: 'h3',
                            className: 'feature-card__title',
                            onChange: onChangeContent,
                            value: content,
                        } )
                );
        },
        save: function (props) {
            return el('div', { className: 'feature-card' },
                        el('div', { className: 'feature-card__icon' }, el(InnerBlocks.Content)),
                        el( RichText.Content, {
                            tagName: 'h3',
                            className: 'feature-card__title',
                            value: props.attributes.content,
                        } )
                );
        },
    });
})(window.wp.blocks, window.wp.editor, window.wp.element, window.wp.blockEditor);

As you can see I have specified that the feature-cards are the parent for the feature-card so that the card blocks can only be used inside the parent block.

However there's a couple of issues that I'm not sure how best to resolve:

First I want to make it so that the ONLY block that can be added as a child block of the feature-cards is the child block. How can I enforce this? As the parent block displays a grid with the expectation of the cards (so other blocks don't work inside here).

Second as stated above the parent block displays a grid... but when inside the editor it seems WordPress adds some wrapper elements like:

enter image description here

Which causes the grid to break when viewing the block inside the editor because it applies the grid CSS to the wrapper... is there anyway around this so that it displays correctly?

Edit: I've been looking at the Social Icons block that's included in the WordPress core to see how they get around this issue and it seems that they don't apply the CSS in the editor-side for that block as they use flexbox to align them but that's only seen on the front-end.

Was it helpful?

Solution

I'm not sure about the second one (removing the wrappers), but as for limiting the allowed blocks:

First I want to make it so that the ONLY block that can be added as a child block of the feature-cards is the child block. How can I enforce this?

You can use the allowedBlocks property of InnerBlocks like so:

// In the edit() function of the feature-cards block type:
el( InnerBlocks, { allowedBlocks: [ 'feature-card' ] } )

And you should know that wp.editor.RichText is deprecated, so use wp.blockEditor.RichText instead. So in your feature-card block type, you'd use var RichText = blockEditor.RichText; and not var RichText = editor.RichText;.

Also, you might also want to use useBlockProps in your code. :)

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top