0

I'd like to get a post object from a custom REST endpoint within a Gutenberg block. The REST endpoint returns as part of its JSON payload an array with a "post" key which contains the contents of the WP_Post PHP object to return. Normally I'd get posts with getEntityRecords and withSelect in the block's JavaScript:

    // ...within gutenberg block...
    edit: withSelect( ( select, props ) => {
        const { attributes } = props;
        const { getEntityRecords, getPostType } = select( 'core' );

        const query = {
            post_id: 5, // this is made up!
        };

        return {
            children: getEntityRecords( 'postType', 'post', query )
        };
    } )( edit ),

...but this seems to only work for the standard WordPress posts REST endpoint. How can I get a post object from a custom REST endpoint within a Gutenberg block? Ideally I'd like to get a post in a form that looks identical to one retrieved using getEntityRecords.

1

(Revised answer to properly address the questions in the question..)

For Question 1 (JS)

How can I get a post object from a custom REST endpoint within a Gutenberg block?

So there's the apiFetch() which you can use to fetch resources from the REST API.

But unlike return { children: getEntityRecords() }, return { children: apiFetch() } won't work because apiFetch() always returns a Promise instance — getEntityRecords() always returns an object/array upon successful API request (and that the response is actually good).

So specifically if you want that to work with withSelect(), then you can add your endpoint as an entity:

  1. So in PHP, you can register a custom endpoint like so:

    register_rest_route( 'my-namespace/v1', 'posts', array( ...your args... ) )
    
  2. And in Gutenberg, you can add it as an entity like so:

    var dispatch = wp.data.dispatch;
    dispatch( 'core' ).addEntities( [
        {
            name: 'posts',           // route name
            kind: 'my-namespace/v1', // namespace
            baseURL: '/my-namespace/v1/posts' // API path without /wp-json
        }
    ]);
    

And then in your custom block:

// Used with withSelect():
return {
    children: select( 'core' ).getEntityRecords( 'my-namespace/v1', 'posts' )
}

For Question 2 (PHP)

I'd like to get a post in a form that looks identical to one retrieved using getEntityRecords.

  1. You can create your very own controller class.

  2. Or maybe extend the WP_REST_Posts_Controller class (which is used with the standard posts routes like wp/v2/posts).

  3. Or just make use of the prepare_item_for_response() and prepare_response_for_collection() methods in WP_REST_Posts_Controller. These two methods can be used to return a list of posts.

Basic example for the third option (in actual implementation, you may want to add authorization/permissions check and/or accept custom parameters like per_page):

class My_REST_Posts_Controller {

    public function __construct() {
        $this->namespace     = '/my-namespace/v1';
        $this->resource_name = 'posts';
    }

    public function register_routes() {
        register_rest_route( $this->namespace, '/' . $this->resource_name, array(
            array(
                'methods'  => 'GET',
                'callback' => array( $this, 'get_items' ),
            ),
        ) );
    }

    public function get_items( $request ) {
        $post_type = 'post'; // or this can be defined as a property in the class
        $posts = get_posts( array(
            'post_type' => $post_type,
        ) );

        $data = array();

        if ( empty( $posts ) ) {
            return rest_ensure_response( $data );
        }

        // Here we make use of the default controller class.
        // Remember that only a single post type is supported.
        $class = new WP_REST_Posts_Controller( $post_type );

        foreach ( $posts as $post ) {
            $response = $class->prepare_item_for_response( $post, $request );
            $data[] = $class->prepare_response_for_collection( $response );
        }

        return rest_ensure_response( $data );
    }
}
  • Thanks, but I'm not actually looking for a special post type - I want to get data (which happens to be a WP_Post) from a custom REST endpoint. I just want the WordPress JSON library to treat what it gets from this custom REST endpoint as if it had come from getEntityRecords, i.e. a post object. – Sean Nov 13 at 18:50
  • Does the updated answer help? – Sally CJ Nov 13 at 19:14
  • Hmm. The custom REST endpoint returns a JSON array with the WP_Post object. I just want to grab that in JavaScript using whatever mechanism is recommended for doing that for within a Gutenberg block. I guess it comes down to: how do I get post data from a custom REST endpoint and parse it in a way that it resembles a post retrieved using getEntityRecord? – Sean Nov 13 at 19:31
  • 1
    Actually, there is.. see updated answer. – Sally CJ Nov 13 at 23:25
  • 1
    Thanks a lot for updating your answer again to make it even clearer. The difference between the promise returned by apiFetch and getEntityRecord was confusing so it's good to have an explanation of the difference here. Much appreciated! – Sean Nov 18 at 9:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.