Google reCAPTCHA v3 using PHP, AJAX and WordPress

2

After having issues with Google reCAPTCHA v2 and a custom WordPress implementation, I started coding an optimized version using the invisible version of Google reCAPTCHA v3.

Based on the post ID variable, I have added several extra fields to the form (not shown here).

Optionally, there’s a handy [cf8] shortcode.

I have named this form feature CF8.

Prerequisites

The prerequisites for this contact form are, obviously, a Google reCAPTCHA v3 (the invisible one). Create one here.

The WordPress Function:

/**
 * CF8: Quick contact form with Google reCAPTCHA v3
 * 
 * @return HTML string
 */
function wppd_cf8() {
    global $post;

    $postId = $post->ID;
    $emailTo = 'email@example.com';

    $out = '';

    $out = '<form id="cf8-form" method="post">
        <p>
            <input type="hidden" name="contact_to" id="contact-to" value="' . $emailTo . '" readonly>
            <input type="hidden" name="contact_id" id="contact-id" value="' . $postId . '">
            <input type="text" name="contact_name" id="contact-name" placeholder="Full Name *">
            <input type="email" name="contact_email" id="contact-email" placeholder="Email *">
            <input type="text" name="contact_phone" id="contact-phone" placeholder="Phone">
            <textarea name="contact_notes" id="contact-notes" rows="3" placeholder="Your Enquiry *"></textarea>
        </p>

        <p>
            <input type="submit" name="cf8_send" id="cf8-send" value="Send" data-ip="1.2.3.4">
        </p>

        <div id="cf8-response"></div>
    </form>';

    return $out;
}
add_shortcode('cf8', 'wppd_cf8');

The WordPress Action

function wppd_action_cf8() {
    $to = filter_input(INPUT_POST, 'to', FILTER_VALIDATE_EMAIL);
    $pid = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT);
    $name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
    $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
    $phone = filter_input(INPUT_POST, 'phone', FILTER_SANITIZE_STRING);
    $notes = filter_input(INPUT_POST, 'notes', FILTER_SANITIZE_STRING);
    $captcha = filter_input(INPUT_POST, 'token', FILTER_SANITIZE_STRING);

    if (!$captcha) {
        echo '<h2>Please check the the captcha form.</h2>';
        exit;
    }

    $secretKey = "BAXtnHN2u5rGtplZ4n5gBAXtnHN2u5rGtplZ4n5g";
    $ip = $_SERVER['REMOTE_ADDR'];

    $url = 'https://www.google.com/recaptcha/api/siteverify';
    $data = [
        'secret' => $secretKey,
        'response' => $captcha
    ];

    $options = [
        'http' => [
            'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
            'method'  => 'POST',
            'content' => http_build_query($data)
        ]
    ];

    $context  = stream_context_create($options);
    $response = file_get_contents($url, false, $context);
    $responseKeys = json_decode($response,true);

    header('Content-type: application/json');

    if ($responseKeys["success"] && $responseKeys["score"] >= 0.5) {
        $body = '<h3>A new quick contact has been sent from <a href="' . get_permalink($pid) . '">' . get_the_title($pid) . '</a>!</h3>
        <p>Contact details:</p>
        <p>
            <b>Name:</b> ' . $name . '<br>
            <b>Email:</b> ' . $email . '<br>
            <b>Telephone:</b> ' . $phone . '<br><br>
            <b>Sent From:</b> <a href="' . get_permalink($pid) . '">' . get_the_title($pid) . '</a><br>
            <b>Post ID:</b> ' . $pid . '<br><br>
            <b>Notes:</b> ' . $notes . '
        </p>

        <p>
            <small>Email sent to ' . $to . ' on ' . date('Y-m-d, H:i') . '</small><br>
            <small>Google reCAPTCHA score: ' . $responseKeys['score'] . '</small>
        </p>';

        $headers[] = "Content-Type: text/html;";

        $subjectLine = 'CF8 Contact Request - ' . get_the_title($pid);

        wp_mail($to, 'CF8 Contact Request', $body, $headers);

        // Return response
        echo json_encode([
            'success' => 'true',
            'score' => $responseKeys["score"]
        ]);
    } else {
        echo json_encode([
            'success' => 'false',
            'score' => $responseKeys["score"]
        ]);
    }

    wp_die();
}
add_action('wp_ajax_wppd_action_cf8', 'wppd_action_cf8');
add_action('wp_ajax_nopriv_wppd_action_cf8', 'wppd_action_cf8');

The CSS

#cf8-response {
    font-size: 14px;
}

The JavaScript

document.addEventListener('DOMContentLoaded', () => {
    /**
     * CF8: Quick contact form with Google reCAPTCHA v3
     */
    if (document.getElementById('cf8-form')) {
        document.getElementById('cf8-form').addEventListener('submit', (event) => {
            event.preventDefault();

            document.getElementById('cf8-response').innerHTML = 'Sending...';

            let to = jQuery("#contact-to").val(),
                id = jQuery("#contact-id").val(),
                reference = jQuery("#contact-reference").val(),
                name = jQuery("#contact-name").val(),
                email = jQuery("#contact-email").val(),
                phone = jQuery("#contact-phone").val(),
                notes = jQuery("#contact-notes").val();

            if (name !== '' && email !== '' && phone !== '' && notes !== '') {
                grecaptcha.ready(() => {
                    grecaptcha.execute("cy08Qu0dkGIsCDBaXKf1cy08Qu0dkGIsCDBaXKf1", {
                        action: "create_comment"
                    }).then((token) => {
                        document.getElementById('cf8-form').insertAdjacentHTML('afterBegin', '<input type="hidden" name="g-recaptcha-response" value="' + token + '">');

                        let request = new XMLHttpRequest(),
                            requestString = '';

                        requestString += '&to=' + to;
                        requestString += '&id=' + id;
                        requestString += '&reference=' + reference;
                        requestString += '&name=' + name;
                        requestString += '&email=' + email;
                        requestString += '&phone=' + phone;
                        requestString += '&notes=' + notes;
                        requestString += '&token=' + token;

                        request.open('POST', ajaxVar.ajaxUrl, true);
                        request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
                        request.onload = () => {
                            response = JSON.parse(request.response);

                            if (response.success) {
                                document.getElementById("cf8-response").innerHTML = "Email sent successfully!";
                            } else {
                                document.getElementById("cf8-response").innerHTML = "An error has occured!";
                            }
                        };
                        request.send('action=wppd_action_cf8' + requestString);
                    });;
                });
            } else {
                document.getElementById("cf8-response").innerHTML = "An error has occured!";
            }
        });
    }
});

And that is all!

Make sure you create a custom plugin or integrate it into your existing plugin. Dumping the code in functions.php is always a bad idea.

Added by Ciprian on Thursday, August 13, 2020 in Blog

Unlimited Automated Page Speed Monitoring & Tracking.
Use SpeedFactor to track your website. It’s simple and reliable.
See how real people experience the speed of your website. Then find (and fix) your web performance problems.
Get Started

Related Articles

Privacy Policy