I have a custom endpoint where I want to change HTTP response status to 404 in certain scenarios (e.g post does not exist). How can I do that? Here is an example of custom endpoint:

function af_news_single( \WP_REST_Request $data ) {
    global $wpdb;

    $year = (int) $data['year'];
    $month = (int) $data['month'];
    $day = (int) $data['day'];
    $slug = $data['slug'];

    $date = "{$year}-{$month}-{$day}";

    $news = $wpdb->get_row(
                DATE_FORMAT(post_date, %s) as `post_date`,
             FROM {$wpdb->posts}
                `post_status` = 'publish' AND
                `post_type` = 'post' AND
                `post_name` = %s AND
                `post_date` BETWEEN %s AND %s + INTERVAL 1 DAY
             LIMIT 1
             ", '%Y-%m-%dT%TZ', $slug, $date, $date

    if ( $news ) {
        $news->post_title = qtranxf_translate( $news->post_title );
        $news->post_content = wpautop( qtranxf_translate( $news->post_content ) );
    } else { /* How to change response code? */ }

    return [ 'data' => $news ];

How can I change response code in this function?


3 Answers 3


You can return a WP_Error object in which you define the status code. Here's a snippet from the REST API documentation:

function my_awesome_func( $data ) {
    $posts = get_posts( array(
        'author' => $data['id'],
    ) );

    if ( empty( $posts ) ) {
        return new WP_Error( 'awesome_no_author', 'Invalid author', array( 'status' => 404 ) );

    return $posts[0]->post_title;

In your case you could do something like:

return new WP_Error( 'page_does_not_exist', __('The page you are looking for does not exist'), array( 'status' => 404 ) );
  • 1
    Now how do I resist the temptation to make all failed API calls return the status 418 I'm a teapot?
    – Pat J
    Commented Oct 1, 2021 at 17:19

The simplest way is to do this:

return new WP_REST_Response(null, 404);

Note: this is still a JSON response containing null as the body. You can return a more useful data structure with error codes/messages, etc., or hook into the REST output filters to output a blank text/plain response.


I would not use:

return new WP_REST_Response(null, 404);

I had an issue with hosting provider when I used status codes in this function. Somehow setting status code triggered mod_rewrite response.

Message: Access denied with code 406 (phase 3). Test 'REQUEST_URI|REQUEST_HEADERS|REQUEST_HEADERS_NAMES|ARGS|ARGS_NAMES|REQUEST_BODY' against '!@validateByteRange 0-31' is true.

It might not be and issue with wordpress but using:

return new WP_REST_Response(null);

solved the problem.

I'll just leave it here in case anyone encounters same problem.

  • Sorry, but this does not answer the question at all. WP_REST_Response extends the WP_HTTP_Response class, and the second argument to the constructor controls the status code. If you omit it, you are not changing the status code, which is the problem at hand.
    – Walf
    Commented Oct 23, 2023 at 3:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.