1

I've been writing various custom blocks, but have run into a small issue: I'd like to be able to directly reference a custom child block inside a custom parent block. The problem is I already have an InnerBlocks component in the parent.

The child block works fine in a standalone context — its purpose being to fetch data from a third party API on certain events. The index.js is pretty standard:

import edit from './edit';
import save from './save';
import metadata from './block.json';

registerBlockType( metadata.name, {
    /**
     * @see ./edit.js
     */
    edit,

    /**
     * @see ./save.js
     */
    save,
} );

The parent block is currently just a thin wrapper around the core/embed block with some extra content appended within its save method. When the core/embed updates, however, an event is triggered that I'd like to pass on to the custom child block.

The parent block currently makes use of the InnerBlocks component

return (
    <div { ...useBlockProps({ className: customClass }) }>
        <InnerBlocks
            allowedBlocks={['core/embed']}
            template={EMBED_TEMPLATE}
            templateLock="all"
            __experimentalLayout={defaultLayout}
        ></InnerBlocks>

        /* And then ideally... */
        <ChildBlock propsAndListeners/>
    </div>
)

To be clear: the parent/child blocks are not for public use, they're solely for use at a specific company, complete with their own branding etc, so reuse is not really a priority at this time. The aim is to hand over a gutenberg site builder with custom blocks specific to their needs.

I assumed that I could export the child block from its index.js, but haven't had any luck with this. How do I go about exporting this so I can simply import ChildBlock from '../path in another file, in much the same way I can reference core blocks?

9
  • what do your blocks do and why do you need to do this? What you're describing doesn't fully make sense, but you're describing things in a super generic way that makes it very difficult to answer the question. On top of that, what you've described sounds heavily like a misunderstanding of how blocks work or how they're meant to be used that probably has a trivial solution that's unrelated to what you've asked about, or maybe not, it's very hard to tell. Use the edit link to add context and examples so that your question is easier to understand.
    – Tom J Nowell
    Feb 18, 2022 at 18:15
  • I've added some extra info, I hope it shines a little extra light on things.
    – verism
    Feb 18, 2022 at 18:46
  • hmm you actually just want to reuse the child block as a user interface component, I've seen this in the past where somebody has tried to use innerblocks to insert a child that provides a pre-chosen image. I'll tell you what I told them, that this is not how blocks work, blocks are not react components or UI components to be reused inside other blocks. If these were HTML tags then it wouldn't make sense logically, blocks are the same. Instead you should use the filters in JS that the editor provides. There's a filter that you can use to add extra attributes, and a filter for the edit component
    – Tom J Nowell
    Feb 18, 2022 at 19:02
  • this way you can modify the core embed block to include the additional attributes and user interface react components you want without introducing new blocks. The approach you've attempted to take here is a dead end, and not how you are meant to build blocks, be that trying to use a block as a react component in another block, or trying to use a block as a container for an embed block with a locked template so that you can manipulate its user interface
    – Tom J Nowell
    Feb 18, 2022 at 19:03
  • OK, I think that makes sense regarding the embed block - I'll look into filters. So would you recommend putting all the custom functionality into a single block that extends/filters the embed block?
    – verism
    Feb 18, 2022 at 19:48

1 Answer 1

1

You cannot embed blocks as react components this way, and you should not try to use other blocks as user interface components by setting innerblocks with a locked template.

Instead, use 2 filters to modify the core/embed block:

  • Use editor.BlockListBlock on core/embed to modify the edit component, wrapping it in your own component that has extra user interface react components
  • Use the blocks.registerBlockType filter to modify the core/embed registration to include your additional attributes
  • Use PHP to adjust how the core/embed block is rendered using filters

This way you can use the standard core embed block and no longer need to register new blocks.

For example this adds a button to the toolbar of every block:

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

addFilter(
    'editor.BlockListBlock',
    'verism/toolbar-button',
    AddToolbarButton,
    10
);
const AddToolbarButton = createHigherOrderComponent( BlockEdit => {
    return ( props ) => {
        if ( props.name != 'core/embed' ) {
            return <BlockEdit { ...props } />;
        }
        return (
            <Fragment>
                <BlockControls>
                    <ToolbarGroup>
                        <ToolbarButton
                            className="verisms-really-nice-button"
                            label="Verisms really nice button"
                            onClick={ () => {
                                console.log( 'button pressed' );
                            } }
                        />
                    </ToolbarGroup>
                </BlockControls>
                <BlockEdit { ...props } />
            </Fragment>
        );
    };
}, 'AddToolbarButton' );

https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#editor-blockedit

You could insert sidebar panels, textfields, toolbar buttons etc.

You could also filter the attributes in PHP via the block_type_metadata filter:

https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#block_type_metadata

2
  • This is very helpful indeed, thanks for the in depth answer. Just one thing, what if I wanted to also be able to use the core/embed block in addition to the filtered version?
    – verism
    Feb 18, 2022 at 21:53
  • No, there is no difference between the two, why would there be? It sounds like there is context and purpose that is essential to your question that you've not shared/hidden. However, think of it this way, just because your car has a feature does not mean you have to use it, and just because Windows has a settings panel for backups, does not mean all those settings are available if you've turned backups off. Otherwise, you're going to have to share what you actually wanted to do, not the super generic version. Making it generic didn't help you, it hurt you.
    – Tom J Nowell
    Feb 19, 2022 at 1:14

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.