23

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 Mar 20 '16 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 :) – websupporter Mar 21 '16 at 6:58
18

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
  • #42061 might add wp_is_rest_request() or wp_doing_rest(). – Ian Dunn Mar 10 '20 at 19:40
14

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
     * 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() {
        $prefix = rest_get_url_prefix( );
        if (defined('REST_REQUEST') && REST_REQUEST // (#1)
                || isset($_GET['rest_route']) // (#2)
                        && strpos( trim( $_GET['rest_route'], '\\/' ), $prefix , 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:

7

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 Oct 5 '20 at 19:54
6

This is complex to achieve, for reasons that would be very lengthy to explain.

Long story short, 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 );
}

Code slighly adapted for StackOverflow. I've renamed the filter and made it a function instead of a public method of a class.

5

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
  • 2
    I think, this would fail, if you would not have pretty permalinks active. – websupporter Jun 10 '19 at 9:34
  • You are definitely correct – Charly Jun 11 '19 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 !! – Antony Gibbs Jul 30 '19 at 6:21
4

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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