How to Make a WordPress Block that Displays Post Meta

WordPress Context-Based Data in Your Blocks Cover Image

One of the unique and interesting challenges that arises when developing new block types for WordPress sites is getting access to post-specific data from the database in your block. Access to this data is needed both on the user-facing frontend, where visitors will see your posts, and on the editor backend, where post authors write their content, in order to maintain WYSIWYG (What You See Is What You Get) block editor principle.

The Secret Sauce: Context

Experienced developers know, however, that a post author does not always want to get data pertaining to the current post they are editing. There are times, such as within a query loop, that you want to output information about another post within your block. This is where the crucial concept of context comes into play.

The context a block is placed in within a post can be thought of as the “environment” or “situation” of the block. For instance, when you place a “Post Title” block as a direct child of the post, it has a default context. Accordingly, it will perform default behavior, which means it will get the title of the currently edited/viewed post. Since this is a WordPress site, I will demonstrate. The block below is a Post Title block, and it has been placed in the default context:

How to Make a WordPress Block that Displays Post Meta

As you can see, it has automatically used the title of this post for its content. Now, let’s look at the same block in a different context:

In the editor

To get access to post meta in the post editor, their are a few prerequisites before actually working on the block. Firstly, if you are developing a block for a custom post type, both the post type and any meta you would like access to in the editor must be published and accessible in the WordPress REST API. To accomplish this, ensure your custom post type supports custom fields, and ensure you set the show_in_rest arg to true in your call to register_post_type:

register_post_type('POST_TYPE_NAME', array(
    ...
    'supports' => array('custom-fields', ...),    //show the post type's meta in the WordPress REST API 

    'show_in_rest' => true,    //show the post type in the WordPress REST API
    ...


));

This will allow the editor to use the WordPress REST API to get data about the custom post type. Then, when registering post meta, set an identical arg when calling the register_post_meta function:

register_post_meta('POST_TYPE_NAME', 'POST_META_NAME', array(
    'show_in_rest' => true,    //show this post meta in the WordPress REST API

    ...
));

Now, the post type and meta attributes will appear in the API. Next, we need to add support for context-based data to our block. To do this, modify the block’s block.json file like so:

{

    "usesContext": [ "postType", "postId" ],
    ...

}

This will provide the block content in the block editor with the post type and the post id of the post referred to in the block’s context. To make use of this data, use the object passed in to the edit function in edit.js, props.context.

export default function Edit(props) {
    console.log(props.context.postType)
    console.log(props.context.postId)
}

This will log the post type and the post id of the post in context. We can use these two pieces of context data to access other pieces of post data using WordPress’ useSelect hook.

import { useSelect } from '@wordpress/data';

This hook allows the retrieval of props from registered selectors. Use it like this:

const post_meta = useSelect((select) => {
    const { getEditedEntityRecord } = select('core');
    const record = getEditedEntityRecord('postType', props.context.postType, props.context.postId);
    return record.meta;
})

This code uses the getEditedEntityRecord function to retrieve a record about a particular post. We specify an attribute to get the post by, in this case, postType, and then we supply the post type and post id from the context. This data includes the post title, author id, post meta, and more. This particular call is concerned with the post meta. By returning the record’s meta attribute, we get access to a JavaScript object containing all the post meta attributes, which we can then use to add post-specific data to the block’s editor-side contents. This object can be used to output the content of post meta in the editor.

Why is this so important? In the WordPress block editor, a paradigm that developers are supposed to uphold is the WYSIWYG principle. This means, “What You See Is What You Get”, and what that means is that what you see in the block editor should look exactly the same as the output will look on the frontend of the site.

This means that the actual values of post meta and other post attributes need to be outputted within the block editor, because these are the values that will be outputted on the frontend. So, now that we know how to get access to this data in the block editor, let’s move on to part two: getting the post metadata on the frontend of the site.

On the frontend

There are a couple ways to determine a block’s output on the frontend of a WordPress site. One of these is using the save.js file. This file is written very similarly to the edit.js file, and, in fact, all post metadata can be gotten in the exact same way, using the method previously described for the edit.js file. So simply repeat the code from the previous section in the save.js file if you decide to use it to generate your frontend content.

The other method of outputting block content on the frontend is using the render.php file. This file uses php to dynamically generate a whenever a visitor visits the site. Fortunately, since this file is written in php, we can use all the handy built-in functionality that WordPress provides to grant us access to the post data in the current context.

One way to get access to post data from the context post is by using the global $post object. Here is an example of checking the post type, and getting some of the post meta using this object:

<?php
global $post;
if ($post->post_type != 'page'){
    echo get_post_meta($post->ID, 'META_KEY', true);
}
?>

This code uses the global $post object, which is automatically defined and updated by WordPress, to check the current post type. If it is a page, it echoes out the “META_KEY” meta attribute to the page, causing it to appear when a user visits this page.

WordPress also provides utility functions, such as get_the_title(), get_the_content(), get_the_author(), and get_the_ID(). These are wrappers that use the global $post object under the hood. It is generally recommended to use these instead of accessing the global object directly.

Summary

In summary, we began by learning about the concept of context in the, well, context of WordPress Block Development. Context determines which post record in the database WordPress will pull data from when generating a block. The example of the Post Title block was used to show how the same block in the same post can show different content based on the context it is placed in. When in the post body, it showed this post’s title, but when contained within a query loop, it showed the title of the article dictated in the loop.

Then, we turned our attention to how we could replicate this functionality of the Post Title block within our own custom blocks. The method for getting context post data in the block editor used the usesContext attribute of the block.json file along with the useSelect hook to get post data from the REST API. Meanwhile, on the frontend, the php helper functions can be used to get post attributes when rendering blocks to the frontend.

Conclusion

So now, you know how to develop your own WordPress blocks with context-based access to post metadata. I wrote this guide because I searched for hours upon hours for how to do this in my own project, and found nothing! So, I hope this guide has proven useful to you and helped you in your block development endeavours!

Click to read more about my other WordPress Development ventures!

Comments

Leave a Reply

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