26

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, 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 :) Mar 21, 2016 at 6:58

6 Answers 6

20

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

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:

1
  • I didn't get what #3 did.
    – kodfire
    Jun 20 at 8:43
8

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, 2020 at 19:54
7

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(), 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 );
}
5

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.

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. Jun 10, 2019 at 9:34
  • You are definitely correct
    – Charly
    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 !! Jul 30, 2019 at 6:21

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.