You might want to customize your WordPress login page or create a custom login form for enhanced security and branding. If you already do, this solution probably isn’t for you. Whilst this method does hook into the standard WordPress authentication, custom login flows may not work.
Why use Turnstile?
- Integrated with Cloudflare: If you’re already using Cloudflare, Turnstile is a convenient and free CAPTCHA solution.
- Effective Against Spam: Adding a CAPTCHA helps prevent bots and scrapers from accessing your site or spamming your forms.
- Lightweight: Turnstile is efficient and less resource-intensive than some other CAPTCHA options.
- To preserve other security measures: For example, Siteground Security Optimiser and Wordfence plugins add 2FA to the default WordPress login form – you may want to keep the 2FA and add Turnstile as another level of security.
The steps
- Access Cloudflare Dashboard:
- Log in to your Cloudflare account.
- Navigate to the
Turnstile
section in the dashboard.
- Add Your Site:
- Click
Add Site
and select your domain. - Follow the on-screen instructions to complete the setup.
- Choose a challenge level that matches your security needs.
- Click
- Retrieve Your Keys:
- Once the site is added, go to
Settings
under your domain. - Note your
Site Key
andSecret Key
. You’ll need these for the next steps.
- Once the site is added, go to
- Add Code to WordPress:
- Open your
functions.php
file or use a code snippet plugin - Copy and paste the snippet below
- Open your
- Replace Placeholder Text:
- Substitute
CLOUDFLARE_SITE_KEY
andCLOUDFLARE_SECRET_KEY
with your actual keys. - Ensure the keys are within single quotes.
- Substitute
- Save Changes:
- Save the file or snippet and test your login page.
function get_cloudflare_turnstile_keys() {
return array(
'site_key' => 'CLOUDFLARE_SITE_KEY',
'secret_key' => 'CLOUDFLARE_SECRET_KEY'
);
}
// Enqueue Turnstile script
function enqueue_turnstile_script() {
wp_enqueue_script('turnstile', 'https://challenges.cloudflare.com/turnstile/v0/api.js', array(), null);
}
add_action('login_enqueue_scripts', 'enqueue_turnstile_script');
// Add Turnstile to login, registration, and forgot password forms
function add_turnstile_to_forms() {
$keys = get_cloudflare_turnstile_keys();
echo '<div class="cf-turnstile" data-sitekey="' . esc_attr($keys['site_key']) . '" data-theme="light"></div>';
}
add_action('login_form', 'add_turnstile_to_forms');
add_action('register_form', 'add_turnstile_to_forms');
add_action('lostpassword_form', 'add_turnstile_to_forms');
// Verify Turnstile response
function verify_turnstile_response($user, $password = '') {
if (!isset($_POST['cf-turnstile-response'])) {
return new WP_Error('captcha_missing', __('Please complete the CAPTCHA.'));
}
$keys = get_cloudflare_turnstile_keys();
$response = wp_remote_post('https://challenges.cloudflare.com/turnstile/v0/siteverify', array(
'body' => array(
'secret' => $keys['secret_key'],
'response' => $_POST['cf-turnstile-response'],
'remoteip' => $_SERVER['REMOTE_ADDR']
)
));
if (is_wp_error($response)) {
return new WP_Error('captcha_error', __('Error verifying CAPTCHA. Please try again.'));
}
$body = wp_remote_retrieve_body($response);
$result = json_decode($body, true);
if (!$result['success']) {
return new WP_Error('captcha_invalid', __('CAPTCHA validation failed. Please try again.'));
}
return $user;
}
// Apply verification to login, registration, and password reset
add_filter('authenticate', 'verify_turnstile_response', 30, 3);
add_filter('registration_errors', 'verify_turnstile_response', 10, 2);
add_action('lostpassword_post', function($errors) {
$user = verify_turnstile_response(null);
if (is_wp_error($user)) {
$errors->add($user->get_error_code(), $user->get_error_message());
}
}, 10, 1);
// Add some custom styling (optional)
function turnstile_login_style() {
echo "<style>
body.login #login {
width: 100% !important;
max-width: 350px !important;
}
body.login .cf-turnstile {
margin-top: 0.4rem !important;
margin-bottom: 1rem !important;
}
</style>";
}
add_action('login_enqueue_scripts', 'turnstile_login_style', 20);