Block Editor
The WordPress Block Editor (Gutenberg) is a modern editing experience that allows content to be created using modular components called blocks. Each block represents a piece of content such as text, images, lists, or custom UI elements.
Creating custom blocks allows developers to extend the editor with tailored functionality suited to specific websites or applications.
The process of learning block development typically begins with a simple example and progressively adds functionality such as attributes, controls, styling, and dynamic rendering.
The objective of this lesson is to introduce the fundamentals of creating a custom Gutenberg block. The learning process follows a gradual approach:
Start with the simplest possible block.
Incrementally add common functionality.
Understand how block assets and structure work.
Learn how JavaScript and PHP interact during block registration.
Developers are encouraged to experiment by modifying code examples and observing how these changes affect the block’s behavior.
Code Syntax Formats
Two formats are typically used when writing Gutenberg block code.
JSX
JSX is a syntax extension for JavaScript used with frameworks like React.
Characteristics:
Requires a build process
Compiled into browser-compatible JavaScript
Easier to read and write
Widely used in Gutenberg development
Example JSX:
return <p>Hello world!</p>;
Plain JavaScript
Plain JavaScript does not require a build step.
Characteristics:
Compatible with browsers without compilation
Slightly more verbose syntax
Useful for simpler setups
Example Plain JavaScript:
return wp.element.createElement(
"p",
null,
"Hello world!"
);
Although both approaches work, most modern Gutenberg development uses JSX with a build step.
Creating a Gutenberg Block
Creating a block involves a combination of JavaScript, Node.js build tooling, and WordPress PHP registration.
Step 1: Create a Plugin
Blocks are usually distributed through WordPress plugins.
Example plugin structure:
my-first-block-plugin
│
├── my-first-block-plugin.php
├── package.json
├── src
│ └── first-block
│ ├── block.json
│ └── index.js
└── build
Step 2: Initialize Node.js
Inside the plugin folder, initialize a Node.js project.
npm init
This generates a package.json file used to manage dependencies and scripts.
Step 3: Install WordPress Scripts
Install the official WordPress development tools.
npm install @wordpress/scripts --save-dev
The @wordpress/scripts package provides build tools such as:
Webpack
Babel
ESLint
Preconfigured Gutenberg environment
Step 4: Configure Build Scripts
Add the following scripts to package.json.
"scripts": {
"start": "wp-scripts start",
"build": "wp-scripts build"
}
Explanation:
| Script | Purpose |
|---|---|
| start | Starts development build with live reloading |
| build | Generates optimized production files |
Step 5: Create Block Directory
Inside the plugin folder create the following structure.
src/
first-block/
This directory will contain the block source files.
Step 6: Create block.json
The block.json file defines the block’s metadata and configuration.
Example:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"title": "First Block",
"name": "learning/first-block",
"version": "0.1.0",
"category": "text",
"icon": "universal-access-alt",
"textdomain": "first-block",
"editorScript": "file:./index.js"
}
Explanation of key fields:
| Field | Description |
|---|---|
| apiVersion | Specifies the block API version |
| title | Block name shown in the editor |
| name | Unique block identifier |
| category | Editor category where the block appears |
| icon | Dashicon used in the block inserter |
| textdomain | Used for translation |
| editorScript | JavaScript file used in the editor |
The block.json file allows WordPress to automatically register assets and configuration.
Step 7: Create index.js
The index.js file contains the JavaScript logic that defines the block.
Example:
import { registerBlockType } from "@wordpress/blocks";
import metadata from "./block.json";
// Register the block
registerBlockType(metadata.name, {
edit: function () {
return <p>Hello world! This is my first block. (editor)</p>;
},
save: function () {
return <p>Hello World! This is my first block. (frontend)</p>;
},
});
Explanation:
| Function | Purpose |
|---|---|
| registerBlockType | Registers the block in Gutenberg |
| edit | Defines how the block appears inside the editor |
| save | Defines how the block is stored and displayed on the frontend |
Important concept:
edit() runs inside the editor.
save() defines the HTML saved into the post content.
Step 8: Register Block in PHP
Finally, register the block on the server side inside the plugin’s main PHP file.
function register_blocks() {
register_block_type( __DIR__ . '/build/first-block' );
}
add_action( 'init', 'register_blocks' );
Explanation:
| Function | Purpose |
|---|---|
| register_block_type() | Registers the compiled block files |
| add_action(‘init’) | Ensures registration during WordPress initialization |
The build folder contains compiled assets produced by the JavaScript build process.
Step 9: Build the Block
Run the build command.
npm run build
This command:
Compiles JSX into browser-compatible JavaScript
Bundles assets
Generates the build directory
Once built, the block will appear inside the WordPress block inserter.
JavaScript and PHP Registration
Blocks are registered in both:
JavaScript → for the editor interface
PHP → for WordPress server-side awareness
This dual registration ensures:
Proper asset loading
Compatibility with server-side rendering
Block availability in REST API and frontend
Asset Handling
When using block.json, WordPress automatically handles:
Script enqueuing
Style loading
Translations
Dependencies
This reduces manual configuration for developers.
Build Assets File
After building, an asset file is generated automatically.
Example:
index.asset.php
This file contains:
Script dependencies
Version information
Example structure:
return array(
'dependencies' => array('wp-blocks', 'wp-element'),
'version' => '123456'
);
WordPress uses this file to load scripts correctly.
Block Styles
Custom block styles can be registered using:
registerBlockStyle('core/paragraph', {
name: 'xyz',
label: 'XYZ Style'
});
When applied, Gutenberg adds the CSS class:
is-style-xyz
to the block wrapper.
Client-Side Only Blocks
Technically, blocks can be registered only in JavaScript without PHP.
However, server-side registration is recommended because it:
Ensures asset loading
Improves compatibility
Supports server-rendered blocks
Allows block discovery by WordPress