Extending WordPress Blocks with JavaScript (and PHP) Block Filter Hooks – Tutorial with Video
One of the cool features that WordPress offers developers is the ability to hook into types of blocks and modify them with filters.
Block Filters are a set of JavaScript and PHP hooks in WordPress we can use to modify existing block properties.
This is possible due to a JavaScript hooks system included with WordPress that includes block filters along with several other types of filters available via JavaScript. In this tutorial we will look at how to work with these filters to modify blocks with both JavaScript and PHP.
This tutorial is an excerpt from my Advanced Gutenberg Development Course that goes in depth into how to extend blocks with JS Filters.
Watch the Video
Like to watch videos? Read no further 🙂
You can also find a repo with some filter examples from the course.
Extend Blocks with wp.hooks.addFilter()
The primary JavaScript function we use to hook into blocks for extending them is wp.hooks.addFilter.
addFilter() comes from the WordPress Hooks library that is very similar to the PHP Hooks library in WordPress.
You can checkout the talk below from one of the library creators, Adam Silverstein, if you want to learn more about the Hooks library and what it can do.
Make wp-hooks a Dependency When Registering Your JavaScript
To use addFilter()
, make sure that you have wp-hooks
as a dependency when you register your JavaScript.
// Register the bundled block JS file
wp_register_script(
'jsforwp-adv-gb-editor-js',
_get_plugin_url() . $editor_js_path,
['wp-element', 'wp-i18n', 'wp-editor', 'wp-hooks'],
filemtime( _get_plugin_directory() . $editor_js_path ),
true
);
Calling addFilter() in Our JavaScript
Then, in our JavaScript, we can call addFilter()
like this:
const { addFilter } = wp.hooks;
addFilter(
"filter.toHookInto",
"custom/filter-name",
customFilterFunction
);
Notice that addFilter
comes with three parameters:
- The filter to hook into
- A unique name for our specific filter
- A custom callback function that does the filtering
Below is what a real world example of what addFilter()
would look like. This particular example hooks into the registerBlockType filter:
const { addFilter } = wp.hooks;
addFilter(
"blocks.registerBlockType",
"jsforwpadvgb/extend-p-block",
extendParagraphBlock
);
Our custom callback function will look different depending on what filter we are hooking into, but here is what a callback function would look like that modify the name of the paragraph block.
function extendParagraphBlock( settings, name ) {
if( "core/paragraph" === name ) {
settings.title = __( "NEW Paragraph", "jsforwpadvgb" );
}
return settings;
}
You can see here, just like PHP filters, we always need to return something from our filters (even if we don’t change anything)!
What Block Filters Do We Have?
At this time we have a number of helpful block filters. You can always check the documentation for a current listing of all block filters.
blocks.registerBlockType
IMO one of the most important filters to learn about first is the one we saw in the example above: blocks.registerBlockType
This filter let’s us hook into and override any of the original settings passed to a block. This includes pretty much any default configuration you would want to change for a block, from it’s title and keywords to it’s attribute and edit and save settings.
Here is a quick example though of how you could use the registerBlockSettings filter to change a few things in the Core Code Block:
const { __ } = wp.i18n;
const { addFilter } = wp.hooks;
addFilter(
"blocks.registerBlockType",
"jsforwp-advgb/extending-register-block-type",
extendWithRegisterBlockType
);
function extendWithRegisterBlockType(settings, name) {
// Check for block type
if ("core/code" === name) {
// Change the block title
settings.title = __("Code Snippet", "jsforwpadvblocks");
// Change the block description
settings.description = __(
"Use for maximum codiness 💃",
"jsforwpadvblocks"
);
// Change block icon
settings.icon = "admin-tools";
// Change supports
settings.supports = lodash.merge( {}, settings.supports, {
html: true,
anchor: true
});
}
return settings;
}
Here is an important thing to remember about filters:
Filters run on ALL blocks, so 99% of the time you want to include a conditional check in your filter callback functions
So, once we check that we have the code block, we can modify the title, description, icon, supports, and more if we wanted to.
A note that this particular example uses loadash, so you would want to make sure that you have lodash
included as a dependency when you register or enqueue your JS.
More Block Filters
Here is a list of some of the other block filters that I like:
- blocks.getSaveElement – Hooks into the save element
- blocks.getSaveContent.extraProps – Let’s us add attributes to the save element
- blocks.getBlockDefaultClassName – So we can override or add to the default class assigned to block markup on the frontend
- blocks.getBlockAttributes – To work with a block’s attributes
- blocks.unregisterBlockType – For removing blocks from appearing in the editor
There are more, and of course check the documentation, to see what might get added in the future.
In my Advanced Gutenberg Development Course I go into depth on how to work with many of the filters mentioned here.
Here is a quick example of how you could extend the classes assigned to the Core Cover Block (note it uses the classnames library):
const { addFilter } = wp.hooks;
import classnames from "classnames";
addFilter(
"blocks.getBlockDefaultClassName",
"jsforwpadvgb/custom-cover-block-class-name",
customCoverClassName
);
function customCoverClassName( className, name ) {
if ( "core/cover" === name ) {
// This will OVERRIDE the class
// return "my-block-cover";
// This will ADD a class
return classnames( className, "my-block-cover" );
}
return className;
}
Hopefully the above makes sense.
- We call
addFilter()
- We create a callback function
customCoverClassName()
- It gives us two pieces of data to use:
className
and thename
of the block - We do a conditional check for the cover block
- Then
return "my-block-cover";
would replace the normal class used - Or
return classnames( className, "my-block-cover" );
will add your own custom class to the block (usually what you want)
Remember, any filter we hook into, needs us to return back what it is we are modifying (even if we don’t modify anything).
A Note on Save Filters and When to Use PHP Filters
It is important to know that when you modify the save setting for a block and you already have posts or pages with those blocks in use, modifying the save setting with JavaScript filters will break your existing blocks.
This happens because the database has your block saved as one thing. Then the editor sees your new save setting and it doesn’t know what to do. This will result in a message to the user that something is wrong with their block and it will want to convert the block to an HTML block with the content from the database.
PHP render_block Filter
To avoid this, we can use the PHP render_block
filter. Filtering the block with PHP will cause the effect to take place when the block is rendered to the frontend and therefor does not interfere with the editor.
Here is an example of what it would look like to use PHP to filter the save setting for a block to wrap the block in extra markup:
add_filter( 'render_block', 'my_wrap_quote_block_fitler', 10, 3);
function my_wrap_quote_block_fitler( $block_content, $block ) {
if( "core/quote" !== $block['blockName'] ) {
return $block_content;
}
$output = '<div class="MYCONTAINER">';
$output .= $block_content;
$output .= '</div>';
return $output;
}
This works very similarly to the JS filter:
- We hook into
render_block
- Our callback function does a conditional check to make sure we only change the block we want (this takes a fail early approach)
- We wrap the save element in our custom markup
- We return the new block content
Although the save filters are cool in JavaScript, and I love doing more WordPress development in JavaScript, I do think it is smarter to use PHP filters when extending the save setting for blocks.
Dig Deeper into Extending Blocks and Working with Fitlers
If you would like to learn more about all of this, I suggest checking out my Advanced Gutenberg Course. Or if this was a bit over your head, you might want to start of with my basic WordPress Block Development Course 🙂
Hope you enjoyed this article! Please reach out with questions and suggestions on how you are extending blocks in WordPress!
Thanks for sharing this tutorial. Can you also please guide me how can I create a block template? I am doing the same using this resource https://wpitech.com/create-wordpress-gutenberg-block-templates/ but it’s giving an error and I am having some programming lines in front end. This is the code
add_action( ‘init’, function() {
$args = array(
‘public’ => true,
‘label’ => ‘News’,
‘show_in_rest’ => true,
‘template_lock’ => ‘all’,
‘template’ => array(
array( ‘core/paragraph’, array(
‘placeholder’ => ‘Breaking News’,
This is a little different than this article, but something I cover in depth in my Theming with Gutenberg Course!
You have a mistake in the manual:
add_filter( ‘render_block’, ‘my_wrap_quote_block_fitler’, 10, 3);
typo – 10, 2);
this filter contain two arguments
Nice article, thanks! Any idea if there is a way to filter the options/attributes on the default blocks?
Example I would like to get rid of pixel selection in spacer block. Do you know if that is possible to achieve?