Contact form 7 Cross-origin issue - form not sending

Hi there,

The Contact Form 7 form has stopped working. It’s stuck on Processing… and in Safari I get a Cross-origin error

[Error] Cross-origin redirection to https://www.wwtdigital-headless.com/wp-json/contact-form-7/v1/contact-forms/180/feedback denied by Cross-Origin Resource Sharing policy: Origin https://wwtdigital.com is not allowed by Access-Control-Allow-Origin.
[Error] Fetch API cannot load https://wwtdigital-headless.com/wp-json/contact-form-7/v1/contact-forms/180/feedback due to access control checks.
[Error] Failed to load resource: Cross-origin redirection to https://www.wwtdigital-headless.com/wp-json/contact-form-7/v1/contact-forms/180/feedback denied by Cross-Origin Resource Sharing policy: Origin https://wwtdigital.com is not allowed by Access-Control-Allow-Origin. (feedback, line 0)
[Error] Unhandled Promise Rejection: TypeError: Cross-origin redirection to https://www.wwtdigital-headless.com/wp-json/contact-form-7/v1/contact-forms/180/feedback denied by Cross-Origin Resource Sharing policy: Origin https://wwtdigital.com is not allowed by Access-Control-Allow-Origin.

In Chrome I see Uncaught (in promise) TypeError: Failed to fetch from create-store.js

It’s possible to check this on the live site https://wwtdigital.com/connect/

I have updated the module to the latest version 0.2.6 and also frontity to the most recent update but that didn’t fix the issue.

Here is the repo https://bitbucket.org/evildonkeylondon/wwt-frontend-frontity/src/pages/

The CMS is on AWS Lightsail while the front end is on Vercel.

Do you have any idea on how to fix this issue? I am no headers expert unfortunately.

Many thanks
Jeff

Problem is, as the error messages indicates, that the server is accepting the request due to CORS. Which is why it’s not possible to submit any data to the REST API.

A good read on how to solve this: https://linguinecode.com/post/enable-wordpress-rest-api-cors

2 Likes

Hi,

Thank you so much for your reply. I have tried that by adding the below to the WordPress functions.php file

function initCors( $value ) {
  $origin_url = '*';

  // Check if production environment or not
  if (ENVIRONMENT === 'production') {
    $origin_url = 'https://wwtdigital.com';
  }

  header( 'Access-Control-Allow-Origin: ' . $origin_url );
  header( 'Access-Control-Allow-Methods: GET' );
  header( 'Access-Control-Allow-Credentials: true' );
  return $value;
}

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

but that did not make any difference. Could you spot any issue in my snippet?

Thanks,
Jeff

I don’t notice anything specific that is an issue, however something I can add is that my hosting didn’t allow me to do this and I had to do it via .htaccess

<IfModule mod_headers.c>
  <IfModule mod_setenvif.c>
    SetEnvIf Origin "^(https://yourdomain\.com|http://localhost:3000)$" CORS=$0
  </IfModule>
  Header set Access-Control-Allow-Origin %{CORS}e env=CORS
  Header append Vary "Origin" env=CORS
  <FilesMatch "\.(php|html)$">
  </FilesMatch>
</IfModule>
# END HttpHeaders

Good luck.

Hi @ni.bonev

Thank you for your help. I’ve tried that too by adding your snippet (changing the domain) to the Lightsail htaccess file of the website instance but again it didn’t make a difference. I’m still getting the cross-origin issue unfortunately. I’ve rebooted the server and cleared the cache but nothing seems to fix the issue.

Any other idea?

Thanks

Make sure you also allow POST, other you won’t be able to send data back to the REST API.

This is the snippet I use myself:

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 ) {
		$origin = get_http_origin();
		$allowed_origins = ['wwtdigital.com']; // add additional domains/IP's here
		if ( $origin && in_array( $origin, $allowed_origins ) ) {
			header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
			header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
			header( 'Access-Control-Allow-Credentials: true' );
			header( 'Access-Control-Expose-Headers: Link', false );
			header( "Access-Control-Allow-Headers: Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type, Origin, Accept");
		}
		return $value;
	});
}

