I've created a custom block that uses a WordPress core block as an innerBlock child; more specifically the core/embed block. What I'd like to do is listen for changes in the child block's attributes, so that I can respond to them in the parent block.
The custom block edit function returns the following:
return (
<div { ...useBlockProps() } onChange={parentUpdate}>
<InnerBlocks
allowedBlocks={['core/embed']}
template={EMBED_TEMPLATE}
templateLock="all"
></InnerBlocks>
</div>
);
And the parentUpdate
function currently looks like:
const parentUpdate = () => {
const thisBlock = select('core/editor').getBlocksByClientId(clientId)[0]
const childBlock = thisBlock.innerBlocks[0]
const videoURL = childBlock.attributes?.url
console.log(videoURL)
}
The parentUpdate
function fires whenever the url attribute in the child embed block changes but (perhaps unsurprisingly) it fires before the child event block updates, meaning I get the value prior to the change, not after.
How should I be approaching this, so that I can use the child attributes after the child block updates?
I've created a custom block that uses a WordPress core block as an innerBlock child; more specifically the core/embed block. What I'd like to do is listen for changes in the child block's attributes, so that I can respond to them in the parent block.
The custom block edit function returns the following:
return (
<div { ...useBlockProps() } onChange={parentUpdate}>
<InnerBlocks
allowedBlocks={['core/embed']}
template={EMBED_TEMPLATE}
templateLock="all"
></InnerBlocks>
</div>
);
And the parentUpdate
function currently looks like:
const parentUpdate = () => {
const thisBlock = select('core/editor').getBlocksByClientId(clientId)[0]
const childBlock = thisBlock.innerBlocks[0]
const videoURL = childBlock.attributes?.url
console.log(videoURL)
}
The parentUpdate
function fires whenever the url attribute in the child embed block changes but (perhaps unsurprisingly) it fires before the child event block updates, meaning I get the value prior to the change, not after.
How should I be approaching this, so that I can use the child attributes after the child block updates?
Share Improve this question edited Jan 26, 2022 at 10:56 verism asked Jan 26, 2022 at 10:09 verismverism 2161 silver badge15 bronze badges 7 | Show 2 more comments1 Answer
Reset to default 2You wouldn't, the need to do this is normally a code smell and a warning sign that you have done something wrong, or are trying to work against react and the way blocks are intended to work in some way.
However if you wanted to continue down the path in the wrong direction, you would rely on useSelect
to acquire the information you wanted, directly accessing select
isn't great and it also means you no longer get changes in your component.
But as I said, and as revealed in your comment, this is all a big hack to work around wanting to show embeds in a block, resulting in putting embed blocks in the inner blocks as children, forcing you to then implement this as a hack to get the information you need, an X Y problem. Don't do that.
Blocks should not depend on other blocks like this, they need to be composable like actual lego bricks. It's ok if two bricks were designed to work together, e.g. column and columns blocks, but it's not a good idea to repurpose a block for editor UI purposes like that.
Instead, read the edit component of the core/embed
block at:
https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/embed/edit.js
It shows:
- how to get a preview code and render it
- handling loading spinners for when it's fetching the embed code
- URL input for video links
- sandboxes
- embeddable vs unembeddable items
With these the URL would just become another prop on your block.
It may even be possible to instead adjust the embed block itself with additional attributes and components via filters to extend it if the goal of your task is to provide a modified UI for an embed. However the details of what your work is intended to implement are scarce.
onChange
isn't a block related event, it's a DOM node related event, I do not believe you can do this via props and attributes in the component as that's not how block data works,<InnerBlocks>
is not the source of data for inner blocks, it's just the mechanism by which they're displayed, it gets that data from elsewhere. What are you trying to implement that requires this? What is your block supposed to do? There's no context provided here so it's difficult to advise on the appropriate actions to take – Tom J Nowell ♦ Commented Jan 26, 2022 at 10:45useSelect
considered. I would also say that all the things you would apply this to actually have very different solutions and this is the optimal solution for none of them – Tom J Nowell ♦ Commented Jan 26, 2022 at 13:36