Question

I'm trying to use a custom endpoint (basically to get a random sorting working) and am using the following code:

// Custom WP API endpoint
function theme_enable_random_api() {

    // create json-api endpoint

    add_action('rest_api_init', function () {

        // http://example.com/wp-json/random/v2/posts

        register_rest_route('random/v2', '/random', array (
            'methods'             => 'GET',
            'callback'            => 'wp_json_offers_v2__posts',
            'permission_callback' => function (WP_REST_Request $request) {
                return true;
            }
        ));
    });

    // handle the request

    function wp_json_offers_v2__posts($request) {
        // json-api params

        $parameters = $request->get_query_params();

        // default search args

        $args = array(
            'post_type'     => $parameters['type'],
            'numberposts'   => 9,
            'offset'        => $parameters['offset'],
            'post_not_in'       => $parameters['exclude'],
            'orderby'       => 'rand',
        );

        // run query

        $posts = get_posts($args);

        // return results
        return new WP_REST_Response($posts, 200);
    }

}

add_action('init', 'theme_enable_random_api');

However the response I'm getting is not the same as the response I would get from a standard call to the api.

Standard:

Custom Endpoint:

The problem really is that I can't access the taxonomy/acf information like I can in the standard one. I'm not great with PHP so more than likely I'm not getting it properly.

Cheers.

Was it helpful?

Solution

You can call the REST API methods to prepare your output in the same way that the plugin does by default, this will also allow any plugins to tie into the output as you have used the ACF plugin as seen in your example output.

The WP_REST_Posts_Controller class has the following in its get posts method

$posts_query = new WP_Query();
$query_result = $posts_query->query( $query_args );

$posts = array();
foreach ( $query_result as $post ) {
    if ( ! $this->check_read_permission( $post ) ) {
        continue;
    }

    $data = $this->prepare_item_for_response( $post, $request );
    $posts[] = $this->prepare_response_for_collection( $data );
}

So you could instantiate a new WP_REST_Posts_Controller instance and call the prepare_item_for_response and prepare_response_for_collection methods on your data to format it identically to the default endpoints.

Something similar to the following should work (untested)

function wp_json_offers_v2__posts($request) {
    // json-api params

    $parameters = $request->get_query_params();

    // default search args

    $args = array(
        'post_type'     => $parameters['type'],
        'numberposts'   => 9,
        'offset'        => $parameters['offset'],
        'post_not_in'       => $parameters['exclude'],
        'orderby'       => 'rand',
    );

    // run query

    $posts = get_posts($args);

    $controller = new WP_REST_Posts_Controller($parameters['type']);

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

    // return results
    return new WP_REST_Response($posts, 200);
}

OTHER TIPS

The accepted answer was helpful. Thanks. But prepare_item_for_response() method was deprecated since v.3.0, so, hope this snippet will help someone with a custom endpoint for WC Orders.

    // Parse all others params
    $args = wp_parse_args( $request->get_params(), $args );

    // Get orders
    $orders = wc_get_orders( $args );

    if ( ! empty( $orders ) && is_array( $orders ) ) {
        $controller = new WC_REST_Orders_Controller ();

        // The response data
        $orders_data = [];
        // We need prepare objects to the response
        foreach ( $orders as $order ) {
            if ( $order instanceof WC_Order ) {
                // Objects
                $prepared_object = $controller->prepare_object_for_response( $order, $request );
                $orders_data[]   = $controller->prepare_response_for_collection( $prepared_object );
            } else {
                // IDs
                $orders_data[] = (int) $order;
            }
        }

        // Return the response
        return new WP_REST_Response( $orders_data, 200 );

    }

The above answer forgot to set a new array variable. Once you add that it works great.

function get_all_posts($request)
{
    $posts = get_posts([
        'posts_per_page' => -1,
        'post_status' => 'publish'
    ]);

    $controller = new WP_REST_Posts_Controller('post');

    $array = [];

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

    return $array;
}

Output looks just like the normal api response.

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top