Add CORS to REST API

Feature Card

Description

For the “Direct to Frontity” installation Frontity uses an external domain. The REST API doesn’t have CORS headers. We can create a PHP plugin for that.

User Stories

As a Frontity user
I want to add easily CORS headers to the REST API
so that I can use a different domain

Possible solution

add_action( 'rest_api_init', 'wp_rest_allow_all_cors', 15 );

function wp_rest_allow_all_cors() {
  remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );

  add_filter( 'rest_pre_serve_request', function( $value ) {
    header( 'Access-Control-Allow-Origin: *' );
    header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
    header( 'Access-Control-Allow-Credentials: true' );
    return $value;
  });
}

I’m not sure this is necessary. It seems that WP does set headers for CORS (I tried one clean installation with Nginx in production and it worked just fine).

Also, in the rest_pre_serve_request hook there is already a function registered called rest_send_cors_headers that sets the headers:

function rest_send_cors_headers( $value ) {
    $origin = get_http_origin();
 
    if ( $origin ) {
        // Requests from file:// and data: URLs send "Origin: null"
        if ( 'null' !== $origin ) {
            $origin = esc_url_raw( $origin );
        }
        header( 'Access-Control-Allow-Origin: ' . $origin );
        header( 'Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE' );
        header( 'Access-Control-Allow-Credentials: true' );
        header( 'Vary: Origin', false );
    } elseif ( ! headers_sent() && 'GET' === $_SERVER['REQUEST_METHOD'] && ! is_user_logged_in() ) {
        header( 'Vary: Origin', false );
    }
 
    return $value;
}

You might not see them when calling the REST API directly from the browser or from an app like Postman because the Origin header is not populated therefore the CORS headers are not set. But if you try setting the Origin header in Postman you’ll see that the CORS headers will be set on the response.

You are absolutely right, it does. Many thanks @orballo :heart:

@SantosGuillamot what do we do with this topic? I wouldn’t like to close it because I don’t want to limit the conversation. Do you have any idea?

I think it’s the same case as the one discussed here:

I’ve just discovered that this is a really bad approach, because if your cache of the REST API response includes headers and doesn’t overwrite them with a general CORS header ("*") then it will return the previous URL. This means that, if you are using that REST API for local development, it can cache Access-Control-Allow-Origin: localhost:3000, and your production site will stop working.

The thing is that, the code that WordPress is using right now is as “safe” as using "*" because it will copy the domain you pass in the Origin header. So, I guess it’s better to set it directly to "*" and avoid caching issues.

EDIT: Moving this back to Awaiting Development.

3 Likes

In the meantime, if someone wants to solve this type of CORS problem, they can use this plugin

or add this code in their WordPress:

add_action( 'rest_api_init', 'wp_rest_allow_all_cors', 15 );

function wp_rest_allow_all_cors() {
  remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );

  add_filter( 'rest_pre_serve_request', function( $value ) {
    header( 'Access-Control-Allow-Origin: *' );
    header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
    header( 'Access-Control-Allow-Credentials: true' );
    return $value;
  });
}

I’m running into this issue too and so far haven’t been able to solve with the above. I’m using Frontity Chakra Theme.

Also tried purging Varnish caches afterwards thinking it may help.

Strangely though my other rest calls aren’t having the same issue. And my site seems to operate just fine (minus an issue where if I open the site on a permalink, the homepage spins out if I navigate there while all other pages work fine and the homepage works fine if I start from the homepage.

**Edit. This seems to be fixed now. … I think I needed to clear by browser cache. But I’m not 100% positive. Cloudways is doing some odd things over here caching wise.

1 Like