4

I am currently stuck on a problem with Gravity Forms and ReactJS. I am trying to load a Gravity Form as a Modal in a ReactJS component for contact purposes. Basically, how I am currently set up is by doing a GET from the WP-API for the page with the form loaded in, and then using dangerouslySetInnerHTML to build the page in the component. The problem is though that when I try to submit the form, its giving me a problem with the POST. Its trying to submit it to the URL from the GET. I can use some serious help here on what would be the best approach.

import React, { PropTypes } from 'react';
import Modal from 'react-modal';
import $ from 'jquery';

class RequestContactModal extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      content: ''
    };
  }

  componentWillMount() {
    const wpApiUrl = '../wp-json/wp/v2/pages/61';

    $.ajax({
      url: wpApiUrl,
      type: 'GET'
    })
      .done((response) => {
        console.log(response);
        this.setState({
          content: response.content.rendered
        });
      })
      .fail((response) => {
        console.log('fail');
        console.log(response);
      });
  }

  handleSubmit = (ev) => {
    ev.preventDefault();
    this.props.closeModal();
  }

  handleCloseClick = (ev) => {
    ev.preventDefault();
    this.props.closeModal();
  }

  render() {
    const customStyles = {
      overlay: {
        backgroundColor: 'rgba(0, 0, 0, 0.65)'
      },
      content: {
        top: '50%',
        left: '50%',
        right: 'auto',
        bottom: 'auto',
        marginRight: '-50%',
        transform: 'translate(-50%, -50%)',
        background: '#fff'
      }
    };

    return (
      <Modal
        isOpen={this.props.isOpen}
        onRequestClose={this.props.closeModal}
        style={customStyles}
      >
        <div>
          <p>Gravity Forms</p>
          <div dangerouslySetInnerHTML={{__html: this.state.content}} />
        </div>
      </Modal>
    );
  }
}

RequestContactModal.propTypes = {
  closeModal: PropTypes.func.isRequired,
  isOpen: PropTypes.bool
};

RequestContactModal.defaultProps = {
  isOpen: false
};

export default RequestContactModal;

1 Answers1

0

This question may be old, but building React applications on WordPress "facelessly" using the WP REST API is gaining momentum in a huge way (it's even the future for WordPress core), so this is bound to come up more and more.

So what is happening is that Gravity Forms sets it's form action by via $action = remove_query_arg( 'gf_token' ); which in turn calls add_query_arg() which then calls $uri = $_SERVER['REQUEST_URI']; - this means that when you use React to display WordPress content containing a Gravity Form, the form's action is set to the REST endpoint called, not the content's permalink. Whoops!

Although Gravity Forms has a bona-fide WP REST API add-on in works, there are two solid options I've been able to suss out so far:

Option 1 - Fully Headless

Ensure you have a REST route that accepts POST (I suggest just reusing a GET route) and add do_action('wp'); to your route callback. You could add it earlier if you like, like the rest_api_init hook. This will ensure that Gravity Forms gets triggered when REST requests are sent to it.

Alternatively, you can call GFForms::maybe_process_form() from your route callback or use it as a callback in the rest_api_init hook. The trick is to ensure that the method gets called when the API receives the request.

Next, have React handle your form submission (you don't want the browser actually posting it directly and showing your visitors JSON). The REST API will automagically return a response with a properly handled Gravity Form markup... validation/error messages, confirmations, etc. Note that Gravity Forms needs to be ajax=false for this approach.

Option 2 - Faceless (Semi-Headless)

Assuming you want to preserve WordPress's permalinks, you will likely have your REST API endpoints configured to match the WordPress permalink URIs; So, for instance /wp-json/your-post-name-here/ is equivalent to /your-post-name-here/. If not, you can always ensure you are sending the URI along with your requests. If this is how you are handling it, you can add something the following to the rest_api_init hook:

function tweak_request_uri() {
    $prefix = '/' . rest_get_url_prefix();
    $_SERVER['REQUEST_URI'] = str_replace( $prefix, '', $_SERVER['REQUEST_URI'] );
}

This ensures that the REQUEST_URI matches the current page, so that the Gravity Form is able to successfully post it's data to WordPress. However, while this allows Gravity Forms postbacks to actual reach the server, you aren't going to get anything meaningful back if you are using only the REST API... because the response is tied to the request to the server, but React is making a new, separate request to the API for content. Ergo, you get a fresh form. Not good UX, that.

To fix this, you need to take whatever function, class, object, etc that you use to package your data prior to rest_ensure_response( $data ) and call it from within a wp_head() hook. You want to json_encode() the data and output it within a script tag as a Javascript variable. For instance, something like this:

var $react_first_load_data = json_encode( [ 'id' => get_the_id(), 'title' => get_the_title(), 'content' => get_the_content() ] );
printf('<script type="text/javascript">window.reactFirstLoadData=%s</script>', $react_first_load_data);

Then, in your React app, you check for the presence of this variable first, and use the data if present. If not, fall back to making the REST request as usual.

I know this answer has been very architectural, but there's a lot of ways to tackle this and it depends heavily on how you've already structured your React implementation with WordPress.

Matt van Andel
  • 636
  • 7
  • 13