Custom endpoint and X-WP-TotalPages (headers)

I have a custom endpoint defined like so:

    add_action( 'rest_api_init', function () {
        register_rest_route( 'menc/v1', '/crosscat/(?Pdept[\w-]+)/(?Pcat[\w-]+)', array(
            'methods' = 'GET',
            'callback' = 'dept_cat_api',
            'args' = array(
                'dept' = array(
                    'sanitize_callback' = function($param, $request, $key) {
                        return sanitize_text_field( $param );
                    }
                ),
                'cat' = array(
                    'sanitize_callback' = function($param, $request, $key) {
                        return sanitize_text_field( $param );
                    }
                ),
                'per_page' = array(
                    'default' = 10,
                    'sanitize_callback' = 'absint',
                ),
                'page' = array(
                    'default' = 1,
                    'sanitize_callback' = 'absint',
                ),
                'orderby' = array(
                    'default' = 'date',
                    'sanitize_callback' = 'sanitize_text_field',
                ),
                'order' = array(
                    'default' = 'desc',
                    'sanitize_callback' = 'sanitize_text_field',
                ),
            ),
        ) );
    } );

    function dept_cat_api( $request ) {
        $args = array(
            'post_type' = 'post',
            'tax_query' = array(
                'relation' = 'AND',
                array(
                    'taxonomy' = 'crosspost',
                    'field'    = 'slug',
                    'terms'    = array( $request['dept'] ),
                ),
                array(
                    'taxonomy' = 'category',
                    'field'    = 'slug',
                    'terms'    = array( $request['cat'] ),
                ),
            ),
            'per_page' = $request['per_page'],
            'page' = $request['page'],
            'orderby' = $request['orderby'],
            'order' = $request['order']
        );

        $posts = get_posts( $args );

        if ( empty( $posts ) ) return new WP_Error( 'no_posts', 'Invalid term(s)', array( 'status' = 404 ) );

        $controller = new WP_REST_Posts_Controller('post');

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

// return results
        return new WP_REST_Response($data, 200);

    }

Remotely I'm having a problem. When I call the route everything seems fine with the content, however both X-WP-TotalPages and X-WP-Total return empty responses.

    object(Requests_Utility_CaseInsensitiveDictionary)#991 (1) {
      ["data":protected]=
      array(20) {
        ["server"]=
        string(5) "nginx"
        ["date"]=
        string(29) "Wed, 14 Jun 2017 14:07:51 GMT"
        ["content-type"]=
        string(31) "application/json; charset=UTF-8"
        ["content-length"]=
        string(6) "104787"
        ["expires"]=
        string(29) "Thu, 19 Nov 1981 08:52:00 GMT"
        ["pragma"]=
        string(8) "no-cache"
        ["x-robots-tag"]=
        string(7) "noindex"
        ["link"]=
        string(65) "; rel="https://api.w.org/""
        ["x-content-type-options"]=
        string(7) "nosniff"
        ["access-control-expose-headers"]=
        string(27) "X-WP-Total, X-WP-TotalPages"
        ["access-control-allow-headers"]=
        string(27) "Authorization, Content-Type"
        ["allow"]=
        string(3) "GET"
        ["x-cacheable"]=
        string(5) "SHORT"
        ["vary"]=
        string(22) "Accept-Encoding,Cookie"
        ["cache-control"]=
        string(28) "max-age=600, must-revalidate"
        ["accept-ranges"]=
        string(5) "bytes"
        ["x-cache"]=
        string(6) "HIT: 1"
        ["x-pass-why"]=
        string(0) ""
        ["x-cache-group"]=
        string(6) "normal"
        ["x-type"]=
        string(7) "default"
      }
    }

Ideally I need both populated, but I could make do with one. I assumed WordPress calculated/populated these via the controller. Do I have to populate them manually? Have I done something incorrectly? Am I experiencing a bug?

Topic wp-api headers Wordpress

Category Web



$posts = $query->get_posts();

$total_posts = $query->found_posts;
$max_pages = $query->max_num_pages;
$returned =  new WP_REST_Response($posts, 200);
$returned->header( 'X-WP-Total', $total_posts );
$returned->header( 'X-WP-TotalPages', $max_pages );
return $returned;

Where should I put it ? In rest-api.php ?


Based on the answer above, I used this code, It works for me.

$query = new WP_Query(array());

$posts = $query->get_posts();

$total_posts = $query->found_posts;
$max_pages = $query->max_num_pages;
$returned =  new WP_REST_Response($posts, 200);
$returned->header( 'X-WP-Total', $total_posts );
$returned->header( 'X-WP-TotalPages', $max_pages );
return $returned;

I had a quick look and here's how the headers are set in the WP_REST_Posts_Controller::get_items() method:

$response  = rest_ensure_response( $posts );
// ...
$response->header( 'X-WP-Total', (int) $total_posts );
$response->header( 'X-WP-TotalPages', (int) $max_pages );
// ...
return $response;

where:

$total_posts = $posts_query->found_posts;

and we could use as @jshwlkr suggested:

$max_pages = $posts_query->max_num_pages;

You could emulate that for your custom endpoint, by using WP_Query instead of get_posts().

Thanks to @DenisUyeda for correcting the typo.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.