How to Enhance WordPress Blocks With Block.json and Server-side Registration

Learn how to register blocks and why block.json is the recommended method.

The WordPress site editor, powered by blocks, allows users to create and customize their content in a structured, visually appealing way. Each block represents a specific type of content, such as a text paragraph, image, video, or any other custom element. For these blocks to function properly, they must be registered with WordPress core. 

Table of Contents

Different methods of block registration

Client-side

Blocks registered client-side are processed by the JavaScript code that runs on the client’s browser. This allows blocks to be added and rendered in both the WordPress editor and the front end. The edit() method defines how the block will be rendered and interacted with in the editor, while the save() method defines how the block will be rendered on the front end of the website.

Server-side

Blocks registered server-side can be processed by the PHP code of the WordPress theme or plugin. This method offers advanced features—like custom fields and dynamic data—that render the block on the server. 

Block.json (recommended)

Blocks can also be registered through a block.json file, a new way to define blocks in the site editor and an improvement over server-side registration. Registering via block.json makes it easier to use blocks in plugins and themes, ensuring consistent metadata, which can also improve front end performance.

How the `block.json` file works

Since the deployment of WordPress 5.8, it’s possible to use a special metafile—`block.json`—that contains the metadata and settings for a block (name, title, and icon). This file makes it easy to distribute and install blocks across different themes and plugins by providing a clear and organized way of defining blocks and their attributes.

The block definition offers the benefit of code sharing between JavaScript, PHP, and other languages when processing block types stored as JSON. Registering blocks with the block.json file also simplifies the registration process—allowing quick and easy dual registration with server-side and client-side—by using the `register_block_type()` WordPress PHP function.

function wpvip_example_block_registration() {
	
	// By providing a path to a directory as the first argument, 
	// `register_block_type` will look for a `block.json` file in
	// that directory.
	// You can also provide the full path to the block.json file.
	register_block_type( __DIR__ );
}
add_action( 'init', wpvip_example_block_registration );

The block.json file is a great option for those who want to distribute their custom blocks to a wider audience and/or make it easy for others to install and use them. Thanks to the easy dual registration, the block can be used in any context: the WordPress editor, a JavaScript front end or mobile app, even the REST API. 

This flexibility gives developers more power when creating and distributing their blocks, especially when ingesting the content to multiple front ends with an omnichannel approach. 

The block.json registration method may even help with front end performance if your theme supports lazy loading of its assets. Blocks that are registered using this metafile will automatically have their asset enqueuing optimized. The CSS and JavaScript assets registered in the `style` or `script` properties will only be enqueued when the block is present on the current page, which helps reduce page size. 

How to register a block using `block.json`

The `block.json` file handles the block registration both client-side and server-side, and carries all the attributes and block configuration needed within a single metadata file. 

1. Create a new block.json file and register with client-side

Find all the available fields for this file in official WordPress.org documentation. Add a schema entry to the top of the block.json file to provide assistance through tooltips, autocomplete, and validation (if your editor supports it) during the development stage.

// block.json file
{
"$schema": "https://schemas.wp.org/trunk/block.json",
    "name": "wpvip_example/hello-block",
    "title": "Hello Block",
    "icon": "shield",
    "category": "common",
    "attributes": {
        "name": {
            "type": "string"
        }
    },
    "editor_script": "file:./build/hello-block.js"
}

The `editor_script` property in the block.json file specifies the JavaScript file that contains the code to register the block on the client-side using the `registerBlockType` function from the `@wordpress/blocks` package. This property should point to the relative path of the JavaScript file where the block is being registered.

import { registerBlockType } from '@wordpress/blocks';
import metadata from '../block.json';

