PHP ROUTE

Custom Block Development Part-8: Dynamic Block

This is the eighth article of our custom block development series, in this article we are going to learn how we can create a dynamic custom block that loads its content directly from WordPress. This article is a continuation of previous articles so if you haven’t read them yet you might get confused while reading this article. You can read our previous article on this link and a complete list of all custom block development articles on this link.

Till now we have learned how to create a custom block with styling options, we have also learned how we can add different media inside our custom block. Now we are going to learn how we can create dynamic custom blocks that fetch data on the fly every time a page loads and show newly fetched data.

What is Dynamic Custom Block?

First, let’s take a look and understand what exactly is dynamic custom block is and how it is different from the normal custom block. With the normal block, the content of that block will always stay the same, and to make any changes you need to make changes in the post in which you have added the block. You will edit the block inside the post and update that post to make the changes live on site.

On the other hand with dynamic block, you run a query whenever your block loads on any page or post and based on the returned response from the query the block will render. That’s how your custom block will always have the latest data and you don’t need to update or make changes in your block.

When to Use Dynamic Block?

Now let’s see what are some use cases of the dynamic custom blocks, the use case mainly depends on what you want to do but let’s see two primary use cases.

  1. Blocks which contents automatically get updated even no changes are made to the block or page itself. For example WordPress’s latest post block. This block will automatically load the block with the newest posts published on the website and you don’t need to make any changes on the block or containing post/page.
  2. Another use case is for the blocks where changes to code (HTML, CSS, JS) will be immediately shown on the front end of the website. For example, if you made changes in the structure of the block, by adding some HTML element, adding some classes, or making changes in layout in any other way. Because of using dynamic block, the changes will load everywhere immediately.

Now let’s see how we can create our own custom dynamic block.

Create Dynamic Custom Block

dynamic custom block

So in our dynamic block, I will create a custom block that will fetch the latest post from the specific post category and show its preview. In the preview, we will have the feature image of the post, below that we’ll have the post title and the post excerpt. You can see how it looks in the image above.

Initial Setup

So before making any change I have created a new block folder in our plugin src folder and created the index.js script for our custom block. I have also added the basic structure of our block with its name, description, logo, and stuff and the code will look as shown below.

const { registerBlockType } = wp.blocks;
const { RichText } = wp.editor;
const { withSelect } = wp.data;

import placeHolder from "../place_holder.png";


// Registering A Block
registerBlockType('wpt/dynamic-block', {
    title: 'WPT Dynamic Block',
    category: 'custom-category',
    icon: 'rest-api',
    supports: {
        align: [ 'wide', 'full' ]
    },

    // Block Edit Function
    edit: withSelect(select => {
       //code for edit...
    });
        
    //Block Save Function 
    save: props => {
        return null;
    },
});

You may have noticed a couple of new things here, firs we are using a package name wp.data. This new package is the prime key to making the dynamic blocks. wp.datapackage has components that let use query WordPress to fetch the latest data.

The second major change is in editproperty which is completely changed, in the edit instead of using the props and arrow function we are using withSelectthat we have imported above from the wp.datapackage.

And the third change is saveproperty, in the, save we are not returning similar content like we have done till now instead we are returning and I know it may bring a lot of questions in your mind but more on this later in this article.

Another thing that we have done is imported this script file to our main index.js file which exists in the src folder.

I have yet not registered this new block in the PHP yet, because we need some extra things for that so we will do that later in this article, let’s just continue without it for now.

Run the Query

Now let’s see how we can run the query to fetch the post from WordPress. To run the GET query inside the editparameter we will run it inside withSelectfunction and return the value like shown in the code below.

 edit: withSelect(select => {
        return{
            // Send a GET query to the REST API.
            posts: select( "core" ).getEntityRecords( "postType", "post", {
                categories: 2, //category id
                per_page: 1 //number of post
            })
        };

    })(({posts, className})=>{
        
}),

In the code above you can see we are sending a GET query to WordPress REST API to fetch the post with category id 2 (if you don’t know how to get category id check below paragraph)and limiting the number of results per page to 1, to get the only latest post of that category. Then we are calling a function with two parameters postand className. The postwill contain the post data and the classNamewill have the classes for the block.

You maybe don’t know how to get a category id if you have never worked with WordPress REST API before since in the category tab the id isn’t added. To check the category go to the categories page and click on the category you want to get the id  and then check the URL bar of the category page you’ll see the category&tag_IDas highlighted in the image.

After that, we will process the post we get from querying as shown below.

// Wait for posts to be returned.
if ( !posts ) {
    return "Loading...";
}

// If no posts are returned.
if ( posts && posts.length === 0 ) {
    return "No posts";
}

// Grab the first post.
const post = posts[0];

console.log( post );

First, we will check if the post didn’t loaded yet then show the loading text.

Process the Query Result

After when we get the post we will check if the post has data and not if its length is equal to zero means no post found. In that case, we will return “No posts” on the front end as shown in the image above.

If the length of the post is more than zero means the post exists and we will save the post in a new post variable.

Then we will log the post variable to see check the returned object. If you have worked with APIs before you’ll know how the API responds, we can use this as a reference to point to the specific value to render in the block below.

