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:
- WooCommerce → Turnstile Settings → WooCommerce tab
- Tick Block Checkout (
wkcft_block_checkout) - Save
No separate toggle needed. The plugin detects which checkout your page uses and injects accordingly.
How It Differs From Classic
| Aspect | Classic | Blocks |
|---|---|---|
| Rendering | PHP template | React component |
| Widget injection | WooCommerce hooks | Block integration API |
| Submission | Form POST + page reload | Store API AJAX |
| Validation | woocommerce_checkout_process hook | woocommerce_store_api_checkout_update_order_from_request hook |
| Position setting | wkcft_checkout_pos | wkcft_block_checkout_pos |
| Design customization | Design Studio styles applied via CSS | Design Studio styles localized to React |
Widget Position (Blocks)
- Option key:
wkcft_block_checkout_pos
| Value | Position in Blocks Checkout |
|---|---|
beforepay | Above the payment methods block |
afterpay | Below the payment methods block |
beforesubmit | Directly above the Place Order button |
carttotals | Inside 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:
- Registers a script handle that loads the React widget component
- Localizes a config object to
window.wkcftBlockswith site key, theme, appearance, selectors, and design studio styles - 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
- Customer clicks Place Order on Blocks checkout
- React component captures the Turnstile token
- Store API POST includes
extensions['turnstile-captcha'].token - Server hook
woocommerce_store_api_checkout_update_order_from_requestfires - Plugin calls
WKCFT_Validator::wkcft_check($token, 'woocommerce-checkout') - Pass → order created
- 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 guestswkcft_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
- Create a new page in WP admin
- Insert the Checkout block
- Publish + set as the Checkout page under
WooCommerce → Settings → Advanced → Page setup - Add a product to cart
- Go to the new Blocks checkout page
- Widget appears in your configured position
- Place a test order — succeeds
Troubleshooting
| Problem | Fix |
|---|---|
| Widget missing on Blocks checkout | Confirm wkcft_block_checkout = yes. Hard refresh. Check browser console for JS errors |
| "Token failed" on every order | Secret Key wrong — check API Settings tab |
| Widget shows but no design customization applied | Confirm wkcftBlocksDesign in browser console — should have your Design Studio values |
| Widget appears above page header | Your 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 not | You likely have two separate pages. Both need the respective toggle — wkcft_block_checkout covers both |
| Payment method React error | Unrelated 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
