5

I have a WordPress backend where I have added my own custom endpoints to the API:

// retrieve countries
register_rest_route( $namespace, '/countries',
    array(
        'methods'  => 'GET',
        'callback' => array( $this, 'get_countries' ),
    )
);

// check answer
register_rest_route( $namespace, '/check_answer',
    array(
        'methods'  => 'POST',
        'callback' => array( $this, 'check_answer' ),
    )
);

I have set up my environment like this: https://example.com is where the React application lives, and WordPress is in a subdirectory, on https://example.com/wp

My React application makes POST and GET requests to those endpoints above. I have a production environment variable where I set the base URL of the API, which is https://example.com/wp/wp-json/game ('game' is my namespace) and so I can make requests with Axios to https://example.com/wp/wp-json/game/countries and https://example.com/wp/wp-json/game/check_answer and here comes the issue.

My server is configured so that it serves the React application both with as without www. So https://example.com and https://www.example.com both serve the same application.

But this generates some interesting issue for my custom endpoints: the GET request always works. but the POST request only works if I am trying it from https://example.com, NOT from https://www.example.com . In case of the latter it just simply shows me a failed request. No response, nothing.

I have googled and it seems to be related to CORS, but I was unable to fix it. Any ideas here?

Shahbaz A.
  • 4,047
  • 4
  • 34
  • 55
Danny Hobo
  • 574
  • 1
  • 5
  • 24
  • What are the exact error messages that the browser is logging in the devtools console? – sideshowbarker May 10 '20 at 00:25
  • What steps have you taken to CORS-enable the server the request is being sent to? – sideshowbarker May 10 '20 at 00:26
  • @sideshowbarker I added this to functions.php: function add_cors_http_header(){ header("Access-Control-Allow-Origin: *"); } add_action('init','add_cors_http_header'); and browser logs: Access to XMLHttpRequest at example.com/wp/wp-json/game/check_answer from origin www.example.com has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. – Danny Hobo May 10 '20 at 11:21
  • The code you added apparently isn’t getting used for OPTIONS requests. You need to ensure that it gets used for OPTIONS requests — not just for GET and POST. And it’s not sufficient to only send the Access-Control-Allow-Origin response header. You also need to send other Access-Control-Allow-\* response headers. – sideshowbarker May 10 '20 at 11:31
  • thanks, but I am still stuck - I understand the OPTIONS part but don't know how to change that in my code, and what do you mean with sending other Access-Control-Allow-* response headers ? Which headers do I need to send? – Danny Hobo May 11 '20 at 18:42
  • 1
    There are other headers such as `Access-Control-Allow-Methods` etc which you might need to set. Perhaps this SO question will help you out: https://stackoverflow.com/questions/8719276/cross-origin-request-headerscors-with-php-headers – Sunil Chaudhary May 12 '20 at 13:38
  • Okay, I just have to ask, can you just force a single domain and redirect everyone else? You can fight CORS and cookies and everything all day long, of you can just agree on a canonical domain and protocol and be done with it. WordPress is happiest with a single domain anyway. – Chris Haas May 12 '20 at 20:44
  • 1
    @DannyHobo Can you share some additional information about your local development environment? - Is your react app using CRA(Create React App)? - Are you using Laravel Valet or a similar tool for your local WordPress environment? If so, are you using Nginx or Apache? - Is your React app using SSR? - Are you working in a Storybook or anything similar? I deal with this a lot but I need some additional information to get you unblocked. – Joe Dooley May 16 '20 at 22:24
  • 1
    @AjeetShah see in the answer below, I tried the exact code that Shazyriver provided – Danny Hobo May 17 '20 at 20:00
  • @JoeDooley this is not local development. This is on a production server. Yes, CRA was used to create the React app. Server runs on Nginx. No SSR. No Laravel. No Storybook. – Danny Hobo May 17 '20 at 20:03
  • Can you show us (add in the question) your browser network API response headers like seen, for example, in [this](https://i.stack.imgur.com/j4ymL.png) image, preferably for both with `www` and without it? – Ajeet Shah May 17 '20 at 22:22
  • @DannyHobo I think we can resolve this issue, but it would be much faster via chat. Are you available? https://chat.stackoverflow.com/rooms/214080/wordpress-custom-api-endpoint-post-request-fails-in-react?highlights=true – Joe Dooley May 17 '20 at 23:09
  • @DannyHobo I'm going to leave the chat window open while I finish up this feature. So I'll be online for the next couple of hours at least. There is no way for me to help without seeing your webpack config and nginx.conf. Let me know if your unable to join. Otherwise just ping me when you click the link to the chat room. Thanks – Joe Dooley May 17 '20 at 23:28
  • CORS is a 401 http error, the call and service are in the same domain, so CORS... I don't believe it is CORS... maybe is just a 401 not access error, Does the end point works if you call it directly (not from your React app, but from the browser directly or Postman or postwoman,... do you need to authenticate to use it? are you authenticating? – Pablo Martinez May 18 '20 at 13:38
  • @JoeDooley sorry, didn't see your message earlier. I don't have a webpack config (it's default CRA, didn't eject it) and don't have root access for Nginx either. I do believe it may be related to Nginx settings, yes, our sys admin says it isn't, but I am not entirely sure I should believe him anymore. – Danny Hobo May 18 '20 at 13:49
  • @PabloMartinez yes, it is CORS. "Access to XMLHttpRequest at example.com/wp/wp-json/game/check_answer from origin www.example.com has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource" it's not a 401 error. – Danny Hobo May 18 '20 at 13:50
  • @DannyHobo just for kicks. Add [this](https://gist.github.com/joedooley/42634b7295ab1278228e86468305f04b) to the index.php in the root directory of your WordPress site. This is just for testing. It should not be used in PROD? If this works you can figure out a more appropriate place to add those headers or proxy your requests with the Nginx proxy_pass directive. – Joe Dooley May 18 '20 at 14:20

1 Answers1

2

First of all i would like to point out that your Get requests work because they belong to the category which does not trigger a preflight request. While your Post request is probably using some header which removes it from the category hence requiring preflight to pass. If you are interested in reading more, here is the documentation link.

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests

Now, according to your comment, the error you are getting is

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

The method you are using for setting headers, as you mentioned in a comment, does not work on rest requests. You can use below function in your functions.php or a plugin file to set the origin to *.

function sr_rest_send_cors_headers( $value ) 
{   
    header( 'Access-Control-Allow-Origin: *' );
    header( 'Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE' );
    header( 'Access-Control-Allow-Credentials: true' );
    header( 'Vary: Origin', false );

    return $value;
}
add_filter( 'rest_pre_serve_request', 'sr_rest_send_cors_headers', 11 );

Although i recommend what WordPress does by default. If you check wp-includes/rest-api.php you will find the original function which i have modified for your purpose. If you are interested in taking a look, here is the trac link.

https://core.trac.wordpress.org/browser/tags/5.4/src/wp-includes/rest-api.php#L574

Shahbaz A.
  • 4,047
  • 4
  • 34
  • 55
  • thanks, but still no luck. Tried the code you gave in functions.php but still the same error. – Danny Hobo May 17 '20 at 19:21
  • @DannyHobo, Can you please provide a snapshot of the request and response header from network tab of your dev tools for this request ? And also a snapshot of console with the error. – Shahbaz A. May 17 '20 at 23:29