Use the Result

Now we will return the JSX object to actually render the block in the block editor, but we won’t be adding editable content in the edit function because the content will be fetched from WordPress itself so the editing option is meaningless and defeats the purpose of having a dynamic block.

For the dynamic block, the user can only change the styling of the block, not the content of the block, for example, we can give a styling option for block alignment like we have done in our example by giving the option to choose the wide or full length for the block.

Now let’s look at our return JSX in the code below:

<div className={`${className} container`}>
    <article className="singleArticle">
    <div className="cover">
        <img src={placeHolder} alt="Cover Image"/>
    </div>
    <div className="content">
        <h2>{post.title.rendered}</h2>
        <p><RichText.Content value = {post.excerpt.rendered}/></p>
    </div>
    </article>
</div>

As you can see in the code above, we have a basic post layout. We have added the classNamewe are getting from the query in our main container. After that in the image src, we will use the placeHolderimage we have imported above. If you are wondering why not we are passing the image URL from postwe are fetching above because the post doesn’t have a featured image, will explain more later.

After that in the heading, we will pass the post title which we will get from the postvariable. In the post, variable title exists in post.title.rendered, notice we are using rendered value not the raw because we want the rendered version on the front end.

After that we have added the post excerpt in the paragraph tag, one thing you may notice is that we have used RichText.Contentcomponent and used the except value in it because even the rendered value is returning <p>tag and some ampersand value so I rapped in inside the RichText.Contentcomponent so the text will render as HTML.

And the rest is basic JSX syntax from which you are already familiar.

Save Parameter

//Block Save Function 
save: props => {
    return null;
},

Now let’s take a look at our saveparameter, as you can see above we have returned null in our saveparameter that is because we are don’t want to save data for block because the data will come from the query and returning null makes this clear to WordPress that it should not store any data for the block.

If you are wondering if we are not saving the block in save then how it will gonna be rendered on the front end, well it will be rendered on the front end with the help of PHP render callback.

PHP Render Callback

Till now we are using the save function to save and render the block for us but for the dynamic block, we can no longer use the save function because we want to render the block on the fly every time when the block gets visible. For that, we will use PHP render_callback,  if we use this callback WordPress will ignore everything written in savethat’s why as a reminder we should return null in the save function.

However, if we use nested block and then we might use some savefunction but that’s out of the scope of this article so let’s skip it for now.

Now let’s see the code for PHP render_callback:

