How to Create Dynamic Blocks for the Gutenberg Editor in WordPress

When a block is presented on the front end, dynamic blocks construct its structure and content on the fly.

Dynamic blocks are mostly used for two purposes:

  1. Content should change even if a post hasn’t been changed in these blocks. The Latest Posts block is an example from WordPress itself. When a new post is published, this block will update everywhere it is used.
  2. Blocks where changes to the website’s code (HTML, CSS, JS) should be immediately visible on the front end. If you modify the structure of a block by adding a new class, an HTML element, or changing the layout in any other way, utilising a dynamic block guarantees that the changes are applied to all instances of that block across the site instantaneously. (If a dynamic block is not utilised, Gutenberg’s validation procedure is applied when block code is altered), resulting in the validation notice which shows in picture below.
img-1

Getting Started with Creating Dynamic Blocks

The save callback method for many dynamic blocks should be null. Instructing the editor to save just the block attributes to the database. These attributes are then passed into the server-side rendering callback. So you can decide how to display the block on the front end of your site. When you return null, the editor will skip the block markup validation process, avoiding issues with frequently changing markup.

If you’re using InnerBlocks in a dynamic block, you’ll need to save the InnerBlocks using <InnerBlocks.Content/> in the save callback method.

You may also preserve the block’s HTML representation. This HTML will be replaced with the result of your callback if you supply a server-side rendering callback, but it will be displayed if your block is disabled or your render callback is deleted.

Any material or configuration you wish to save for that block may be saved using block attributes. The number of recent posts you wish to show may be preserved as an attribute in the first example above with the latest posts block. Alternatively, attributes may be utilized for each item of information you wish to display in the front end, such as headline text, paragraph text, an image, a URL, and so on.

The example below demonstrates how to construct a dynamic block that only displays the most recent post as a link.

ES5:

( function ( blocks, element, data, blockEditor ) {
    var el = element.createElement,
        registerBlockType = blocks.registerBlockType,
        useSelect = data.useSelect,
        useBlockProps = blockEditor.useBlockProps;
 
    registerBlockType( 'softhunt/example-dynamic', {
        apiVersion: 2,
        title: 'last post',
        icon: 'megaphone',
        category: 'widgets',
        edit: function () {
            var content;
            var blockProps = useBlockProps();
            var posts = useSelect( function ( select ) {
                return select( 'core' ).getEntityRecords( 'postType', 'post' );
            }, [] );
            if ( ! posts ) {
                content = 'Loading...';
            } else if ( posts.length === 0 ) {
                content = 'No posts';
            } else {
                var post = posts[ 0 ];
                content = el( 'a', { href: post.link }, post.title.rendered );
            }
 
            return el( 'div', blockProps, content );
        },
    } );
} )(
    window.wp.blocks,
    window.wp.element,
    window.wp.data,
    window.wp.blockEditor
);

ESNext:

import { registerBlockType } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import { useBlockProps } from '@wordpress/block-editor';
 
registerBlockType( 'softhunt/example-dynamic', {
    apiVersion: 2,
    title: 'last post',
    icon: 'megaphone',
    category: 'widgets',
 
    edit: () => {
        const blockProps = useBlockProps();
        const posts = useSelect( ( select ) => {
            return select( 'core' ).getEntityRecords( 'postType', 'post' );
        }, [] );
 
        return (
            <div { ...blockProps }>
                { ! posts && 'Loading' }
                { posts && posts.length === 0 && 'No Posts' }
                { posts && posts.length > 0 && (
                    <a href={ posts[ 0 ].link }>
                        { posts[ 0 ].title.rendered }
                    </a>
                ) }
            </div>
        );
    },
} );

It is not necessary to modify the client’s default save implementation because it is a dynamic block. Instead, a server component is required. The contents in the front of your site depend on the function called by the render_callback property of register_ block_type.

<?php
 
/**
 * Plugin Name: Gutenberg examples dynamic
 * Description: Gutenberg examples dynamic by softhunt.net
 */
 
function softhunt_gutenberg_dynamic_render_callback( $block_attributes, $content ) {
    $recent_posts = wp_get_recent_posts( array(
        'numberposts' => 1,
        'post_status' => 'publish',
    ) );
    if ( count( $recent_posts ) === 0 ) {
        return 'No posts';
    }
    $post = $recent_posts[ 0 ];
    $post_id = $post['ID'];
    return sprintf(
        '<a class="wp-block-my-plugin-latest-post" href="%1$s">%2$s</a>',
        esc_url( get_permalink( $post_id ) ),
        esc_html( get_the_title( $post_id ) )
    );
}
 
function softhunt_gutenberg_examples_dynamic() {
    // automatically load dependencies and version
    $asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');
 
    wp_register_script(
        'softhunt_gutenberg-examples-dynamic',
        plugins_url( 'build/block.js', __FILE__ ),
        $asset_file['dependencies'],
        $asset_file['version']
    );
 
    register_block_type( 'softhunt/example-dynamic', array(
        'api_version' => 2,
        'editor_script' => 'softhunt_gutenberg-examples-dynamic',
        'render_callback' => 'softhunt_gutenberg_dynamic_render_callback'
    ) );
 
}
add_action( 'init', 'softhunt_gutenberg_examples_dynamic' );

Factors to keep in mind:

  • The edit feature still displays a representation of the block in the editor’s context (which may change significantly from the rendered version; the block’s creator has complete control over this).
  • Because the rendering is done on the server, the built-in save method just returns null.
  • The server-side rendering is a function that takes two arguments: the block and the block inner content, and returns the markup (quite similar to shortcodes)

Live rendering in the block editor

The <ServerSideRender> block was added in Gutenberg 2.8, allowing rendering to take place on the server using PHP rather than JavaScript.

Client-side rendering in JavaScript is always preferable; server-side rendering is only used as a backup. (client rendering is faster and allows better editor manipulation).

ES5:

( function ( blocks, element, data, blockEditor ) {
    var el = element.createElement,
        registerBlockType = blocks.registerBlockType,
        ServerSideRender = serverSideRender,
        useBlockProps = blockEditor.useBlockProps;
 
    registerBlockType( 'softhunt/example-dynamic', {
        apiVersion: 2,
        title: 'last post',
        icon: 'megaphone',
        category: 'widgets',
        edit: function () {
            var blockProps = useBlockProps();
            return el(
                'div',
                blockProps,
                el( ServerSideRender, {
                    block: 'softhunt/example-dynamic',
                    attributes: props.attributes,
                } )
            );
        },
    } );
} )(
    window.wp.blocks,
    window.wp.element,
    window.wp.data,
    window.wp.blockEditor
);

ESNext:

import { registerBlockType } from '@wordpress/blocks';
import ServerSideRender from '@wordpress/server-side-render';
import { useBlockProps } from '@wordpress/block-editor';
 
registerBlockType( 'softhunt/example-dynamic', {
    apiVersion: 2,
    title: 'last post',
    icon: 'megaphone',
    category: 'widgets',
 
    edit: () => {
        const blockProps = useBlockProps();
        return (
            <div { ...blockProps }>
              <ServerSideRender
                    block="softhunt/example-dynamic"
                    attributes={ props.attributes }
                />
            </div>
        );
    },
} );

This code does not utilize the wp-data package, but rather the wp-server-side-render package. Make that the PHP code’s dependencies are up to date. For auto dependencies, you may use wp-scripts and ESNext setup (see the Gutenberg-examples repo for PHP code setup).

That’s all for this article if you have any queries please contact us through our website or email us at [email protected]

Leave a Comment