Turnstile CAPTCHA For WooCommerceTurnstile CAPTCHA For WooCommerce
Buy Now
View Demo
  • Getting Started

    • Introduction
    • Quick Start
    • Features
    • Installation
    • First-Time Setup
    • Get Turnstile Keys
    • Onboarding Wizard
  • Settings

    • Settings Overview
    • API Settings
    • General
    • Design Studio
    • Conditional Rules
    • Per-Form Config
    • Notifications
  • Supported Forms

    • All Supported Forms
    • WooCommerce Forms
    • WordPress Forms
    • Third-Party Form Plugins
    • Checkout Blocks
    • Shortcode
  • Protection & Monitoring

    • Analytics Dashboard
    • Rate Limiting
    • Recovery URL
    • Email Digest
    • Webhooks
  • Developer

    • REST API
    • Filters & Hooks
    • Site Health
  • Compare

    • vs reCAPTCHA
    • vs hCaptcha
  • Help

    • Troubleshooting
    • FAQ
    • Glossary
Support
Buy Now
View Demo
  • Getting Started

    • Introduction
    • Quick Start
    • Features
    • Installation
    • First-Time Setup
    • Get Turnstile Keys
    • Onboarding Wizard
  • Settings

    • Settings Overview
    • API Settings
    • General
    • Design Studio
    • Conditional Rules
    • Per-Form Config
    • Notifications
  • Supported Forms

    • All Supported Forms
    • WooCommerce Forms
    • WordPress Forms
    • Third-Party Form Plugins
    • Checkout Blocks
    • Shortcode
  • Protection & Monitoring

    • Analytics Dashboard
    • Rate Limiting
    • Recovery URL
    • Email Digest
    • Webhooks
  • Developer

    • REST API
    • Filters & Hooks
    • Site Health
  • Compare

    • vs reCAPTCHA
    • vs hCaptcha
  • Help

    • Troubleshooting
    • FAQ
    • Glossary
Support
  • Getting Started

    • Introduction
    • Quick Start — Turnstile Live in 5 Minutes
    • Features — Everything the Plugin Can Do
    • Installation — Full Setup Guide
    • First-Time Setup
    • Get Turnstile Keys from Cloudflare
    • Onboarding Wizard
  • Settings

    • Settings Overview — All 9 Tabs
    • API Settings Tab
    • General Settings Tab
    • Design Studio Tab
    • Conditional Rules Tab
    • Per-Form Config Tab
    • Notifications Tab
  • Supported Forms

    • All Supported Forms
    • WooCommerce Forms
    • WordPress Forms
    • Third-Party Form Plugins
    • Checkout Blocks Integration
    • Shortcode — Drop the Widget Anywhere
  • Protection & Monitoring

    • Analytics Dashboard
    • Rate Limiting — Auto-Lockout for Abusive IPs
    • Recovery URL — Unlock a Stuck IP
    • Email Digest
    • Webhooks — Real-Time Alerts on Bot Spikes
  • Developer

    • REST API
    • Filters & Hooks
    • Site Health Integration
  • Compare

    • Turnstile vs Google reCAPTCHA
    • Turnstile vs hCaptcha
  • Help

    • Troubleshooting
    • Frequently Asked Questions
    • Glossary

Checkout Blocks Integration

The plugin protects both the classic [woocommerce_checkout] shortcode AND the newer Blocks-based checkout — with a single toggle.

What Are Checkout Blocks

WooCommerce introduced the block-based checkout as a React-powered replacement for the classic PHP-rendered checkout. It is:

  • Faster (AJAX-based, no full reloads)
  • More customizable in the block editor
  • Required for some modern payment method features

If your store's /checkout/ page uses the Checkout block (not the [woocommerce_checkout] shortcode), you are on Blocks checkout.

Enable

The enable toggle is shared with classic checkout:

  1. WooCommerce → Turnstile Settings → WooCommerce tab
  2. Tick Block Checkout (wkcft_block_checkout)
  3. Save

No separate toggle needed. The plugin detects which checkout your page uses and injects accordingly.

How It Differs From Classic

AspectClassicBlocks
RenderingPHP templateReact component
Widget injectionWooCommerce hooksBlock integration API
SubmissionForm POST + page reloadStore API AJAX
Validationwoocommerce_checkout_process hookwoocommerce_store_api_checkout_update_order_from_request hook
Position settingwkcft_checkout_poswkcft_block_checkout_pos
Design customizationDesign Studio styles applied via CSSDesign Studio styles localized to React

Widget Position (Blocks)

  • Option key: wkcft_block_checkout_pos
