(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:
-
So in PHP, you can register a custom endpoint like so:
register_rest_route( 'my-namespace/v1', 'posts', array( ...your args... ) ) -
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
usinggetEntityRecords.
-
Or maybe extend the
WP_REST_Posts_Controllerclass (which is used with the standard posts routes likewp/v2/posts). -
Or just make use of the
prepare_item_for_response()andprepare_response_for_collection()methods inWP_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, "https://wordpress.stackexchange.com/" . $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 );
}
}