So far we’ve built our own block. This tutorial shows how to extend other people’s blocks — particularly core blocks — using WordPress’s JS hook system. This is how block-toolbar plugins, format-bar additions, and custom inserter filters work.
The hook system
@wordpress/hooks is the JS equivalent of WP’s PHP hook system. Two flavors:
addFilter()— modify a value passing throughaddAction()— react to something happening
The hooks fire at well-defined points in the block lifecycle. Pick the right one for the modification you want.
Hook 1: blocks.registerBlockType — modify block settings
Fired when WordPress registers a block. Modify the settings object to add attributes, change icons, alter supports:
import { addFilter } from '@wordpress/hooks';
addFilter(
'blocks.registerBlockType',
'my-first-block/add-lock-attribute',
(settings, name) => {
if (name !== 'core/paragraph') return settings;
return {
...settings,
attributes: {
...settings.attributes,
isLocked: { type: 'boolean', default: false },
},
};
}
);
Now every paragraph has an isLocked attribute. Setting and using it is the next step.
Hook 2: editor.BlockEdit — wrap the edit component
Wrap a block’s Edit component with a higher-order component to add inspector controls, toolbar buttons, or wrappers:
import { addFilter } from '@wordpress/hooks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody, ToggleControl } from '@wordpress/components';
const withLockToggle = createHigherOrderComponent((BlockEdit) => {
return (props) => {
if (props.name !== 'core/paragraph') return <BlockEdit {...props} />;
return (
<>
<BlockEdit {...props} />
<InspectorControls>
<PanelBody title="Custom" initialOpen={false}>
<ToggleControl
label="Locked"
checked={props.attributes.isLocked}
onChange={(value) => props.setAttributes({ isLocked: value })}
/>
</PanelBody>
</InspectorControls>
</>
);
};
}, 'withLockToggle');
addFilter('editor.BlockEdit', 'my-first-block/with-lock-toggle', withLockToggle);
Now every paragraph has a “Custom” inspector panel with a “Locked” toggle.
Hook 3: blocks.getSaveContent.extraProps — modify saved markup
Add HTML attributes to the saved output without rewriting Save:
addFilter(
'blocks.getSaveContent.extraProps',
'my-first-block/locked-class',
(props, blockType, attributes) => {
if (blockType.name !== 'core/paragraph') return props;
if (!attributes.isLocked) return props;
return {
...props,
className: `${props.className || ''} is-locked`,
'data-locked': 'true',
};
}
);
Now paragraphs with isLocked: true get class="is-locked" and data-locked="true" in the saved HTML.
SlotFill — adding to existing slots
Some Gutenberg UI areas (the document sidebar, the publish flow) are SlotFill points. Plugins can add their own panels:
import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel } from '@wordpress/editor';
import { TextControl } from '@wordpress/components';
const MyDocumentPanel = () => (
<PluginDocumentSettingPanel
name="my-plugin-panel"
title="My Plugin Settings"
icon="admin-plugins"
>
<TextControl label="External tracking ID" value="" onChange={() => {}} />
</PluginDocumentSettingPanel>
);
registerPlugin('my-first-block-document-panel', { render: MyDocumentPanel });
This adds a custom panel to the document sidebar in any post-edit screen.
When to extend vs fork
| Situation | Approach |
|---|---|
| Add a small option to a core block | Filter (this tutorial) |
| Need a totally different look | Build your own custom block |
| Change behavior for ALL blocks | Filter editor.BlockEdit with no type check |
| Replace a core block entirely | Use the block-deregister + replace pattern |
What’s next
Part 10 packages everything into a polished plugin — proper file structure, asset enqueuing, server-side render callbacks, plugin metadata.
Get the next one in your inbox. Practical tips, no fluff.
More tutorials
View all-
Block Patterns
Register reusable block compositions — landing-page hero, feature grid, FAQ section — that users insert as a complete unit.
25 min
-
Block Attributes and Serialization
Master the attribute system — types, sources, defaults, and how block data round-trips between the editor, the database, and the front-end.
30 min
-
Building a Block Plugin
Package your block as a proper WordPress plugin — file structure, asset enqueueing, server-side render callbacks, plugin metadata.
35 min