On my blog’s home page, there are two paragraphs about the posts I write and the projects I work on. Each of them includes a button that links to the archive for that type of post — posts for the blog, and projects, a custom post type, for projects — and a link to the last post of that type. Since I published my blog, I have been updating the home page each time I write a new post.

There is a block called Latest Posts which gave me the functionality I needed, except it does not have the option to display a custom post type, only categories. I could also have used the Query Loop block. But both blocks had the same issue: HTML output. In my design, last post is just a link inside an existing paragraph, and both Latest Posts and Query Loop blocks have an output which includes an unordered list. Query Loop also does not allow titles to have a tag different from a heading tag — h1
to h6
.
I made a custom block called Pinned Post, which outputs the title of the sticky post for a given post type or category, or the latest post if no post has been made sticky — if the checkbox with the label Stick to the top of the blog has been checked.

I will not be uploading it to the WordPress repository, mostly because it has little to offer in addition to the existing default blocks I mentioned. Although it passed the Block Plugin Checker test, surprisingly. But I created a public repository so anyone can check or use it.

WordPress has @wordpress/create-block
, a very helpful node package that creates all the files we need for our block — which is a plugin that uses React. The knowledge of React necessary to make a custom block is not as much as I thought, but knowing Javascript — including ES6 — and JSX is a must, so you should start with these before diving into React or Redux / @wordpress/data
.
We need to code two different implementations: one that will be used in the editor —
edit
— and another one that will be used in the frontend —save
. This is true for any block, even simple ones.
But if we want to develop a dynamic block, things get complicated: not only must we code two implementations, but we have to do it in two different languages. Why is that? Because the react implementation that fetches data using the REST API, is not meant to be used in the front, and will not work. So after implementing it using React for the editor, we have to make a PHP version to display the information on our frontend, bypassing the save
function, and creating a PHP function to call using render_callback
in our block registration.
I know, it sounds strange, but it is what it is.
On the PHP side, I would not make any comments, as it is easy to find documentation and examples. On the React side, some notes:
- Using
getEntityRecords
is super easy to retrieve any data. It is an improvement compared toWP_Query
, which is an unfair comparison, but let’s say that the new method has a better structure and makes more sense. - Once you get how the continuous refreshing works, using React and
@wordpress/data
is awesome for developers. And how data is saved and used may be hard to understand conceptually, but it is very easy to work with. - Implementing something like custom fields for our block options and customisation is incredibly easy. For example, having an
input
that will show on the sidebar for editing the title of our block, needs only this much code:
<InspectorControls key="setting">
<fieldset>
<TextControl
label="Title"
value={ attributes.title }
onChange={ onChangeTitle }
/>
</fieldset>
</InspectorControls>

And having fields that show conditionally — either a select
for categories or another one for post types is displayed based on the option chosen in another select — is as easy as:
{ attributes.queryType == 'category' && (
<SelectControl
label="Category"
value={ attributes.queryValue }
onChange={ onChangeQueryValue }
options={ categoriesListOptions }
/>
) }
{ attributes.queryType == 'postType' && (
<SelectControl
label="Post Type"
value={ attributes.queryValue }
onChange={ onChangeQueryValue }
options={ postTypesListOptions }
/>
) }
In conclusion, Pinned Post block was easier and more complicated to make than I anticipated, but thanks to the tools WordPress provides — including documentation — it has been a very positive learning experience. It was also probably not worth the hassle just to change the HTML output because WordPress provides hooks to customise how core blocks are rendered on our site; just having the functionality to choose a custom post type is not something many projects would need.