34

I am starting a bit with the REST API. If I am not completly mislead, the init action hook is also executed when its a REST API request. Now, I want to execute some code only, when it is not a REST API request.

So I was looking for a command like is_rest() in order to do something like

<?php
if( ! is_rest() ) echo 'no-rest-request';
?>

But I couldn't find something like this. Is there a is_rest() out there?

2
  • 1
    Maybe you can elaborate on what you want to do when it's not a REST request? The type of request isn't determined until query parsing, which happens after init. Also note that the parts of the API can be used internally on requests that aren't REST requests, so you risk breaking something if you are relying on that detection.
    – Milo
    Commented Mar 20, 2016 at 16:39
  • Thanks a lot you both. @birgire: Can you post this as an answer, so I can check it. Basically, it is the answer to my question :) Commented Mar 21, 2016 at 6:58

8 Answers 8

22

It's a good point by @Milo, the REST_REQUEST constant is defined as true, within rest_api_loaded() if $GLOBALS['wp']->query_vars['rest_route'] is non-empty.

It's hooked into parse_request via:

add_action( 'parse_request', 'rest_api_loaded' );

but parse_request fires later than init - See for example the Codex here.

There was a suggestion (by Daniel Bachhuber) in ticket #34373 regarding WP_Query::is_rest(), but it was postponed/cancelled.

1
  • 3
    #42061 might add wp_is_rest_request() or wp_doing_rest().
    – Ian Dunn
    Commented Mar 10, 2020 at 19:40
22

Just stumbled over the same problem and wrote a simple function is_rest that allows you to check if the current request is a WP REST API request.

<?php

if ( !function_exists( 'is_rest' ) ) {
    /**
     * Checks if the current request is a WP REST API request.
     *
     * Case #1: After WP_REST_Request initialisation
     * Case #2: Support "plain" permalink settings and check if `rest_route` starts with `/`
     * Case #3: It can happen that WP_Rewrite is not yet initialized,
     *          so do this (wp-settings.php)
     * Case #4: URL Path begins with wp-json/ (your REST prefix)
     *          Also supports WP installations in subfolders
     *
     * @returns boolean
     * @author matzeeable
     */
    function is_rest() {
        if (defined('REST_REQUEST') && REST_REQUEST // (#1)
                || isset($_GET['rest_route']) // (#2)
                        && strpos( $_GET['rest_route'], '/', 0 ) === 0)
                return true;

        // (#3)
        global $wp_rewrite;
        if ($wp_rewrite === null) $wp_rewrite = new WP_Rewrite();
            
        // (#4)
        $rest_url = wp_parse_url( trailingslashit( rest_url( ) ) );
        $current_url = wp_parse_url( add_query_arg( array( ) ) );
        return strpos( $current_url['path'] ?? '/', $rest_url['path'], 0 ) === 0;
    }
}

References:

3
  • I didn't get what #3 did.
    – kodfire
    Commented Jun 20, 2022 at 8:43
  • This is the best function for wordpress ever written on stackoverflow. Needed to use this for a pre_get_posts hook that ignores rest requests and worked like a charm.
    – Philip
    Commented Jan 25, 2023 at 8:12
  • Ah! Now I understand what's wrong with a popular plugin who copied your 2018 code but never caught the (very important) change you made in 2022! Well done :-) Thanks for the update! Commented Sep 24, 2023 at 11:28
13

If you need it after init has fired:

defined('REST_REQUEST') && REST_REQUEST

If you need it before init, there are two ways:

Use wp_is_json_request() (Introduced in WordPress 5.0), or try to infer if it's a REST Request through the URL. Detecting the URL will vary whether the site is using permalinks or plain permalinks.

WooCommerce does it like this, and it's a good solution:

function is_rest_api_request() {
    if ( empty( $_SERVER['REQUEST_URI'] ) ) {
        // Probably a CLI request
        return false;
    }

    $rest_prefix         = trailingslashit( rest_get_url_prefix() );
    $is_rest_api_request = strpos( $_SERVER['REQUEST_URI'], $rest_prefix ) !== false;

    return apply_filters( 'is_rest_api_request', $is_rest_api_request );
}
9

Two options here really,

  1. Check if REST_REQUEST is defined.
  2. Hook into rest_api_init where you wanted to hook into init.
1
  • 1
    If you are using WP version 4.4.0+ (which you probably are), this is the correct answer.
    – Mat Lipe
    Commented Oct 5, 2020 at 19:54
6

To solve this problem I wrote a simple custom function based on the assumption that if the URI being requested falls under the WordPress site's Rest API URL, then it follows that it's a Rest API request.

Whether it's a valid endpoint, or authenticated, is not for this function to determine. The question is this: is the URL a potential Rest API url?

function isRestUrl() {
    $bIsRest = false;
    if ( function_exists( 'rest_url' ) && !empty( $_SERVER[ 'REQUEST_URI' ] ) ) {
        $sRestUrlBase = get_rest_url( get_current_blog_id(), '/' );
        $sRestPath = trim( parse_url( $sRestUrlBase, PHP_URL_PATH ), '/' );
        $sRequestPath = trim( $_SERVER[ 'REQUEST_URI' ], '/' );
        $bIsRest = ( strpos( $sRequestPath, $sRestPath ) === 0 );
    }
    return $bIsRest;
}

If your $_SERVER['REQUEST_URI'] isn't properly populated, this function will still return false, regardless.

There is no hard-coding of the URL so if you for some reason change your API URL base, this will adapt.

4

Maybe not right, but I ended up with

if (strpos($_SERVER[ 'REQUEST_URI' ], '/wp-json/') !== false) {
    // Cool API stuff here
}

Feel free to let me know if this isn't right. Trying to make a helpful plugin starter to eventually share: https://gitlab.com/ripp.io/wordpress/plugin-starter

3
  • 3
    I think, this would fail, if you would not have pretty permalinks active. Commented Jun 10, 2019 at 9:34
  • You are definitely correct
    – Charly
    Commented Jun 11, 2019 at 14:25
  • Ok it requires pretty permalink... but who doesn't want it !!!? This seems to me the safest way to do this. All other solutions are fancy but over time if you want your code to still run on later wp versions... this seems to me a safe way !! Commented Jul 30, 2019 at 6:21
4

With WordPress 6.5, core provides such a function wp_is_rest_endpoint to reliably determine whether the current request is a request against a REST endpoint.

There’s also another function wp_is_serving_rest_request to check whether a REST API request is actually being served. If you use it, make sure to call it after the parse_request action, as it will always return false before it.

1
3

You can use wp_is_json_request() like below:

if ( wp_is_json_request() ) {
    // do you stuff here
}

Make sure that you set Accepts or Content-Type as application/json otherwise wp_is_json_request() will return false.

More Documentation: https://developer.wordpress.org/reference/functions/wp_is_json_request/

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.