1/* Woo Checkout */ 2jQuery( document ).ready(function() { 3 4 var cfturnstileWooCheckoutAttempted = false; 5 6 // Track actual submission attempts so we don't reset on every checkout refresh. 7 jQuery( document.body ).on( 'submit', 'form.checkout', function() { 8 cfturnstileWooCheckoutAttempted = true; 9 }); 10 11 // If the page loads with an existing checkout error force a reset so the next submission has a fresh token. 12 if ( jQuery('.woocommerce-error, .woocommerce-NoticeGroup-checkout .woocommerce-error').length ) { 13 setTimeout( turnstileWooCheckoutReset, 50 ); 14 } 15 16 jQuery( document.body ).on( 'update_checkout updated_checkout applied_coupon_in_checkout removed_coupon_in_checkout', function() { 17 // Re-render if the widget container was replaced/emptied or is missing entirely. 18 var $widget = jQuery('#cf-turnstile-woo-checkout'); 19 if ( !$widget.length || $widget.is(':empty') ) { 20 // Use longer delay to ensure DOM replacement is complete. 21 setTimeout( turnstileWooCheckoutReset, 300 ); 22 return; 23 } 24 25 // After a failed submit, Woo will typically refresh the checkout fragments. 26 // Reset here (only after an attempted submit) to avoid the stale/used token issue. 27 if ( cfturnstileWooCheckoutAttempted && jQuery('.woocommerce-error, .woocommerce-NoticeGroup-checkout .woocommerce-error').length ) { 28 setTimeout( turnstileWooCheckoutReset, 300 ); 29 cfturnstileWooCheckoutAttempted = false; 30 } 31 }); 32 33 // Woo triggers this when the AJAX checkout submission returns an error. 34 jQuery( document.body ).on( 'checkout_error', function() { 35 setTimeout( turnstileWooCheckoutReset, 500 ); 36 cfturnstileWooCheckoutAttempted = false; 37 }); 38}); 39function turnstileWooCheckoutReset() { 40 if ( typeof turnstile === 'undefined' ) { 41 return; 42 } 43 44 var el = document.getElementById('cf-turnstile-woo-checkout'); 45 if ( !el ) { 46 return; 47 } 48 49 // If Woo replaced the container and it's now empty, render a fresh widget. 50 if ( !el.innerHTML || el.innerHTML.trim() === '' ) { 51 try { 52 turnstile.render(el); 53 } catch (e) { 54 try { turnstile.render('#cf-turnstile-woo-checkout'); } catch (e2) {} 55 } 56 return; 57 } 58 59 // Preferred: reset the existing widget (clears the used/expired token). 60 try { 61 if ( typeof turnstile.reset === 'function' ) { 62 turnstile.reset(el); 63 return; 64 } 65 } catch (e) {} 66 67 // Fallback: remove + render. 68 try { 69 turnstile.remove(el); 70 } catch (e) { 71 try { turnstile.remove('#cf-turnstile-woo-checkout'); } catch (e2) {} 72 } 73 try { 74 turnstile.render(el); 75 } catch (e) { 76 try { turnstile.render('#cf-turnstile-woo-checkout'); } catch (e2) {} 77 } 78} 79 80/* On click "show login" link re-render */ 81jQuery('.showlogin, .show-login, .e-show-login, .woocommerce-form-login-toggle a').on('click', function() { 82 setTimeout(function() { 83 turnstile.remove('.sct-woocommerce-login'); 84 turnstile.render('.sct-woocommerce-login'); 85 }, 250); 86}); 87 88/* Woo Checkout Block */ 89document.addEventListener('DOMContentLoaded', function() { 90 if (typeof wp !== 'undefined' && wp.data && typeof turnstile !== 'undefined') { 91 92 function setTurnstileExtensionData(token) { 93 var dispatch = wp.data.dispatch('wc/store/checkout'); 94 if (!dispatch) return; 95 if (typeof dispatch.setExtensionData === 'function') { 96 dispatch.setExtensionData('simple-cloudflare-turnstile', { token: token }); 97 } else if (typeof dispatch.__internalSetExtensionData === 'function') { 98 dispatch.__internalSetExtensionData('simple-cloudflare-turnstile', { token: token }); 99 } 100 } 101 102 function cfturnstileWooBlockCheckoutRender() { 103 104 var turnstileItem = document.getElementById('cf-turnstile-woo-checkout'); 105 if (!turnstileItem) return; 106 107 // If already initialized, try reset to preserve state but clear token 108 if (turnstileItem.getAttribute('data-sct-init') === 'true' && turnstileItem.hasChildNodes()) { 109 try { 110 turnstile.reset(turnstileItem); 111 setTurnstileExtensionData(''); 112 return; 113 } catch (e) {} 114 } 115 116 // Ensure any existing widget (auto-rendered or otherwise) is removed 117 try { turnstile.remove(turnstileItem); } catch (e) {} 118 119 try { 120 turnstile.render(turnstileItem, { 121 sitekey: turnstileItem.dataset.sitekey, 122 appearance: turnstileItem.dataset.appearance || 'always', 123 callback: setTurnstileExtensionData, 124 'expired-callback': function() { setTurnstileExtensionData(''); } 125 }); 126 turnstileItem.setAttribute('data-sct-init', 'true'); 127 } catch (e) {} 128 } 129 130 // Re-render Turnstile after the Place order button is clicked 131 var cfturnstileWooBlockClickTimer = null; 132 jQuery(document.body).on('click', '.wc-block-components-checkout-place-order-button', function() { 133 if (cfturnstileWooBlockClickTimer) { 134 clearTimeout(cfturnstileWooBlockClickTimer); 135 } 136 cfturnstileWooBlockClickTimer = setTimeout(function() { 137 cfturnstileWooBlockCheckoutRender(); 138 }, 2000); 139 }); 140 141 // Render Turnstile when the checkout data is updated and the widget is not present or not initialized 142 var unsubscribe = wp.data.subscribe(function() { 143 const turnstileItem = document.getElementById('cf-turnstile-woo-checkout'); 144 if (turnstileItem && (turnstileItem.innerHTML.trim() === '' || turnstileItem.getAttribute('data-sct-init') !== 'true')) { 145 cfturnstileWooBlockCheckoutRender(); 146 } 147 }, 'wc/store/cart'); 148 } 149});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.