Having issues submitting form via AJAX on WordPress with reCAPTCHA

I've spent a good few hours trying to Google my way out of this, and I keep coming up with one issue or another. I'm getting myself wrapped up in knots and I am hoping that someone can help me by giving me a metaphorical slap around the face and showing me how the hell to do this properly.

Ok ... so I have a page on my front end that is inserted by a shortcode. This form is essentially a sort of AMA (Ask Me Anything) form, which I am using to create posts in my Admin area. Visitors enter their question, name and email, and submit the form to me via AJAX. The submissions are saved into the WordPress database under an ama custom post type, and an email is sent to me via wp_mail because I have an SMTP plugin installed that routes all requests for wp_mail through there. I have CMB2 installed on my website, and have keys for reCAPTCHA saved there.

So far, so good.

I had a working form with CMB2 fields, but CMB2 doesn't seem to support reCAPTCHA (otherwise it worked fine). So I decided to start from scratch and write my own form since it was just three fields that I wanted to submit. What could possibly go wrong, right?

Here's my Franken-code.

function ccdClient_shortcode_amaForm( $atts ) {

	// Parse attributes
    $atts = ( shortcode_atts( array(
        'id'        => uniqid('ccdClient_amaForm_'),
    ), $atts, 'ama_form' ) );

    $rcKey = cmb2_get_option( 'ccdtheme_settings_apikeys', '_ccdclient_themesettings_apikeys_captcha_sitekey' );

    $form = '
    <form id="' . $atts['id'] . '" name="' . $atts['id'] . '" method="post" action="">
        <div class="amaError"></div>
        <div class="amaForm-field-question amaForm-field">
            <p><label for="question">Your Question</label></p>
            <p><textarea id="question" name="question" tabindex="1"></textarea></p>
        <div class="amaForm-fieldGroup amaForm-groupTwo">
            <div class="amaForm-field-name amaForm-field">
                <p><label for="name">Your Name</label></p>
                <p><input type="text" id="name" name="name" tabindex="2" /></p>
            <div class="amaForm-field-email amaForm-field">
                <p><label for="email">Your Email</label></p>
                <p><input type="email" id="email" name="email" tabindex="3" /></p>
        <div class="amaForm-fieldGroup amaForm-groupTwo">
            <div class="amaForm-field-recaptcha amaForm-field amaForm-recaptcha">
                <div class="g-recaptcha" data-sitekey="' . $rcKey . '"></div>
            <div class="amaForm-field-submit amaForm-field amaForm-submit">
                <input type="submit" value="Publish" id="submit" name="submit" />
        $(document).ready(function() {

            // Get form
            var amaForm = $("#' . $atts['id'] . '");
            // Get messages div
            var amaError = $("#' . $atts['id'] . ' .amaError");
            // Set data
            var amaData = { "action" : "ama_form_process"}

            var options = { 
                url: "'. admin_url( 'admin-ajax.php' ) .'",
                type: "post",
                dataType: "json",
                data: amaData,
                success : function(responseText, statusText, xhr, $form) {
                    $(amaError).html("Your form has been submitted successfully");

            //Set submit function
            amaForm.on("submit", function(e) {
                //Prevent default form behavior
                // Serialise form data
                //Post via AJAX
                .done(function(response) {
                    // Make sure that the amaError div has the "success" class.
                    // Set the message text.
                .fail(function(data) {
                    // Make sure that the amaError div has the "error" class.

                    // Set the message text.
                    if (data.responseText !== "") {
                    } else {
                        $(amaError).text("Oops! An error occured, and your message could not be sent.");

    return $form;
add_shortcode('ama_form', 'ccdClient_shortcode_amaForm');

function ama_form_process() {
    // If the form was submitted
    if ($_SERVER["REQUEST_METHOD"] == "POST") {

        // Include WordPress files
        include_once '../../../../../wp-includes/wp-load.php';

        // Set reCaptcha private key
        $recaptchaKey = cmb2_get_option( 'ccdtheme_settings_apikeys', '_ccdclient_themesettings_apikeys_captcha_secretkey' );

        // If the Google Recaptcha box was clicked
        if(isset($_POST['g-recaptcha-response']) && !empty($_POST['g-recaptcha-response'])){
            $captcha = $_POST['g-recaptcha-response'];
            $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=" . $recaptchaKey . "&response=" . $captcha);
            $obj = json_decode($response);

            // If the Google Recaptcha check was successful
            if($obj->success == true) {
                $question = strip_tags( trim( $_POST['question'] ) );
                $name = strip_tags( trim( $_POST["name"] ) );
                $name = str_replace( array("\r","\n"), array(" "," "), $name);
                $email = filter_var( trim( $_POST["email"] ), FILTER_SANITIZE_EMAIL );
                if ( !$name || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
                    echo "Oops! There was a problem with your submission. Please complete the form and try again.";

                // Add the content of the form to $post as an array
                $post = array(
                    'post_title'    => $question,
                    'post_status'   => 'pending',   // Could be: publish
                    'post_type' 	=> 'ama', // Could be: `page` or your CPT
                    'meta_input'    => array(
                        '_ccdclient_ama_name'   => $name,
                        '_ccdclient_ama_email'  => $email,
                echo 'Saved your post successfully! :)';

                $recipient = get_option('admin_email');
                $subject = "New question from $name";
                $email_content = "Name: $name\n";
                $email_content .= "Email: $email\n\n";
                $email_content .= "Message:\n$question\n";
                $email_headers = "From: $name <$email>";
                wp_mail( $recipient, $subject, $email_content, $email_headers );
            // If the Google Recaptcha check was not successful
            else {
                echo "Robot verification failed. Please try again. Success:" . $response;
        // If the Google Recaptcha box was not clicked
        else {
            echo "Please click the reCAPTCHA box.";
    // If the form was not submitted
    // Not a POST request, set a 403 (forbidden) response code.
    else {
        echo "There was a problem with your submission, please try again.";
add_action("wp_ajax_ama_form_process", "ama_form_process");

//use this version for if you want the callback to work for users who are not logged in
add_action("wp_ajax_nopriv_ama_form_process", "ama_form_process");

As you can guess, I have looked at about a dozen or so pages and combined the efforts of each of them, thus overwriting parts that would perhaps have worked and confused myself no end, and so am resorting to here to preserve what is left of my sanity.

EDIT: Apologies. Whilst I copied the code, I wasn't specific on what issues I was facing. Goes to show the extent I was frustrated.

I have had a number of issues with this code. Currently, when I submit the form, it keeps the same URL but returns a 404 error page. However, it has previously told me that it cannot recognise functions - and therefore couldn't run - such as cmb2_get_option (which is a modification of get_option that specifically works with CMB2 options pages) and wp_insert_post. The latter error (ie: wp_insert_post) came up when the secret key was hard-coded into the script and not called from the get_option function.