Creating Custom Gutenberg Blocks for WordPress
Create a plugin to house the code for the custom Gutenberg blocks
To create a new plugin, create a directory for it: in the wp-content/plugins
directory, create a new directory for the plugin e.g. my-custom-blocks
. As a convention, this name should be snake case and will be referenced throughout as a namespace for the blocks.
Within that directory, make a new file by the same name e.g. my-custom-blocks.php
.
Add to that a minimum of the following:
<?php
/*
Plugin Name: My Custom Blocks
Description: This plugin adds my custom blocks.
Author: First Last
*/
Create a custom Gutenberg block
Dynamic Blocks
Dynamic blocks are useful if you want to add a block that outputs the contents of ACF fields or some arbitrary PHP code. Dynamic blocks require editing a render.php
file for output on the frontend and editing the edit.js
file to define any output within the WP Admin.
To create a standard block, in the following code example, avoid the --variant="dynamic"
flag.
Running the Scaffolding Script
Navigate to the plugin directory and use the WP Scaffold to create the custom block. In a shell, where my-custom-block
is the name of the block and you want it to be of the dynamic type:
cd wp-content/plugins/my-custom-blocks/
npx @wordpress/create-block@latest --variant="dynamic" my-custom-block
Modifying the Structure to Allow for Multiple Custom Blocks within a Single Plugin
The scaffolding script creates a directory at the same level as my-custom-blocks/src
.
Change directory into wp-content/plugins/my-custom-blocks/my-custom-block
and delete everything but the src
directory within it.
cd my-custom-block
find . -maxdepth 1 -not -name 'src' -not -name '.' -exec rm -rf {} +
Move the files from the src
directory to the top level of the directory so they are immediate descendents of wp-content/plugins/my-custom-blocks/my-custom-block/
:
mv src/my-custom-block/* ./
Delete wp-content/plugins/my-custom-blocks/my-custom-block/src
:
rm -rf src
Move the new directory into a src/
directory at the root of the plugin so the path to the custom block is now something like wp-content/plugins/my-custom-blocks/src/my-custom-block
:
cd ..
mkdir src
mv my-custom-block src/
Register the block in wp-content/plugins/my-custom-blocks/my-custom-blocks.php
. Edit that file to include:
function my_custom_blocks_init(): void {
register_block_type(__DIR__ . '/build/my-custom-block');
}
add_action('init', 'my_custom_blocks_init');
Add a package.json
file. This replaces the package.json
file we deleted from my-custom-block
after creating it with the scaffolding. As a direct descendant of my-custom-blocks/
, create the package.json
file. Add to it:
{
"name": "my-custom-blocks",
"version": "0.1.0",
"description": "My Custom Blocks",
"author": "First Last",
"license": "GPL-2.0-or-later",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build --webpack-src-dir=src --output-path=build",
"start": "wp-scripts start --webpack-src-dir=src --output-path=build",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"packages-update": "wp-scripts packages-update",
"plugin-zip": "wp-scripts plugin-zip",
"test:unit": "wp-scripts test-unit-js"
},
"devDependencies": {
"@wordpress/scripts": "^29.0.0"
}
}
Edit the src/my-custom-block/block.json
file:
- Replace
create-block
withmy-custom-blocks
in thename
. - Specify a new icon. The icon can be chosen from the WordPress Dashicons Resource page.
- Revise the
description
to accurately describe the purpose of the block.
Nesting Blocks Inside of Other Blocks
To create a block that allows children, a common pattern for setting up a specific grid or flex layout or card structure, in the edit.js
file of the parent block, in the returned component, add, where we are allowing only the my-custom-blocks/my-custom-block
card to be added and we have included a first card in the template:
<InnerBlocks
template={[["my-custom-blocks/my-custom-block"]]}
allowedBlocks={["my-custom-blocks/my-custom-block"]}
/>
Modify the block.json
file as well to indicate that the block supports inner blocks and which blocks to allow:
{
...
"supports": {
"innerBlocks": true
},
"allowedBlocks": [
"core/paragraph",
"core/spacer",
"my-custom-blocks/my-custom-block"
],
...
}
To allow any child blocks, the edit.js
file simply needs to return the InnerBlocks
component:
import { InnerBlocks, useBlockProps } from "@wordpress/block-editor";
import "./editor.scss";
export default function Edit() {
return (
<InnerBlocks />
);
}
Modify the block.json
file as well to indicate that the block supports inner blocks and omit defining allowedBlocks
which will allow all blocks by default:
{
...
"supports": {
"innerBlocks": true
},
...
}
The save.js
file in either case returns the content of the inner blocks:
import { InnerBlocks, useBlockProps } from "@wordpress/block-editor";
export default function save() {
return (
<InnerBlocks.Content />
);
}
Restricting a Block to Be a Child of a Certain Other Type of Block
To limit a block so it can only be used in a parent block, in the block.json
file of the child block, add a key for parent
and set the value to an array of parent blocks (in this example my-custom-blocks/my-custom-block-wrapper
), e.g.:
"parent": ["my-custom-blocks/my-custom-block-wrapper"],
Building
The wp-content/plugins/my-custom-blocks/package.json
file lists the scripts available. During development, start
will compile the blocks on demand while build
will do a one-time build. To run the scripts, from the wp-content/plugins/my-custom-blocks/
directory, run:
npm run start
or
npm run build
Adding a Combination of Blocks to the Plugin as a Pattern
Often when theming a website with Gutenberg custom blocks, a combination of blocks will be used to create an effect. Collecting the group as a pattern provides a useful way for content creators to find and add them.
To do this, assemble the combination of Gutenberg blocks on a new post. Select the whole combination of blocks and right-click to create a new pattern. You probably don't want it to be global unless the blocks are all dynamic. With global patterns, a change to one use affects all the others. Save the combination and then navigate to the theme → patterns and export the JSON.
Open the JSON in a text editor, copy out the value of content
and append it to wp-content/plugins/my-custom-blocks/my-custom-blocks.php
, wrapping it in a function and hooking that function like so:
function my_custom_blocks_patterns_init(): void
{
register_block_pattern('my-custom-blocks/my-pattern', array(
'title' => __('My Pattern', 'my-custom-blocks'),
'categories' => array('featured'), // adding the pattern to the featured collection makes it easier for content editors to find
'source' => 'plugin',
'content' => ""
));
}
add_action('init', 'my_custom_blocks_patterns_init');
Feedback?
Email us at enquiries@kinsa.cc.