As a reminder, we will start to create a static “Subscription form” block, this one:

Custom block Gutenberg
However, by the end of this lesson, our block will now have any CSS yet, we will add CSS for our custom Gutenberg block in one of the next lessons of this course.

File Structure of a Custom Gutenberg Block

We can begin by creating the following files in the block folder.

FileDescription
misha-block.phpMain block and plugin file.
block.jsonContains block information.
src/index.jsContains JavaScript (JSX) code of the block.
src/editor.scssCSS styles of the block in the Block Editor.
src/style.scssCSS styles of the block in both the Block Editor and on the website.

You can also feel free to create a /build folder where all the compiled files will be generated automatically by the @wordpress/scripts tool. You can also put the block.json file into the /src folder, and after that, its copy will be created in the /build folder automatically as well, but I prefer not to do that.

register_block_type() – Registering Gutenberg Blocks in PHP

Just in case, it is not what you think it is. Of course, we are not going to use PHP for Gutenberg block development; however, we still need to add a couple of lines into the main block/plugin PHP file, which is, in our case, misha-block.php.

All we need to do is use the register_block_type() function inside the init action hook. In this function, you can either provide some block information or just a directory path to the block.json file. Let’s do the latter.

/*
 * Plugin name: Block by Misha
 * Version: 1.0.0
 * Author: Misha Rudrastyh
 * Author URI: https://rudrastyh.com
 * Plugin URL: https://rudrastyh.com/gutenberg/create-a-block.html
 */
add_action( 'init', 'rudr_register_in_php' );

function rudr_register_in_php() {

	register_block_type( __DIR__ );

}

In my case, the block.json file is exactly in the same directory as the misha-block.php file is, which means that we can provide __DIR__ as an argument of the register_block_type() function.

In case you decided to go another way and put your block.json file into the /src folder, then you need to specify the path to the /build folder.

register_block_type( __DIR__ . '/build' );

block.json

Using the block.json file has only become available since WordPress version 5.8. Before that, we had to put the block information half in the register_block_type() PHP function and half in the registerBlockType() JavaScript function (we will talk about it soon).

I preferred to do as many things on the client side as possible, but I know that most of the developers tried to do the opposite – as many things as possible on the server side.

Below is an example of the block.json configuration file that we are going to use for our “Subscription form” block. Of course, it has many more parameters available, and you can find all of them in the official WordPress documentation. Plus, we will learn some of the parameters we will learn later during this course.

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 2,
	"name": "rudr/subscribe-form",
	"title": "Subscription form",
	"description": "This block displays a subscription form",
	"category": "text",
	"icon": "email",
	"editorScript": "file:./build/index.js",
	"editorStyle": "file:./assets/style.css",
	"style": "file:./assets/front.css",
	"supports": {
		"html": true,
		"align" : [ "wide", "full" ]
	}
}

So far we have:

  • $schema and apiVersion are not something you should be concerned about; you can leave them be unless you have some specific requirements.
  • name – It is the block slug with its namespace. The namespace can be a string that you will use for all Gutenberg blocks you develop, for example, I use “rudr”.
  • title – The block name, how it is going to be displayed in the Block Editor.
  • description – The block description, which will be displayed in the Block Editor when you hover over a block in the inserter.
  • category – Here, you can set in which group of blocks in the Inserter your custom block should appear. The standard ones are: media, design, widgets, theme, embed and text. But it is possible to create a custom category there.
  • icon – I don’t usually use this parameter because it only allows you to choose an icon from the Dashicons set (you just need to provide an icon slug). I usually use custom SVG icons for Gutenberg blocks, so we can skip this parameter and do the stuff in the registerBlockType() function.
  • editorScript – Most of the block code will be in this JavaScript file.
  • editorStyle – Provide the path to a CSS (or SCSS) file with styles that should be applied only in the Block Editor.
  • style – The path to a CSS (or SCSS) file with styles that will be applied to your custom block in both the Block Editor and on the website.
  • supports – This parameter can have a lot of additional block configuration, and we will learn some of them in the following tutorials. For now, I allow the users to view the block HTML with the help of "html": true and to make the block wide or full-width.

As a reminder, you can always download the files of our custom Gutenberg block for every lesson using the link below:

Sorry, but you don’t have access to the source files. Sign in or buy the course.

registerBlockType() – Registering the Block in JavaScript

Below is the code for the main JavaScript file of the Gutenberg block, which is src/index.js.

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';

import metadata from './../block.json';

registerBlockType( 
	metadata,
	{
		edit: () => {
			return(
				<div {...useBlockProps()}>
					<h3>Subscribe to my newsletter</h3>
					<p>
						<span>Email address</span>
						<span>Subscribe</span>
					</p>
				</div>
			)
		},
		save: () => {
			return (
				<div {...useBlockProps.save()}>
					<h3>Subscribe to my newsletter</h3>
					<form>
						<input type="email" placeholder="Email address" />
						<button>Subscribe</button>
					</form>
				</div>
			)
		}
	}
)

Now, let’s discuss the above code a little bit:

  • As you can see, we don’t provide any block information (a block name, description, etc), because we import it from the block.json file instead.
  • The edit() method generates the block HTML markup, which is used only inside the Block Editor. This is actually a critical point to understand, because, for example, in our case of a subscription form block, it means that we don’t have to use <input>, <form>, or <button> tags inside this method. Why? Because you are not going to submit your form when editing a post, are you?
  • On the other hand, the save() method should return the HTML of a block exactly the same way as how the block is going to be displayed on the website pages and saved to the database. That’s where we can use <form>, <input> and <button> HTML tags.

Moving save() and edit() methods into separate files

The code above is completely fine; however, if you’re working on a complicated custom block for Gutenberg, it will be much more convenient for you, I guess, if you do the work with both edit() and save() methods in separate JavaScript files.

In that case, this is how our src/index.js file is going to look:

import { registerBlockType } from '@wordpress/blocks';

import Edit from './edit';
import Save from './save';
import metadata from './../block.json';

registerBlockType( 
	metadata,
	{
		edit: Edit,
		save: Save
	}
)

src/edit.js file:

import { useBlockProps } from '@wordpress/block-editor';

export default function Edit() {
	return(
		<div {...useBlockProps()}>
			<h3>Subscribe to my newsletter</h3>
			<p>
				<span>Email address</span>
				<span>Subscribe</span>
			</p>
		</div>
	)
}

src/save.js file:

import { useBlockProps } from '@wordpress/block-editor';

export default function Save() {
	return (
		<div {...useBlockProps.save()}>
			<h3>Subscribe to my newsletter</h3>
			<form action="">
				<input type="email" placeholder="Email address" />
				<button>Subscribe</button>
			</form>
		</div>
	)
}

You can download the Gutenberg block files from this tutorial using the link below:

Sorry, but you don’t have access to the source files. Sign in or buy the course.

Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 15 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X