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 '
'; echo '
'; 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; } }