registerBlockType( metadata, {
edit: () => { /* edit component */ },
save: () => { /* save component, where the rendering happens */ },
}

2. Register with server-side

Once your block is registered client-side with all the metadata from the `block.json` file, it needs to be registered on the server-side. Do this by calling the `register_block_type()` function with the block directory as the first argument (the full path to the `block.json` file can also be provided). The block will be registered on both client and server-side, sharing the same metadata like block attributes, CSS styles, and JS files.

// file: hello-block.php
<?php

function wpvip_example_register_hello_block() {
    // Register the block using a block.json file in the current directory
    register_block_type( __DIR__ );
}
add_action( 'init', 'wpvip_example_register_hello_block' );

The `register_block_type` function also accepts a second argument, with an array of block type arguments, which can be used to configure how the block is registered. This function can also register the block with a specific rendering callback function as shown below.

<?php

function wpvip_example_register_hello_block() {
    // Register the block using a block.json file in the current directory
    register_block_type( __DIR__,
    array(
        'render_callback' => 'wpvip_example_render_hello_block',
    )
    );
}
add_action( 'init', 'wpvip_example_register_hello_block' );

function wpvip_example_render_hello_block( $attr ) { ... }

Alternatively to setting a render callback, it’s possible to leverage the `render` property in the `block.json` file. This property specifies which PHP file will be used to server-side render the block. If the `render` property and the `render_callback` argument are not set, the rendering will be handled by the client-side, as a normal client-side block would. 

// block.json file with server-side rendering
{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "name": "wpvip_example/hello-block",
    (...)   
    "render": "file:./render.php"
}

For more information on available arguments when registering a block, review the `register_block_type` documentation and `block.json` metadata documentation.

Benefits of using both server-side and client-side block registration for decoupled applications 

If you can’t use a block.json file, at least register with both client-side and server-side. While possible, exclusive client-side registration for blocks in the site editor can unfortunately limit the functionality of the block, making it difficult to use outside the WordPress environment. Issues include rendering the blocks when generating HTML for a web front end, or generating specific components on a mobile application to represent that block. 

Registering server-side is especially important for decoupled applications where the content needs to flow from the WordPress back end to a completely different front end environment. If the WordPress core doesn’t know about a block and its attributes (as a consequence of not performing server-side registration), it will not provide that information via API to be consumed by the decoupled application, and therefore the application will cannot render that content properly. 

Dual registration to both server-side and client-side allows for greater flexibility in using the block. It enables the WordPress API to recognize the block, its attributes, and how to generate structured data to represent that block so you can use it in any context.

Our recommendation: use server-side registration, or the block.json file, to register blocks in WordPress.

How to register a client-side block on the server-side

You can register a current client-side block on the server-side without using the `block.json` metadata file.

1. Register the block on client-side

For this custom block named “Hello Block”, which is registered only on the client-side, we’ve used the `registerBlockType` function, with an attribute named `name` (a simple string). See the step-by-step registration below.

// file: hello-block.js
import { registerBlockType } from '@wordpress/blocks';

registerBlockType( 'wpvip-example/hello-block', {
    title: 'Hello Block',
    icon: 'shield',
    category: 'common',
    attributes: {
        name: {
            type: 'string',
        },
    },
    edit: ( { className, setAttributes, attributes } ) => {
        const { name } = attributes;
        return (
            <div className={ className }>
                <p>Hello {name}</p>
                <input 
                    type='text'
                    value={name}
                    onChange={(event) => setAttributes({name: event.target.value})}
                />
            </div>
        );
    },
    save: ( { attributes } ) => {
        const { name } = attributes;
        return <p>Hello {name}</p>;
    },
} );

The `edit` callback renders a paragraph with the text `”Hello” + name`, followed by an input field that allows you to edit the `name` value. The `save` callback then returns the paragraph with the string as the final output of the block.

This block, while fully functional, is registered only on the client-side of WordPress, which means it’s visible only to the WordPress editor—as such, WordPress core is unaware of its existence.

2. Register the block on server-side

To make it visible to WordPress core, register it on the server-side using the WordPress PHP API. There are two ways to do this: 

  1. Create a new PHP file to handle the block’s server-side registration
  2. Use an existing file if it is already bundled with a plugin or a theme

Easily register a client-side block on the server-side through the `register_block_type` PHP function. If we continue with the “Hello Block” example, we just need to call the `register_block_type` as shown below.

// file: hello-block.php
<?php

function wpvip_example_register_hello_block() {
    // (...) enqueue the scripts and styles (...)

    register_block_type('wpvip-example/hello-block' );
}
add_action( 'init', 'wpvip_example_register_hello_block' );

We’ve now registered a very simple client-side-only block on the server-side. All the rendering is still handled on the client-side with the `save` callback function on the `hello-block.js` file. 

Note: the server-side still doesn’t know which attributes are available in this block because its registration is basic—all block logic is handled in the client side. 

As we have only a single attribute in this example (`name`), we can provide that information when registering the block as seen in the script below.

// file: hello-block.php
<?php

function wpvip_example_register_hello_block() {
    // (...) enqueue the scripts and styles (...)

    register_block_type( 'wpvip-example/hello-block', 
[ 
'attributes' => [
		'name' => [
			'default' => 'default name',
			'type'    => 'string'
		],
	],
	] );
}
add_action( 'init', 'wpvip_example_register_hello_block' );

It’s also possible to offload the rendering to the server-side, by making use of the `render_callback` argument. This approach will render the block content on the server-side using PHP.

// file: hello-block.php
<?php

function wpvip_example_register_hello_block() {
    // (...) enqueue the scripts and styles (...)

    register_block_type(
        'wpvip-example/hello-block',
        array(
		 'attributes' => (...), // block attributes
            'render_callback' => 'wpvip_example_render_hello_block',
        )
    );
}
add_action( 'init', 'wpvip_example_register_hello_block' );

function wpvip_example_render_hello_block( $attributes ) {
    return '<p>Hello ' . esc_html( $attributes['name'] ) . '</p>';
}

We now have two callback functions that handle the rendering of the block: one on the client-side (the `save` callback) and one on the server-side (the `wpvip_example_render_hello_block` function). When working with dynamic blocks, you should return `null` from the `save` callback function defined on the JavaScript file. This tells the editor to save only the block’s attributes to the database and skip the block markup validation process, avoiding frequently changing markup issues. 

These attributes are then passed into the server-side rendering function, which you can use to decide how to display the block on the front end of your site. The server-side render function will then be in charge of displaying the block on the front end, using the saved attributes to display the block correctly. 

The final block will look like this:

// file: hello-block.js
import { registerBlockType } from '@wordpress/blocks';

registerBlockType( 'wpvip-example/hello-block', {
    title: 'Hello Block',
    icon: 'shield',
    category: 'common',
    attributes: {
        string: {
            type: 'string',
        },
    },
    edit: ( { className, setAttributes, attributes } ) => {
        const { string } = attributes;
        return (
            <div className={ className }>
                <p>Hello {string}</p>
                <input 
                    type='text'
                    value={string}
                    onChange={(event) => setAttributes({string: event.target.value})}
                />
            </div>
        );
    },
    save: ( { attributes } ) => null,
} );
// file: hello-block.php
<?php

function wpvip_example_register_hello_block() {
    // (...) enqueue the scripts and styles (...) 

    register_block_type(
        'wpvip-example/hello-block',
		[ 
'attributes' => [
		'name' => [
			'default' => 'default name',
			'type'    => 'string'
		],
	],
        	     'render_callback' => 'wpvip_example_render_hello_block',
	] );
}
add_action( 'init', 'wpvip_example_register_hello_block' );

function wpvip_example_render_hello_block( $attributes ) {
    return '<p>Hello ' . esc_html( $attributes['name'] ) . '</p>';
}

Simplify conversion with a block.json file

Converting a client-side block into a server-side block can seem daunting, but using the block.json file simplifies the process. This method allows for easy distribution and installation of blocks, and also automatically registers the blocks on both server-side and client-side.

The block.json method also allows for code sharing between JavaScript, PHP, and other languages when processing block types stored as JSON. By using block.json, you can take full advantage of the powerful capabilities of the site editor and build robust, dynamic, and versatile blocks for your WordPress website.

This flexibility ensures your blocks are not limited in their functionality and can be used in any context, both inside and outside the WordPress environment.

Still need help? 

Get the latest content updates

Want to be notified about new content?

Leave your email address and we’ll make sure you stay updated.