最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I import one custom block into another?

programmeradmin3浏览0评论

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?

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?

Share Improve this question edited Feb 18, 2022 at 18:44 verism asked Feb 18, 2022 at 17:58 verismverism 2161 silver badge15 bronze badges 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 Commented Feb 18, 2022 at 18:15
  • I've added some extra info, I hope it shines a little extra light on things. – verism Commented 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 Commented 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 Commented 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 Commented Feb 18, 2022 at 19:48
 |  Show 4 more comments

1 Answer 1

Reset to default 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

发布评论

评论列表(0)

  1. 暂无评论