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 πŸ™‚

Free video explaining most of this article

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:

  1. The filter to hook into
  2. A unique name for our specific filter
  3. 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 the name 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.

Filtering Saved 
Block Content
May/Will Break 
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!