If you are new to writing plugins for the WordPress Block Editor (Gutenberg), you may be a little confused how to do all the things you did regularly, like grabbing posts with WP_Query.

You will be very pleased to know that you can pretty much still do everything you used to do with WP_Query by using getEntityRecords.

For example, we can grab the latest posts by using the following bit of code:

wp.data.select( 'core' ).getEntityRecords( 'postType', 'posts' );

You can also query Custom Post Types (CPT) in the same way, as long as you have made your CPT accessible via the REST API.

wp.data.select( 'core' ).getEntityRecords( 'postType', 'my_custom_post_type' );

We can even pass in some arguments that may look sort of familiar:

wp.data.select( 'core' ).getEntityRecords(
	'postType', 
	'post', 
	{
        'status': 'draft', 
		'per_page': 2, 
	} 
);

You can find the definitive list of the arguments you can pass into the function here in the Gutenberg developer guide.

Try it in the Console

If you are logged into a site, and you are viewing the front end, you can test out pretty much any Gutenberg command. WordPress stores them all in the handy wp object.

Typing the above command into the console on one of my development sites I get the following:

Using getEntityRecords
Using getEntityRecords to grab posts in the Console

The screenshot above shows the console returning two WordPress post objects in the JavaScript, which are draft posts (as per the parameters I passed into getEntityRecords).

The JavaScript Post Object

Exploring the post object further in the console you can see there are plenty of properties returned for you to access.

id: 42
date: "2020-03-21T14:02:00"
date_gmt: "2020-03-21T14:02:00"
guid: {
	rendered: "https://wholesomecode.ltd/?p=42"
	raw: "https://wholesomecode.ltd/?p=42"
}
modified: "2020-03-21T14:02:00"
modified_gmt: "2020-03-21T14:02:00"
password: ""
slug: "wp-query-and-the-wordpress-block-editor-gutenberg"
status: "draft"
type: "post"
link: "https://wholesomecode.ltd/?p=42"
title: {
	raw: "WP_Query and the WordPress Block Editor (Gutenberg)"
	rendered: "WP_Query and the WordPress Block Editor (Gutenberg)"
}
content: {
	raw: "Content goes here."	
	rendered: "<p>Content goes here.</p>↵"
	protected: false
	block_version: 0
}
excerpt: {
	raw: ""
	rendered: "<p>Content goes here.</p>↵"
	protected: false
}
author: 1
featured_media: 101
comment_status: "open"
ping_status: "open"
sticky: false
template: ""
format: "standard"
meta: {
	_wcltd_meta_example_1: "1" 		
	_wcltd_meta_example_2: "Hello"
}
categories: [1]
tags: []
country: []
region: []
city: []
permalink_template: "https://wholesomecode.ltd/%postname%/"
generated_slug: "wp-query-and-the-wordpress-block-editor-gutenberg"

Post Meta in Gutenberg

One thing you will notice from the post object we explored above, is that all of the post meta is contained within the object in the meta property. This saves us doing the equivalent of get_post_meta() for this object in Gutenberg.

However if you do want to get the post meta for a single post object see the get_post_meta equivalent in Gutenberg article.

Getting the Image Details in Gutemberg

The post object you can get the featured media ID, which is stored in the featured_media property.

You can use getMedia (the WordPress Gutenberg equivalent of wp_get_attachment_image) to get the properties for this attachment.

The Gutenberg Post Loop

Lets expand the block created by the @wordpress/create-block script, that I wrote about previously to include an example of how to make the equivalent of a WP_Query loop in Gutenberg.

First we need to import the select() function from wp-data. We can do this by either referencing the NPM module:

import { select } from '@wordpress/data;

Or by using the wp object:

const { select } = wp.data;

We are going to stick with the practices used in the created block and use the NPM module, and use the @wordpress/data method.

Here is a basic implementation of the equivalent of a WP_Query loop in Gutenberg.

Featured Images

Note that featured images must be set for the latest two posts for this example to work correctly.

import { registerBlockType } from '@wordpress/blocks';
import { select, withSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';

registerBlockType( 'wholesomecode/wholesome-plugin', {
	title: __( 'Wholesome Plugin', 'wholesomecode' ),
	description: __( 'Just an Example Plugin', 'wholesomecode' ),
	category: 'common',
	icon: 'smiley',

	edit: withSelect( ( select ) => {
		const posts = select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': 2 } );
		let media = {};
		posts.forEach( post => {
			media[ post.id ] = select('core').getMedia( post.featured_media );
		});
		return {
			posts,
			media
		};
	} )( props => {

		const { media, posts } = props;

		if ( ! posts || ! media ) {
			return (
				<p>{ __( 'Loading...', 'wholesomecode' ) }</p>
			);
		}

		return (
			<ul>
			{ posts.map(
				( post ) => {
					if ( media[ post.id ] ) {
						const imageThumbnailSrc = media[ post.id ].media_details.sizes.thumbnail.source_url;
					return (
						<li>
							<img src={ imageThumbnailSrc } />
							<a href={ post.link }>
								{ post.title.raw }
							</a>
						</li>
					)
					}
				}
			) }
			</ul>
		);
	} ),

	save() {
		return (
			<p>
				{ __( 'Wholesome Plugin – Nothing to see here.', 'wholesomecode' ) }
			</p>
		);
	},
} );

Note the use of withSelect to pre-load the data before the block loads. You can find out more about withSelect by reading the Gutenberg documentation.

The above code outputs the following (very basic) example of an article list and their associated thumbnails in the editor:

Example Post Loop in Gutenberg
Example Post Loop in Gutenberg.

Using the REST API

If you would like to get custom data via the REST API check out my post on using the REST API with the WordPress Block Editor (Gutenberg).

Previous ArticleNext Article

This post has 12 Comments

12
    1. Agreed Denis, I would use withSelect as a high order component. I’ll write a tutorial about what those are and how to use them in the future.

      1. useSelect is preferred to withSelect because of clarity of code. See developers notice when they were introducing this hool.

        1. I think its a personal preference.

          I like to use withSelect as a wrapper to the component usually, but it’s been simplified in this example.

  1. Hi, following your article, I got:
    An error occurred while running ‘mapSelect’: null is not an object (evaluating ‘posts.forEach’)
    Any ideas?

    1. Hi Daniel,

      For this example to work, the featured image needs to be set on the posts you are pulling in.

      You may need to add some error checking in so that it does not fail if they are not set.

  2. Just stumbled upon your blog while looking for WP_Query help for Gutenberg. A quick glance and I can see you have lots of great content for Gutenberg implementations. Thanks a lot for sharing your knowledge!

    1. Thank you Per, and you are very welcome. There is still lots of content in the works too, so watch this space for more Gutenberg and WordPress development guides.

  3. Hey Matt,

    Just wondering if you knew a solution for using getEntitiyRecords for a non-logged in user on the frontend.

    Thanks for the great write up!

    1. Hi Aaron,

      I suppose you would have to adjust the user roles for your logged out users. Or you could create a custom REST API endpoint.

      It all depends on what you are using it for.

  4. Hi Matt,
    thanks for the great article.
    I would like to know how to write a save part to actually save the query and display it on the fron-end.

    1. In the edit script of your block you would use the query to return all the information you need, which then would be saved and outputted via the save method.

      However if you want the information returned by the loop to always be the latest on the front end, you will need to implement a dynamic block, with a PHP render.

      I hope that makes sense.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.