You can also allow every domain/IP with the following:

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' );
		header( 'Access-Control-Expose-Headers: Link', false );
		header( "Access-Control-Allow-Headers: Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type, Origin, Accept");
		return $value;
	});
}
3 Likes

Thank you for your massive help, but still nothing. I have tried allowing all domain/IP but I still get the same issue.

After some testing I now think it’s an AWS Lightsail settings issue. I have cloned the back end on a different server and the form works fine with your snippet.

I now need to figure out why Lightsail is blocking the form. Any idea here is also welcome…!

Thanks for all you help and support guys.

I haven’t worked with Lightsail yet, but it seems to be an issue with Cloudfront (distribution system) which can be fixed by switching some checkboxes :slight_smile:

Alternatively; although since the CF7 package does work on another host this most likely isn’t the case, it could also be an error in the request send to the server. I had this issue with my Gravity Forms script where I had to set mode: 'no-cors', in the fetch headers.

Hi @Johan,

I’m the one who has the cf7 package. Are there any disadvantages to setting this header in the package?

@kasper
As far as I know are there no real disadvantages, except that it will always execute the request even when not allowed, instead of first checking (preflight) if the request is allowed by the server, which could cause heavy requests to be executed with no response.

Note that mode: "no-cors" only allows a limited set of headers in the request:

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type with a value of application/x-www-form-urlencoded, multipart/form-data, or text/plain

source: Using Fetch - Web APIs | MDN

Although even with no-cors I’m able to send credentials, which is most likely due to the fact that the server allows everything.
fetch() has a lot of different variables which can be set and I haven’t figured out all of them yet, so someone with more HTTP/JS knowledge will probably be able to explain it better.

@Johan I see.

So do you think that I should include a no-cors header, do nothing about it, or make users decide on their own with something like this:

state: {
    cf7: { 
      cors: "cors", // no-cors, *cors, same-origin
    }
}

@Johan this might be a good implementation?

I have read up a bit more, and “no-cors” seems like it does more harm than good.

I made the implementation and tested it, and when I set the mode to “no-cors” the form was sent, but the user would never know because the form itself was stuck in “processing” because it could not read the response body. That is one of the things that “no-cors” does, it prevents js frontend code from reading the response body of the fetch.

Hello @jeff , @Johan , @kasper . Thanks for providing a solution. Unfortunately, seems like it’s not working for me.

I used the spinet provided in this thread , in my functions.php file of the default template, as @Johan @jeff suggested, but I’m getting the same error when trying to use the contact form. Bellow an screenshot of the error and the functions.php file. This is the website domain https://wildperutravel.vercel.app/

Thanks in advance, hope you can help me with this.
CORSFUNCTION


.

I believe the first issue is that the URL it is trying to post to doesn’t exist.
https://restapi.wildfreewalkingtours.com/wp-jsoncontact-form-7/v1/contact-forms/111/feedback'
instead of
https://restapi.wildfreewalkingtours.com/wp-json/contact-form-7/v1/contact-forms/111/feedback'

Hi @alex.fernando.801,

As @Johan said, that is most likely the issue. What version of frontity do you have?

Thank you so much @Johan , @kasper for pointing out my mistake, I added the “/” to the url and the contact form worked again. After that I had a cross origin problem because of migrating the wp installation but I modified the .htaccess on my cpanel and it worked again. @kasper I’m using “frontity”: “^1.14.3”, and “@aamodtgroup/frontity-contact-form-7”: “^0.2.7”, seems like the contact form works with the last version @aamodtgroup/frontity-contact-form-7 and at least the last two versions of frontity.

Hi @alex.fernando.801,

So in frontity 1.14.3, did you have to add the “/” manually in the package?

@kasper , sorry I didn’t explain it correctly, I was talking about the URL of the REST API I’m using in frontity settings. Before it was domain/wp-json, now it’s “domain/wp-json/” and it worked.

@alex.fernando.801 Aha.

You can actually use state.source.url instead of state.source.api, and then it will automatically add the right API address, so just https://domain.com