- Custom route pagination
- CORS
Adding Pagination to custom routes
So, the deault routes have query paramters like page and per_page to handle pagination, we can also that in out route.
When we send request to a builtin route like wp/v2/posts , in the headers we get two headers for pagination :
| X-WP-Total | no. of total pots |
| X-WP-TotalPages | total pages |
So, in order to make our rest api also similar we can expose these headers and also allow the paramters page and per_page for this.
This is the code I have written.
function resgister_celebs_route() {
register_rest_route(
'/rt-movies/v1/',
'/celebs',
array(
'methods' => 'GET',
'callback' => 'celebs_route_callback',
'args' => array(
'page' => array(
'type' => 'integer',
'description' => 'Page Number',
),
'per_page' => array(
'type' => 'integer',
'description' => 'Number of posts per page',
'default' => 10,
),
),
)
);
}
add_action( 'rest_api_init', 'resgister_celebs_route' );
This is code of the function that will handle our pagination
function celebs_route_callback( WP_REST_Request $request ) {
$request_params = $request->get_query_params();
$default_params = array(
'page' => 1,
'per_page' => 10,
);
$params = wp_parse_args( $request_params, $default_params );
$args = array(
'post_type' => 'rt-celebs',
'posts_per_page' => $params['per_page'],
'paged' => $params['page'],
);
$query = new WP_Query( $args );
$posts = $query->get_posts();
$total_posts = $query->found_posts;
$total_pages = ceil( $total_posts / $params['per_page'] );
// Return 400 if page number if greater than total pages
if($params['page'] > $total_pages){
return new WP_Error( 'invalid_page_number', 'Invalid page number', array('status' => 400 ) );
}
// Prepare the response.
$response = new WP_REST_Response();
$response->set_data( $posts );
$response->header( 'X-WP-Total', count( $posts ) );
$response->header( 'X-WP-TotalPages', $total_pages );
return $response;
}
Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.
MDN
So basically, browsers follow same-origin policy , means if your web app tries to make request to an api on a differetn domain, it will not work.
But what if the request is necessary, like you have a decoupled architecture and hosted multiple api on different domains and for frontend the domain is different. For that we have to allow CORS
It work by HTTP headers mechanism, means we can set header that tell the browser that this specific domains CORS are allowed
here are the HEADERS used in CORS
Access-Control-Allow-Origin: https://myapi.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
To use this in wordpress, we can hook into the pre server request and update the header.
function set_cors_headers($value) {
header( 'Access-Control-Allow-Origin: *' );
return $value;
}
add_filter( 'rest_pre_serve_request', 'set_cors_headers', 999 );
Why the priority is set 999, well ther is a function in rest-api.php named rest_send_cors_headers() which also set the cors headers but it sets so that all origin request are allowed.
So we have to make sure that our function runs after that
Why not just unhook the function and use our own? , yes it is also possible to do.
Restricting API access to only one host
function restrict_api() {
$allowed_host = 'getit.local';
if ( isset( $_SERVER['HTTP_ORIGIN'] ) && $_SERVER['HTTP_ORIGIN'] === $allowed_host ) {
header( "Access-Control-Allow-Origin: $allowed_host" );
} else {
wp_send_json_error( array( 'message' => 'Requests not allowed from this host' ), 403 );
exit;
}
}
add_action( 'rest_api_init', 'restrict_api' ,9999);
Leave a Reply