This post will walk you through how to unregister a block to successfully hide a WordPress block from the inserter depending on the template or template part of a Block Based Theme.
This post is meant for theme and plugin developers looking to dynamically control where a specific block can be added to a WordPress website. Use cases would include, wanting to hide a block from the posts and pages editor, and wanting to hide the block from a given template part or template to prevent users from being able to insert the block at all.
To get the most out of this post, check out the full github repo here.
Registering the Block only with Javascript
This section of the post focuses on changing a block created with the block.json file into a Javascript only block for easier control. We will use the @wordpress/create-block
method to create a block plugin and then we will alter our plugin files so that the block is purely made of Javascript. Finally, we’ll install all of our dev dependencies that we’ll need to be able to hide a block from the inserter.
Create Block Plugin
First we’ll open up a plugin folder in our local server’s WordPress installation. I use Local By Flywheel and using VSCode am able to open up the plugin folder of my current site. In my VSCode terminal I’ll simply run the Create Block command:
npx @wordpress/create-block testing-block
Next, in my terminal I will change directories into my block plugin:
cd testing-block
Transfer Block to purely Javascript
In my testing-block.php
plugin file, I’m going to remove the create_block_testing_block_block_init()
function and the action hook add_action( 'init', 'create_block_testing_block_block_init' );
.
Instead, we’re going to enqueue the build assets into our plugin using the wp_enqueue_scripts
and enqueue_block_editor_assets
actions.
In my testing-block.php file under the plugin comment I’ll add the following action hooks:
add_action('wp_enqueue_scripts', 'my_enqueue_assets');
add_action('enqueue_block_editor_assets', 'my_enqueue_block_assets');
Next I’ll create each function to be called by these action hooks. The first function will pull in my CSS from the build folder that is created after I run npm build in the terminal.
function my_enqueue_assets() {
$css_dir = plugin_dir_url(__FILE__) . 'build';
wp_enqueue_style('testing-block', $css_dir . '/index.css', []);
}
The second function will pull in my Javascript, CSS, and WordPress Script dependencies from the build folder. Ensure that you include all of these dependencies in the dependency array. We’ll install the remaining dependencies that don’t come bundled in Create Block next.
function my_enqueue_block_assets() {
$build_dir = plugin_dir_url(__FILE__) . 'build';
wp_enqueue_script('testing-block', $build_dir . '/index.js', [ 'lodash', 'wp-block-editor', 'wp-blocks', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-i18n' ] , null, true);
wp_enqueue_style('testing-block', $build_dir . '/index.css', [ 'wp-edit-blocks' ]);
}
Like developing WordPress Block themes? Checkout how to load and use an image with your block theme here.
Alter the index.js file to register the block using Javascript
In my index.js file inside of the src directory, I’m going to update the registerBlockType function so that it uses the same information currently stored in the block.json file.
First, I’ll remove the import metadata from './block.json'
from the top of this file. I’ll replace the first parameter of the registerBlockType functionmetadata.name
with the name of the block 'create-block/testing-block'
.
Next, I’ll just add the title, category, icon, description, textdomain, and supports properties. My registerBlockType function now looks like this:
registerBlockType( 'create-block/testing-block', {
title: 'Testing Block',
category: 'widgets',
icon: 'smiley',
description: 'Example block scaffolded with Create Block tool.',
textdomain: 'testing-block',
supports: {
inserter: false
},
edit: Edit,
save,
} )
Finally, I can go ahead and remove the block.json file altogether and run npm run build
in my terminal. I should be able to find my testing block in the inserter in the widgets category.
Installing Dependencies
We’ll install these dependencies below which we’ll need to be able to hide blocks dynamically.
- Lodash – We’ll use the debounce function from this package to prevent continuous calls to our functions.
- WordPress Blocks – We’ll be using functions from this package to manage how and when our block appears in the inserter.
- WordPress Data – We’ll use this package to create our conditionals to tell our plugin when to show our block in the inserter.
- WordPress dom-ready – We’ll use this package to call our functions once the dom has fully loaded.
Run the following commands in your project file’s terminal:
npm i --save lodash
npm install @wordpress/dom-ready --save
npm install @wordpress/data --save
npm install @wordpress/blocks --save
Choosing the conditional to hide the block with
Using a WordPress Data Module, we will be able to create a conditional to tell our plugin when to show a block in the inserter.
In this project, I will be using the core/edit-post
library to determine whether the user is on a given template or template part.
WordPress Data Store Conditional to Hide From a Template Part or Template
First, we’re going to import the domReady function from the WordPress dom-ready package.
import domReady from '@wordpress/dom-ready'
In our index.js file we’ll also import the select function from the @wordpress/data
store.
import { select } from '@wordpress/data'
We’ll add the domReady function to the index.js file under our registerBlockType function.
domReady(() => {
})
Inside the domReady function we’ll be using the getEditedPostId, which will give us the template or template part name.
This function will return as undefined when it runs on the post or page editor. This is good for our use because we are trying to hide a block from our theme’s header template part.
In this way, if the postId is not the header template part, then we’ll be unregistering the block that sets the inserter to true. I’ll get into that more below.
domReady(() => {
const getPostId = () => select('core/edit-site').getEditedPostId()
//output "theme//template" or "theme//template-part"
})
NOTE: You’ll want to know the textdomain of the theme you’re using on your WordPress installation. The textdomain will be the first part of the postId followed by 2 slashes and then the name of the template or template part.
“theme//template”
Looking for more WordPress tutorials? Learn how to use WordPress in a React Typescript project here.
Hiding the Block from the Inserter Dynamically
To hide the block from the inserter dynamically, we’ll want to wrap the registerBlockType function with another function.
We’ll be creating 2 wrapper functions, one that calls registerBlockType with the inserter property set to false, and one set to true.
Register Block Type functions
In our index.js file, we’ll wrap our registerBlockType function in a function called registerWithoutInserter()
. Then we’ll immediately call this function below:
const registerWithoutInserter = () => {
registerBlockType( 'create-block/testing-block', {
title: 'Testing Block',
category: 'widgets',
icon: 'smiley',
description: 'Example block scaffolded with Create Block tool.',
textdomain: 'testing-block',
supports: {
inserter: false
},
edit: Edit,
save,
} )
}
registerWithoutInserter()
Above this function, we’ll create a function called registerWithInserter()
. This function will not be immediately called:
const registerWithInserter = () => {
registerBlockType( 'create-block/testing-block', {
title: 'Testing Block',
category: 'widgets',
icon: 'smiley',
description: 'Example block scaffolded with Create Block tool.',
textdomain: 'testing-block',
supports: {
inserter: true
},
edit: Edit,
save,
} )
}
Using domReady, subscribe, and debounce
At the top of our index.js file, we need to import the subscribe and debounce functions.
Subscribe will ensure that our functions will run whenever the state of the WordPress Blocks changes. We need this to ensure our changes to the inserter property of the block will be apparent when we change templates and template parts in the Site Editor.
Because subscribe will run our functions multiple times, we need to utilize the debounce function to ensure our functions are only run once.
At the top of the index.js file, add the import for the debounce function and update the import from the @wordpress/data package:
import { debounce } from 'lodash'
import { select, subscribe } from '@wordpress/data'
Inside our domReady function and below the getPostId function, we’ll add the subscribe and debounce functions like so:
domReady(() => {
const getPostId = () => select('core/edit-site').getEditedPostId()
subscribe(
debounce(() => {
}, 200)
)
})
The debounce function must be called directly within the subscribe function or else it won’t work. The 200 parameter of the debounce function is the amount of time in milliseconds the debounce function will wait to run its functions.
Find out if the block supports the inserter or not
We’re going to need to find out if the block we’ll be unregistering has the inserter property set to true or false. This will help load the correct block.
At the top of our file, we’ll update our import statement for the @wordpress/blocks like so:
import { registerBlockType, getBlockSupport } from '@wordpress/blocks'
Next, inside of the domReady function, we’ll create a function that will check if a given block supports the inserter or not:
domReady(() => {
const getPostId = () => select('core/edit-site').getEditedPostId()
// the new code to add:
const supportsInserter = (block) => getBlockSupport(block, 'inserter')
// before the subscribe function
subscribe(
Our final step will be importing the unregisterBlockType function from the @wordpress/blocks package.
import { registerBlockType, unregisterBlockType, getBlockSupport } from '@wordpress/blocks'
Example: Successfully Hiding a Block from a template part
In the following example, I am going to unregister the block type ‘create-block/testing-block’, then register the block that supports the inserter.
This will run when the template part is the header. The postId is my-theme//header and I’m checking to ensure the block that is going to be unregistered is the block that doesn’t support the inserter.
Inside the debounce function, I’ll start by defining postId as the function we wrote earlier that exists in the domReady scope.
debounce(() => {
const postId = getPostId()
}, 200)
Next, I’m checking that the postId is the header template part, and that the block doesn’t support the inserter. Within this condition I’m unregistering the block type and re-registering it with the function that has the inserter set to true:
if (postId === 'my-theme//header' &&
!supportsInserter('create-block/testing-block')) {
unregisterBlockType('create-block/testing-block')
registerWitInserter()
}
Now, I want to ensure that I cannot insert this block after visiting the header template part and then visiting another template part or template. My next conditional is the opposite of the one above:
if (postId !== 'my-theme//header' &&
supportsInserter('create-block/testing-block')) {
unregisterBlockType('create-block/testing-block')
registerWithoutInserter()
}
Example: Successfully Hiding a Block from a template
Let’s say we want to hide our block from the home template. We’ll write out our functions like so:
if (postId === 'my-theme//home' &&
!supportsInserter('create-block/testing-block')) {
unregisterBlockType('create-block/testing-block')
registerWitInserter()
}
if (postId !== 'my-theme//home' &&
supportsInserter('create-block/testing-block')) {
unregisterBlockType('create-block/testing-block')
registerWithoutInserter()
}
Once again, don’t be afraid to check out the plugin code in its entirety here.
Hopefully now you’ve found enough information here to get your blocks hidden from the inserter in a way that works for your project. Thanks for stopping by!
Photo by Annie Spratt on Unsplash