How to Create a Gutenberg Block if You Know Nothing
I want to begin with some kind of intro. Let’s suppose guys, that you have some experience with builders, like… (I do not want to call their names). Do you remember how all the builders work? With the help of shortcodes, right?
It is a shortcode in a shortcode in a shortcode in a shortcode! ๐ฑ
But what is a shortcode? It is PHP code, right? The first mistake with Gutenberg might be thinking that its blocks are something like shortcodes.
But it is not true, the result HTML is generated immediately while you edit your content with Gutenberg and saved in database just the same form it is going to be displayed on your website. Well, maybe excluding Gutenberg comments like this: <!-- wp:misha/newsletter -->
Below is what we are going to create in this tutorial โ simple subscription form block.

Step 1. Enqueue Block JS and CSS
The simplest part of the tutorial because I think most of you are familiar with it.
Let’s begin with creating two files in your theme / plugin folder, one is block-newsletter.js
and another is block-newsletter.css
. I think it should be clear what we’re going to put in these files.
Once you created the files, we can try to include them:
add_action( 'enqueue_block_editor_assets', 'misha_block_assets' ); function misha_block_assets(){ wp_enqueue_script( 'misha-newsletter', plugin_dir_url( __FILE__ ) . 'assets/block-newsletter.js', array( 'wp-blocks', 'wp-element' ), filemtime( dirname( __FILE__ ) . '/assets/block-newsletter.js' ) ); wp_enqueue_style( 'misha-newsletter-css', plugin_dir_url( __FILE__ ) . 'assets/block-newsletter.css', array( 'wp-edit-blocks' ), filemtime( dirname( __FILE__ ) . '/assets/block-newsletter.css' ) ); }
I decided to work in a custom plugin which I’ve created specifically for this block, so I use plugin_dir_url( __FILE__ )
to get the URL of the plugin folder and filetime()
function to prevent .js and .css files from being cached while I’m working with them.
To make sure that your files have been enqueued, you can insert some simple code there, like alert( 'test' )
in the block-newsletter.js
file and body{ background: #000 }
in block-newsletter.css
file.
Note: Please use block-newsletter.css
only to customize this certain block, do not use it if you need to change some Gutenberg editor styles, in case you need to, make a look at this tutorial.
Step 2. Using registerBlockType() to Create a New Gutenberg Block
Components Explained
In order to create a simple not editable block, we will need createElement()
method, which is the part of wp.element
component and registerBlockType()
which is the part ofย wp.blocks
component. Seems clear at this moment?
( function( blocks, element ) { const el = element.createElement; const { registerBlockType } = blocks; // const registerBlockType = blocks.registerBlockType; // the same registerBlockType( .... ); // it is described in the next chapter } )( window.wp.blocks, // wp.blocks becomes just "block" variable window.wp.element, );
In the above code I can also write:
const { createElement } = element; const { registerBlockType } = blocks;
But while working with blocks usually we have to use createElement()
too often and it will be much more easier if this method will be named el()
.
registerBlockType()
It is where all the magic happens when you create Gutenberg blocks.
registerBlockType( 'misha/newsletter', { title: 'Newsletter', icon: iconEmail, category: 'common', keywords: [ 'email', 'subscribe', 'misha' ], edit: function( props ) { } save: function( props ){ } });
misha/newsletter
(line 7) โ is the block ID, you can use something/something
iconEmail
(line 9) is the constant / variable which contains a SVG icon, there is a separate tutorial about icons in Gutenberg, highly recommended to read.
category
(line 10) โ in which category your block should be:

common
, formatting
, layout
, widgets
, embed
.keywords
(line 11) โ specify no more than 3 keywords in an array. When somebody performs a search for a block, the block title and keywords will be used.
edit()
and save()
functions are described below.
edit()
This function returns HTML code which is used to display a block in Gutenberg. And it is critical to understand.
It means that for our block we do need <form>
or <button>
tags, they will be in save() function below. But here we must use just static HTML elements like div or span or p. That’s all!
In the next tutorial we are going to replace some of them with Editable
and RichText
components, but at this moment our block is not editable, so we will leave it for now.
In order to understand the below code you have to learn some basics about creating elements in React.
edit: function( props ) { return ( el( 'div', { className: props.className }, el( 'div', { className: 'misha-block-form-wrap' }, el( 'div', {}, 'Enter your email address' ), el( 'div', {}, 'Subscribe' ) ) ) ); },
save()
This function should return HTML how the block is going to be displayed on the website pages and saved to database. That’s why here we’re using <form>
, <input>
and <button>
tags.
save: function( props ) { return ( el( 'div', { className: props.className }, el( 'form', { className: 'misha-block-form-wrap' }, el( 'input', { 'type': 'email', 'placeholder' : 'Enter your email address' } ), el( 'button', {}, 'Subscribe' ) ) ) ); },
Finally, the result.

We’re done ๐
If you would like to download the ready plugin, here it is.
Comments — 8
Thanks
Great
Great post, thanks!
But why I can’t do it when I create my custom theme? Why I must cheate some plugin for this? How I can create my custom block in my theme wordpress?
Thank you!
You can easily do it in a custom theme, why not
What’s your opinion about putting custom gutenberg block into the theme or as a plugin?
In this blog it’s said that having a plugin is better. https://jasonyingling.me/gutenberg-best-practices-for-blocks-and-themes/
But when developing, I prefer to have everything in one place instead of two.
And how would you add the custom gutenberg block into the theme instead as a plugin?
My opinion is that putting it in themes is ok ๐
Hi in which file am I supposed to put the registerBlockType function?
Hi Kate,
In
block-newsletter.js
.Comments are closed.