site_key = JVB_CLOUDFLARE_SITE_KEY;
// $this->secret_key = JVB_CLOUDFLARE_SECRET_KEY;
// Add hooks for login and registration forms
add_action('login_enqueue_scripts', [$this, 'enqueueTurnstileScripts']);
add_action('login_form', [$this, 'addTurnstileToLogin']);
add_action('register_form', [$this, 'addTurnstileToRegister']);
// Add verification hooks
add_filter('authenticate', [$this, 'verifyLoginTurnstile'], 99, 3);
add_filter('registration_errors', [$this, 'verifyRegisterTurnstile'], 10, 3);
// Add hook for lost password form
add_action('lostpassword_form', [$this, 'addTurnstileToLogin']);
add_action('lostpassword_post', [$this, 'verifyLostpasswordTurnstile']);
}
/**
* Enqueue Turnstile script
* @return void
*/
public function enqueueTurnstileScripts():void
{
wp_enqueue_script(
'cloudflare-turnstile',
'https://challenges.cloudflare.com/turnstile/v0/api.js',
[],
null,
true
);
// Add this line to set the async and defer attributes
wp_script_add_data('cloudflare-turnstile', 'async', true);
wp_script_add_data('cloudflare-turnstile', 'defer', true);
}
/**
* Add Turnstile to login form
* @return void
*/
public function addTurnstileToLogin():void
{
echo '
';
}
/**
* Add Turnstile to registration form
* @return void
*/
public function addTurnstileToRegister():void
{
echo '';
echo '
';
echo '';
echo '
';
}
/**
* Verify Turnstile token
* @param $token
*
* @return bool
*/
public function verifyTurnstile($token = null):bool
{
// If no token is provided, try to get it from the request
if (!$token && isset($_POST['cf-turnstile-response'])) {
$token = $_POST['cf-turnstile-response'];
}
// If still no token, verification fails
if (!$token) {
return false;
}
$data = [
'secret' => $this->secret_key,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR']
];
$url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
$response = wp_remote_post($url, [
'body' => $data,
'timeout' => 30
]);
if (is_wp_error($response)) {
return false;
}
$body = wp_remote_retrieve_body($response);
$result = json_decode($body, true);
return isset($result['success']) && $result['success'] === true;
}
/**
* Verify login form
* @param null|WP_User|WP_Error $user
* @param string $username
* @param string $password
*
* @return WP_Error|WP_User
*/
public function verifyLoginTurnstile(null|WP_User|WP_Error $user, string $username, string $password):WP_Error|WP_User
{
global $_POST;
// Skip verification if already logged in or if no username/password
if (is_user_logged_in() || empty($username) || empty($password)) {
return $user;
}
// Skip on AJAX requests (for better compatibility with other plugins)
if (wp_doing_ajax()) {
return $user;
}
// If already have an error, just return it
if (is_wp_error($user)) {
return $user;
}
// Check Turnstile
if (!$this->verifyTurnstile()) {
return new WP_Error('turnstile_verification_failed', 'ERROR: Please complete the security check.');
}
return $user;
}
/**
* Verify registration form
* @param WP_Error $errors
* @param string $sanitized_user_login
* @param string $user_email
*
* @return WP_Error
*/
public function verifyRegisterTurnstile(WP_Error $errors, string $sanitized_user_login, string $user_email):WP_Error
{
// Skip on AJAX requests (for better compatibility with other plugins)
if (wp_doing_ajax()) {
return $errors;
}
// Check Turnstile
if (!$this->verifyTurnstile()) {
$errors->add('turnstile_verification_failed', 'ERROR: Please complete the security check.');
}
return $errors;
}
/**
* Verify lost password form
* @param WP_Error $errors
*
* @return WP_Error
*/
public function verifyLostpasswordTurnstile(WP_Error $errors):WP_Error
{
// Skip on AJAX requests (for better compatibility with other plugins)
if (wp_doing_ajax()) {
return $errors;
}
// Check if the form was submitted
if (!isset($_POST['user_login']) || empty($_POST['user_login'])) {
return $errors ;
}
// Check Turnstile
if (!$this->verifyTurnstile()) {
$redirect_to = isset($_POST['redirect_to']) ? $_POST['redirect_to'] : '';
$errors = new WP_Error('turnstile_verification_failed', 'ERROR: Please complete the security check.');
// WP's lost password form handling
wp_die($errors->get_error_message(), __('Security Check Failed', 'edmonton-ink'), [
'response' => 403,
'back_link' => wp_lostpassword_url($redirect_to)
]);
}
return $errors;
}
}