Custom Google reCAPTCHA v3 using PHP, AJAX and WordPress

Custom Google reCAPTCHA v3 using PHP, AJAX and WordPress

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 [icwcf8] shortcode.

I have named this form feature ICWCF8.

Prerequisites

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

The WordPress Function:

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

    $postId = $post->ID;
    $emailTo = '[email protected]';

    $out = '';

    $out = '<form id="icwcf8-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="icwcf8_send" id="icwcf8-send" value="Send" data-ip="1.2.3.4">
        </p>

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

    return $out;
}
add_shortcode('icwcf8', 'wppd_icwcf8');

The WordPress Action

function wppd_action_icwcf8() {
    $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 = "secretKeyBAXtnHN2u5rGtplZ4n5gBAXtnHN2u5rGtplZ4n5g";
    $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_icwcf8', 'wppd_action_icwcf8');
add_action('wp_ajax_nopriv_wppd_action_icwcf8', 'wppd_action_icwcf8');

The JavaScript

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

            document.getElementById('icwcf8-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('icwcf8-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("icwcf8-response").innerHTML = "Email sent successfully!";
                            } else {
                                document.getElementById("icwcf8-response").innerHTML = "An error has occured!";
                            }
                        };
                        request.send('action=wppd_action_icwcf8' + requestString);
                    });;
                });
            } else {
                document.getElementById("icwcf8-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.


Jayesh Patel
Author
Jayesh Patel

Jayesh Patel is a Professional Web Developer & Designer and the Founder of InCreativeWeb.

As a highly Creative Web/Graphic/UI Designer - Front End / PHP / WordPress / Shopify Developer, with 14+ years of experience, he also provide complete solution from SEO to Digital Marketing. The passion he has for his work, his dedication, and ability to make quick, decisive decisions set him apart from the rest.

His first priority is to create a website with Complete SEO + Speed Up + WordPress Security Code of standards.



Explore

Related Articles

11th April, 2024

W3 Total Cache: A Comprehensive Review & Guide for 2024

8th April, 2024

Top 10 Must-Have Web Design Resources and Tools for 2024

8th April, 2024

Unleash Accessibility Potential in Front-end Development