plugin development – Updating parent block attributes from child block?
I can’t seem to find an answer to this that I can understand
I have tabs and a tab block, which is a clone of this basic tab block plugin. I’m trying to add the ability to select an “icon” for each tab block.
I’m close. Using the MediaUpload component, I’m able to see the file I’ve selected under the activeTab
object, but it doesn’t update the parent block attribute, so I can’t reference the icon_url
attribute.
tab/edit.js
const Edit = ({ attributes, setAttributes, clientId }) => {
const { uid, activeTab } = attributes;
useEffect(() => {
if (!uid) {
setAttributes({ uid: clientId });
}
}, []);
const display = activeTab === uid ? "block" : "none";
const ALLOWED_MEDIA_TYPES = ["image", "svg"];
const setTabIcon = (icon_url) => {
const parentBlock = select("core/block-editor").getBlock(clientId);
dispatch("core/block-editor").updateBlockAttributes(
parentBlock.clientId,
{
...attributes,
icon_url,
}
);
};
return (
<div {...useBlockProps()}>
<InspectorControls>
<div>
<MediaUpload
allowedTypes={ALLOWED_MEDIA_TYPES}
onSelect={(media) => setTabIcon(media.url)}
render={({ open }) => (
<button onClick={open}>Open Media Library</button>
)}
/>
</div>
</InspectorControls>
<div className={"guten-tab-panel"} style={{ display }}>
<InnerBlocks
allowedBlocks={["core/heading", "core/paragraph"]}
renderAppender={() => <InnerBlocks.ButtonBlockAppender />}
/>
</div>
</div>
);
};
export default Edit;
In tabs.js, I’m trying to reference tab.icon_url. icon_url doesn’t exist, only uid
and title
tabs/tabs.js
const Edit = ({ attributes, setAttributes, clientId }) => {
const { tabs, activeTab } = attributes;
const blockProps = useBlockProps({
className: `${useBlockProps().className} guten-tab-wrapper`,
});
const setActiveTab = (uid) => {
setAttributes({ activeTab: uid });
const parentBlock = select("core/block-editor").getBlock(clientId);
parentBlock.innerBlocks.forEach((innerBlock) => {
dispatch("core/block-editor").updateBlockAttributes(
innerBlock.clientId,
{
activeTab: uid,
}
);
});
};
const addNewTab = () => {
const tab = createBlock("ahsan03/tab");
const position = tabs.length;
dispatch("core/block-editor").insertBlock(tab, position, clientId);
setAttributes({
tabs: [
...tabs,
{
uid: tab.clientId,
title: `Tab ${tabs.length + 1}`,
icon_url: "",
},
],
});
setActiveTab(tab.clientId);
};
const tabTitleChange = (newValue) => {
setAttributes({
tabs: [
...tabs.map((tab) => {
return tab.uid === activeTab
? {
...tab,
title: newValue,
}
: tab;
}),
],
});
};
useEffect(() => {
if (tabs.length && !activeTab) {
setActiveTab(tabs[0].uid);
}
}, [tabs]);
return (
<>
<div {...blockProps}>
<div className={"guten-tabs-nav"}>
{tabs.map((tab) => {
return (
<div
key={tab.uid}
className={"guten-tab-item"}
role="tab"
tabIndex="0"
onClick={() => setActiveTab(tab.uid)}
>
<div
className={`guten-tab-link${
tab.uid === activeTab
? " is-active"
: ""
}`}
>
<img src={tab.icon_url} alt="" />
{console.log("tabs tab", {
tab,
})}
<RichText
tagName="div"
value={tab.title}
onChange={tabTitleChange}
/>
</div>
</div>
);
})}
<Button
variant={"primary"}
icon={"plus"}
onClick={addNewTab}
>
{__("", "gtt")}
</Button>
</div>
<div className={"guten-tab-content"}>
<InnerBlocks
allowedBlocks={["ahsan03/tab"]}
renderAppender={false}
/>
</div>
</div>
</>
);
};
export default Edit;
How can I fix this so uploading an image is in the parent block attributes?
Here’s an updated setTabIcon function that I think is closer to what I need, I’m just not sure what to do after fetching the parentBlock.
const setTabIcon = (icon_url) => {
const parentBlockIds =
select("core/block-editor").getBlockParents(clientId);
parentBlockIds.forEach((parentBlockId) => {
const parentBlock = select("core/block-editor").getBlock(parentBlockId);
console.log({ parentBlock });
});
};
Leave an answer