Handling _embed for custom REST API endpoints

by ccprog   Last Updated August 14, 2019 02:08 AM

I am preparing a plugin for REST API integration (the WP 4.7 core version) by providing custom endpoints for data from the plugin. One of the things I am trying to do is to set a _links property in the response and make the linked resource embeddable. Heavily simplified code excerpt:

class Clgs_REST_Logs extends WP_REST_Controller {
    const NSPACE = 'clgs';
    const BASE = 'logs';

    public function register_routes() {
        register_rest_route( self::NSPACE, '/' . self::BASE, array(
            array(
                'methods'   => WP_REST_Server::READABLE,
                'callback'  => array( $this, 'get_items' ),
             ),
            'schema' => array( $this, 'get_public_item_schema' ),
        ) );
        register_rest_route( self::NSPACE, '/' . self::BASE . '/count', array(
            array(
                'methods'   => WP_REST_Server::READABLE,
                'callback'  => array( $this, 'get_count' ),
            ),
            'schema' => array( $this, 'get_count_schema' ),
        ) );
    }

    public function get_items( $request ) {
        $log_entries = // get an array

        $collection = $this->prepare_collection_for_response( $log_entries, $request );
        $response = rest_ensure_response( array(
            'items' => $collection
         ) );

        $max_pages = max( 1, ceil( $total_items / (int) $params['per_page'] ) );

        $this->set_count_headers( $response, (int) $total_items, (int) $max_pages );

        $count_link =  $this->prepare_link_url( array( self::BASE, 'count' ) );
        $response->add_links( array (
            'count'  => array(
                'href' => $count_link,
                'embeddable' => true
            ),
        ) );

        return $response;
    }

    public function get_count( $request ) {
        // provide some statistics data
    }

    public function prepare_link_url ( $parts = array() ) {
        array_unshift( $parts, self::NSPACE );
        return rest_url( implode( '/', $parts ) . '/' );
    }
}

A response to a request http://wptesting.intern/index.php/wp-json/clgs/logs/?_embed looks like this:

{
    "items": [...],
    "_links": {
        "count": [{
            "embeddable": true,
            "href": "http://wptesting.intern/index.php/wp-json/clgs/logs/"
        }]
    },
    "_embedded": {
        "count": [{
            "code": "rest_no_route",
            "message": "No route was found matching the URL and request method",
            "data": {"status":404}
        }]
    }
}

Requests to http://wptesting.intern/index.php/wp-json/clgs/logs/count/, if done separately, succeeds.

I have done this additionally with pretty premalinks disabled and http://wptesting.intern/index.php/?route=... to be sure this is not a routing rewrite issue, and the same thing happens.

Has anyone an idea why the embedding fails?

Tags : rest-api


Answers 1


The slash at the end is the culprit. While real requests with a / at the end of the route get wp_unslash()ed before resolving, the links for embeds do not.

So,

    public function prepare_link_url ( $parts = array() ) {
        array_unshift( $parts, self::NSPACE );
        return rest_url( implode( '/', $parts ) );
    }

does the trick.

ccprog
ccprog
January 08, 2017 01:36 AM

Related Questions


Updated February 16, 2016 00:15 AM

Updated February 19, 2016 02:03 AM

Updated March 03, 2016 01:03 AM

Updated March 20, 2016 08:03 AM

Updated March 05, 2016 01:03 AM