WordPress REST API: ‘Access-Control-Allow-Origin’ header contains multiple values

If you’re experiencing errors when attempting to access WordPress REST API endpoints between domains due to CORS policies, this code snippet will help.

If you’re working with the WordPress REST API, sooner or later you’re likely to end up trying to load content between domains, particularly if you’re creating a headless CMS setup. For example, your WordPress backend may live at wp.mysite.com whilst the frontend of your application lives at mysite.com. In these circumstances, you may run into problems with Cross-Origin Resource Sharing (CORS).

For security reasons, browsers restrict HTTP requests initiated from scripts if they cross over between domains (a cross-origin request). In the headless CMS scenario above, you may need to make AJAX calls from your website frontend to your WP backend. Initially, you’re likely to receive an error such as:

Access to XMLHttpRequest at ’https://wp.yoursite.com/wp-admin/admin-ajax.php’ from origin ’https://www.yoursite.com’ has been blocked by CORS policy

A quick Google search would provide the solution: adding the following line to the .htaccess file in your WordPress domain will allow cross-origin requests from the specified domain.

Header add Access-Control-Allow-Origin "https://www.yoursite.com"

However, if you subsequently try to load data from the WordPress REST API via now, you’ll be presented with a new error:

'Access-Control-Allow-Origin' header contains multiple values 'https://www.yoursite.com, *', but only one is allowed

We only specify a single value in the .htaccess rule, so why are two values being detected? The answer is that the REST API by default returns its own Access-Control-Allow-Origin header and, by default, the value of this is ‘*’. So both our .htaccess rule and the API’s own rule are being returned simultaneously.

If we’re already setting requests through another means, such as .htaccess, we can simply disable these additional REST API CORS headers using the following snippet:

add_action('rest_api_init', function() {
    remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
}, 15);

A lightweight, intuitive WordPress theme to enable flexible developement.

  • Lighting-fast installer
  • Intuitive SASS structure
  • Bloat-free

Build with Barebones