function wpt_dynamic_render_callback( $attributes, $content ) {

global $post;

// Get the latest posts using wp_get_recent_posts().
$recent_posts = wp_get_recent_posts ( array(
    'category' => 2,
    'numberposts' => 1,
    'post_status' => 'publish',
) );

// Check if any posts were returned, if not, say so.
if ( 0 === count( $recent_posts ) ) {
    return 'No posts.';
}

// Get the post ID for the first post returned.
$post_id = $recent_posts[0]['ID'];

// Get the post object based on post ID.
$post = get_post( $post_id );

// Setup postdata so regular template functions work.
setup_postdata($post);

return sprintf(
    ' <div class="container %1$s">
        <article class="singleArticle">
        <div class="cover">
            %2$s
        </div>
        <div class="content">
            <h2>%3$s</h2>
            <p>%4$s</p>
        </div>
        </article>
    </div>',
    wpt_block_classes( $attributes ),
    wpt_post_img( $post ),
    esc_html( get_the_title($post) ),
    esc_html( get_the_excerpt($post) )
);

// Reset postdata to avoid conflicts.
wp_reset_postdata();

In the above code, we have a function called wpt_dynamic_render_callbackin that function, we have two parameters $attributesand $content. In $attributeswe will have the block styling attributes so if we add any class to style the block we will get it from $attributesthe content that will be used for the nested inner block so we can safely ignore it for now.

After that first, we have declared a global variable $postso we can store the post data in it and reference it easily.

global $post;

After that we have queried for the post, make sure this query is the same as the query we have in the block script file.

// Get the latest posts using wp_get_recent_posts().
$recent_posts = wp_get_recent_posts ( array(
    'category' => 2,
    'numberposts' => 1,
    'post_status' => 'publish',
) );

After running the query we will check if we got any post if not then we will return no post and if we do have a post we will continue.

// Check if any posts were returned, if not, say so.
if ( 0 === count( $recent_posts ) ) {
    return 'No posts.';
}

Then we will get the post id from the returned query result and will store that id in a new variable.

// Get the post ID for the first post returned.
$post_id = $recent_posts[0]['ID'];

Next, we will use that post id to get the post from the WordPress database and store that post inside the global variable we have created above.

// Get the post object based on post ID.
$post = get_post( $post_id );

Next, we will use setup_postdata()function so regular template functions work.

Now we will return the block output the same as our script page just change the inner value parameters as PHP syntax and the rest will stay the same.

return sprintf(
    ' <div class="container %1$s">
        <article class="singleArticle">
        <div class="cover">
            %2$s
        </div>
        <div class="content">
            <h2>%3$s</h2>
            <p>%4$s</p>
        </div>
        </article>
    </div>',
    wpt_block_classes( $attributes ),
    wpt_post_img( $post ),
    esc_html( get_the_title($post) ),
    esc_html( get_the_excerpt($post) )
);

As you can see we have used four placeholders in our return statement. In the first placeholder, we have passed the $attributeswhich we are getting from the function parameter. But instead of directly using that attribute we have first passed it in the function and then used its value. Because the $attributesis an array and sometimes it returns as null.

So in the function first we will check for the expected attribute, if it exists then we will add them in a single string variable and then return it so it will get passed in the PHP render_callbackreturn statement. You can see the function code below.

/**
 * Build classes based on block attributes.
 * Returns string of classes.
 * 
 * $attributes - array - Block attributes.
 */
function wpt_block_classes( $attributes ) {
    $classes = null;
    if ( isset($attributes['align']) ) {
        $classes = 'align' . $attributes['align'] . ' ';
    }

    if ( isset($attributes['className']) ) {
        $classes .= $attributes['className']; 
    }

    return $classes;
}

In the second parameter, we are passing the featured image URL, but sometimes posts don’t have the featured image so we need to check if the featured image exists and handle the possibilities.

For that, we will also create a function to check if $posthave a featured image URL, if it has then we will return the URL and if it doesn’t have the featured image then we will pass the placeholder image. You can see the function below:

/**
 * Serve up featured image is available, otherwise serve up logo.
 * Returns <img> element.
 * 
 * $post - object - The post object.
 */ 
function wpt_post_img( $post ) {
    $wpt_img = get_the_post_thumbnail( $post, 'wptFeatImg' );
    if ( empty( $wpt_img ) ) {
        $url = plugins_url( "src/place_holder.png", __FILE__ );
        $wpt_img = '<img src="' . $url . '" alt="Featured Imafge" />';
    }
    return $wpt_img;
}

For the third and fourth placeholder variables, we are using WordPress predefined functions to get the required value and convert the result into a proper format to render in the frontend.

esc_html( get_the_title($post) ),
esc_html( get_the_excerpt($post) )

And then, at last, we will call wp_reset_postdata()to reset the post data to avoid any conflicts.

Register the Block

The method of registering the Dynamic Block is slightly different from the normal block registration because this time along with registering the script and style we also need to register the render_callbackso the block will render via PHP renderer.

The code of registering the dynamic custom block is as shown below:

// Register dynamic block.
register_block_type( 'wpt/dynamic-block', array(
    'style' => 'style',
    'editor_script' => 'wpt-block',
    'render_callback' => 'wpt_dynamic_render_callback' //PHP Render Callback
) );

Now our custom dynamic block coding is complete, save all the code, and run the command npm run startand got to block editor add a new post in the category and add a dynamic custom block in your post or page and publish it. You’ll see your latest post in that block both in the editor and on the published page.

Get Featured Image in Block Editor

After running the above code and adding the block you may have noticed in our block editor only the placeholder image is loading and not the featured image. That is because the query we have run does not return the featured image URL. So let’s know how we can solve this issue.

To get the featured image we need to add a filter in our PHP file so when we run the GET query in the block script file along with post data we can also get the required feature image.

We will be using the code given below to achieve this functionality.

/**
 * Add the featured image to the REST API response.
 */
add_filter( 'rest_prepare_post', 'wpt_fetured_image_json', 10, 3 );

function wpt_fetured_image_json( $data, $post, $context ) {
    // Get the featured image id from the REST API response.
    $featured_image_id = $data->data['featured_media']; 

    // Get the URL for a specific image size based on the image ID.
    $featured_image_url = wp_get_attachment_image_src( $featured_image_id, 'full' ); // get url of the original size

    // If we have a URL, add it to the REST API response.
    if( $featured_image_url ) {
        $data->data['featured_image'] = $featured_image_url[0];
    }

    return $data;
}

In the above code, we are adding a filter so when we fetch the data above function will find the image id from the post, run the query to get the image of full size(you can select another size if you want), and then add that link as featured_imagein the query response as you can see in the logged object image below.

Now we just need to pass this image URL in our editfunction <img>src and now we will be seeing our post featured image in our editor as well.

<img src={post.featured_image} alt="Cover Image"/>

And with that our dynamic block is complete and fully functional in both block editor and published post/page.

As you can see in the above image, we are now getting our post feature image in the block editor as well.

Conclusion

Now we have learned from the basic hello world block to the custom dynamic block and with that our this article series is complete. I hope now you can make great custom blocks for yourself and your clients. If you have any questions, doubts, suggestions, or having trouble following this article or series comment your thoughts below we will respond to them as soon as possible.

Gutenberg is still developing and there will be more future iteration to it and it is possible after some time code the codes may change slightly however that is highly unlikely but if something doesn’t work share that in the comment section we will update the articles.

You can get the complete source code used in this article and in the complete series on my Github repo.

Also it series may have ended but there are a lot of things to learn and we keep writing more content regularly so make sure to bookmark our site and visit it regularly for more amazing articles and tutorials to be a better developer.

Have questions or confused about something WordPress Related? Join Our Discord Server & ask a Question

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top