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', () => {
const form = document.getElementById('cf8-form');
const responseEl = document.getElementById('cf8-response');
if (form) {
form.addEventListener('submit', (event) => {
event.preventDefault();
responseEl.textContent = 'Sending...';
const to = document.getElementById('contact-to').value;
const id = document.getElementById('contact-id').value;
const reference = document.getElementById('contact-reference').value;
const name = document.getElementById('contact-name').value;
const email = document.getElementById('contact-email').value;
const phone = document.getElementById('contact-phone').value;
const notes = document.getElementById('contact-notes').value;
if (name && email && phone && notes) {
grecaptcha.ready(() => {
grecaptcha.execute('cy08Qu0dkGIsCDBaXKf1cy08Qu0dkGIsCDBaXKf1', { action: 'create_comment' })
.then((token) => {
const hiddenInput = document.createElement('input');
hiddenInput.type = 'hidden';
hiddenInput.name = 'g-recaptcha-response';
hiddenInput.value = token;
form.prepend(hiddenInput);
const params = new URLSearchParams();
params.append('action', 'wppd_action_cf8');
params.append('to', to);
params.append('id', id);
params.append('reference', reference);
params.append('name', name);
params.append('email', email);
params.append('phone', phone);
params.append('notes', notes);
params.append('token', token);
fetch(ajaxVar.ajaxUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: params.toString()
})
.then(response => response.json())
.then(data => {
if (data.success) {
responseEl.textContent = 'Email sent successfully!';
} else {
responseEl.textContent = 'An error has occurred!';
}
})
.catch(() => {
responseEl.textContent = 'An error has occurred!';
});
});
});
} else {
responseEl.textContent = 'An error has occurred!';
}
});
}
});
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.