"; } cfturnstile_field_show('', '', 'woocommerce-checkout', '-woo-checkout'); ?> get_method() === 'POST' ) { if ( $request->get_param('payment_method') !== null ) { $chosen_payment_method = sanitize_text_field( $request->get_param('payment_method') ); // Retrieve the selected payment methods from the cfturnstile_selected_payment_methods option $selected_payment_methods = get_option('cfturnstile_selected_payment_methods', array()); if(is_array($selected_payment_methods)) { // Check if the chosen payment method is in the selected payment methods array if ( in_array( $chosen_payment_method, $selected_payment_methods, true ) ) { $skip = 1; } } } // Additional skip: WooPayments Express or Stripe Express (Apple Pay / Google Pay / Link) on block checkout. if ( ! $skip ) { $payment_method = $request->get_param( 'payment_method' ); $payment_data = $request->get_param( 'payment_data' ); $express_detected = false; if ( is_array( $payment_data ) ) { foreach ( $payment_data as $pd_item ) { if ( is_array( $pd_item ) && isset( $pd_item['key'] ) ) { $key = $pd_item['key']; $value = isset( $pd_item['value'] ) ? $pd_item['value'] : ''; if ( in_array( $key, array( 'express_payment_type', 'payment_request_type' ), true ) && ! empty( $value ) ) { $express_detected = true; break; } } } // Allow customization via filter, defaults to skip when WooPayments or Stripe express is detected. $skip_on_express = apply_filters( 'cfturnstile_skip_on_express_pay', ( ($payment_method === 'woocommerce_payments' || $payment_method === 'stripe') && $express_detected ), $payment_method, $payment_data, $request ); if ( $skip_on_express ) { $skip = 1; } } } // Check if guest only enabled $guest = esc_attr( get_option('cfturnstile_guest_only') ); // Check — always require a fresh Turnstile token (tokens are single-use). if( !$skip && (!$guest || ( $guest && !is_user_logged_in() )) ) { $extensions = $request->get_param( 'extensions' ); $token = ( is_array( $extensions ) && isset( $extensions['simple-cloudflare-turnstile']['token'] ) ) ? $extensions['simple-cloudflare-turnstile']['token'] : ''; if ( empty( $token ) ) { throw new \Exception( cfturnstile_failed_message() ); } // Store token so the cleanup callback can access it. global $cfturnstile_block_checkout_token; $cfturnstile_block_checkout_token = $token; // If this token already passed verification, skip re-check. if ( cfturnstile_get_verified( 'cfturnstile_block_checkout_checked', $token ) ) { $cfturnstile_wc_block_checkout_ran = true; return; } $check = cfturnstile_check( $token ); $success = $check['success']; $cfturnstile_wc_block_checkout_ran = true; if($success != true) { throw new \Exception( cfturnstile_failed_message() ); } else { cfturnstile_set_verified( 'cfturnstile_block_checkout_checked', $token, 120 ); } } } } // Clear checkout verification transients after all validation hooks have run add_action('woocommerce_after_checkout_validation', 'cfturnstile_woo_checkout_clear_transient', 9999); function cfturnstile_woo_checkout_clear_transient() { cfturnstile_clear_verified( 'cfturnstile_checkout_checked' ); } // Block checkout: clear the transient after the order is processed add_action('woocommerce_store_api_checkout_order_processed', 'cfturnstile_woo_block_checkout_clear_transient', 9999); function cfturnstile_woo_block_checkout_clear_transient() { global $cfturnstile_block_checkout_token; if ( ! empty( $cfturnstile_block_checkout_token ) ) { cfturnstile_clear_verified( 'cfturnstile_block_checkout_checked', $cfturnstile_block_checkout_token ); } } add_action('woocommerce_loaded', 'cfturnstile_register_endpoint_data', 20); function cfturnstile_register_endpoint_data() { if ( ! function_exists( 'woocommerce_store_api_register_endpoint_data' ) ) { return; } woocommerce_store_api_register_endpoint_data( array( 'endpoint' => 'checkout', 'namespace' => 'simple-cloudflare-turnstile', 'schema_callback' => function() { return array( 'token' => array( 'description' => __( 'Turnstile token.', 'simple-cloudflare-turnstile' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'sanitize_callback' => 'sanitize_text_field', ), ); }, ) ); } } // Woo Checkout Pay Order Check if(get_option('cfturnstile_woo_checkout_pay')) { add_action('woocommerce_pay_order_before_submit', 'cfturnstile_field_checkout', 10); add_action('woocommerce_before_pay_action', 'cfturnstile_woo_checkout_pay_check', 10, 2); function cfturnstile_woo_checkout_pay_check($order) { $check = cfturnstile_check(); $success = $check['success']; if($success != true) { wc_add_notice( cfturnstile_failed_message(), 'error'); } } } // Woo Login Check if(get_option('cfturnstile_woo_login')) { add_action('woocommerce_login_form','cfturnstile_field_woo_login'); if(!get_option('cfturnstile_login')) { add_action('authenticate', 'cfturnstile_woo_login_check', 21, 1); function cfturnstile_woo_login_check($user) { // Check skip if(!isset($user->ID)) { return $user; } if(!isset($_POST['woocommerce-login-nonce'])) { return $user; } // Skip if not WooCommerce login if(defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST) { return $user; } // Skip XMLRPC if(defined( 'REST_REQUEST' ) && REST_REQUEST) { return $user; } // Skip REST API if(is_wp_error($user) && isset($user->errors['empty_username']) && isset($user->errors['empty_password']) ) {return $user; } // Skip Errors // Check if already validated (cache-friendly, no PHP session) if( cfturnstile_get_verified( 'cfturnstile_login_checked' ) ) { return $user; } // Check Turnstile $check = cfturnstile_check(); $success = $check['success']; if($success != true) { $user = new WP_Error( 'cfturnstile_error', cfturnstile_failed_message() ); } else { cfturnstile_set_verified( 'cfturnstile_login_checked' ); } return $user; } // Clear verification flag on login add_action('wp_login', 'cfturnstile_woo_login_clear', 10, 2); function cfturnstile_woo_login_clear($user_login, $user) { cfturnstile_clear_verified( 'cfturnstile_login_checked' ); } } } // WP login check to skip when Woo login is disabled add_filter( 'cfturnstile_wp_login_checks', 'cfturnstile_woo_skip_wp_login_check', 10, 1 ); function cfturnstile_woo_skip_wp_login_check( $skip ) { // If the WooCommerce login integration is disabled but a Woo login form is submitted, // skip the global WordPress login Turnstile check. if ( ! get_option( 'cfturnstile_woo_login' ) && isset( $_POST['woocommerce-login-nonce'] ) ) { return true; } return $skip; } // Woo Register Check if(get_option('cfturnstile_woo_register')) { add_action('woocommerce_register_form','cfturnstile_field_woo_register'); if(!is_admin()) { // Prevents admin registration from failing add_action('woocommerce_register_post', 'cfturnstile_woo_register_check', 10, 3); } function cfturnstile_woo_register_check($username, $email, $validation_errors) { if(defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST) { return; } // Skip XMLRPC if(defined( 'REST_REQUEST' ) && REST_REQUEST) { return; } // Skip REST API if(!is_checkout()) { $check = cfturnstile_check(); $success = $check['success']; if($success != true) { $validation_errors->add( 'cfturnstile_error', cfturnstile_failed_message() ); } } } } // Woo Reset Check if(get_option('cfturnstile_woo_reset')) { add_action('woocommerce_lostpassword_form','cfturnstile_field_woo_reset'); add_action('lostpassword_post','cfturnstile_woo_reset_check', 10, 1); function cfturnstile_woo_reset_check($validation_errors) { if(isset($_POST['woocommerce-lost-password-nonce'])) { $check = cfturnstile_check(); $success = $check['success']; if($success != true) { $validation_errors->add( 'cfturnstile_error', cfturnstile_failed_message() ); } } } } // Check if WooCommerce block checkout page function cfturnstile_is_block_based_checkout() { if ( function_exists('is_checkout') && is_checkout() && !isset($_GET['pay_for_order']) ) { $checkout_page_id = wc_get_page_id( 'checkout' ); if ( $checkout_page_id && has_block( 'woocommerce/checkout', get_post( $checkout_page_id )->post_content ) ) { return true; } } return false; }