ValuePosition in Blocks Checkout
beforepayAbove the payment methods block
afterpayBelow the payment methods block
beforesubmitDirectly above the Place Order button
carttotalsInside the cart totals sidebar summary

Integration Implementation (Developer Detail)

The plugin registers a WooCommerce Blocks IntegrationInterface:

  • Class: WKCFT_Block_Checkout_Integration
  • Name: turnstile-captcha
  • Script handle: turnstile-block-checkout
  • Registration hook: woocommerce_blocks_checkout_block_registration

The class:

  1. Registers a script handle that loads the React widget component
  2. Localizes a config object to window.wkcftBlocks with site key, theme, appearance, selectors, and design studio styles
  3. Fires validation via Store API hook on order placement

Script Data Passed to JS

window.wkcftBlocks = {
  site_key: '0x4AAA...',
  is_required: true,
  theme: 'light',
  appearance: 'always',
  enabled: true,
  disable_submit: 'no',
  load_mode: 'instant',
  lazy_delay: 2000,
  selectors: {
    checkout: '#place_order',
    pay: 'button#place_order',
    login: 'button[name="login"]',
    register: 'button[name="register"]'
  }
};

window.wkcftBlocksDesign = {
  // Design Studio wrapper styles + label/helper markup
};

Validation Flow

  1. Customer clicks Place Order on Blocks checkout
  2. React component captures the Turnstile token
  3. Store API POST includes extensions['turnstile-captcha'].token
  4. Server hook woocommerce_store_api_checkout_update_order_from_request fires
  5. Plugin calls WKCFT_Validator::wkcft_check($token, 'woocommerce-checkout')
  6. Pass → order created
  7. Fail → Store API throws RouteException with HTTP 400, React shows error

Compatibility Declared

The plugin declares compatibility with cart_checkout_blocks so WooCommerce does not show the "plugin may not be compatible" warning.

This declaration sits in the main plugin file:

\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
  'cart_checkout_blocks',
  WKCFT_FILE,
  true
);

Same applies to HPOS (custom_order_tables).

Design Studio Styles in Blocks

The full Design Studio styling is passed to the React component via wkcftBlocksDesign. This means:

  • Background / border / shadow from Design Studio apply in Blocks too
  • Label and helper text render in Blocks
  • Widget size and theme override apply

No extra configuration needed — setting Design Studio once covers both checkouts.

Visibility Rules (Logged-In / Guest Only)

The plugin respects the same visibility rules on Blocks:

  • wkcft_logged_in_only — widget hides for guests
  • wkcft_checkout_guest_only — widget hides for logged-in

Logic (pseudo):

if (both on) or (both off) → show for everyone
else if (guest_only && !logged_in) → show
else if (logged_in_only && logged_in) → show
else → hide

Test the Integration

  1. Create a new page in WP admin
  2. Insert the Checkout block
  3. Publish + set as the Checkout page under WooCommerce → Settings → Advanced → Page setup
  4. Add a product to cart
  5. Go to the new Blocks checkout page
  6. Widget appears in your configured position
  7. Place a test order — succeeds

Troubleshooting

ProblemFix
Widget missing on Blocks checkoutConfirm wkcft_block_checkout = yes. Hard refresh. Check browser console for JS errors
"Token failed" on every orderSecret Key wrong — check API Settings tab
Widget shows but no design customization appliedConfirm wkcftBlocksDesign in browser console — should have your Design Studio values
Widget appears above page headerYour theme or a customization plugin moves the Checkout block to a weird position. Move the widget via wkcft_block_checkout_pos
Blocks checkout works but classic does notYou likely have two separate pages. Both need the respective toggle — wkcft_block_checkout covers both
Payment method React errorUnrelated to Turnstile. Check payment gateway plugin

Disable Blocks While Keeping Classic

Some stores want Turnstile on the classic checkout only and not Blocks (or vice versa). There is no built-in toggle for this — both use the same wkcft_block_checkout option.

Workaround via filter:

add_filter('wkcft_conditions_should_skip', function($skip, $context) {
    if ($context === 'woocommerce-checkout') { // Blocks context slug
        return true; // skip Blocks
    }
    return $skip;
}, 10, 2);

Related Pages

  • WooCommerce Forms — Classic checkout + other WC forms
  • Design Studio — Styles apply to both checkouts
  • Supported Forms — All form slugs
  • REST API — Verify endpoint for headless Blocks integrations
Prev
Third-Party Form Plugins
Next
Shortcode — Drop the Widget Anywhere