Guide

Form Captcha

Cloudflare Turnstile captcha for the form submission flow. Usually included inside Form Submit. The widget stays hidden until submit begins, then gates the API call.

Namespace

prc-block/form-captcha

Category

forms

Block inserter example

block.json includes an empty example object so the inserter uses default attributes.

Supports

FeatureValue
Spacing (margin)true
Interactivitytrue
HTMLfalse

Attributes

None. State comes from the parent form interactivity context.

Parent / ancestor

No explicit constraint in block.json. Designed to run inside prc-block/form (typically nested under Form Submit).

Usage

  1. Prefer the Form Submit template, which already includes this block.
  2. No inspector config — uses PRC_PLATFORM_TURNSTILE_SITE_KEY.
  3. On submit, the form reveals captcha; after success, submission continues.

Requirements

  • PRC_PLATFORM_TURNSTILE_SITE_KEY must be defined.
  • The Turnstile script is registered and enqueued by the block’s PHP class.

Block markup example

<!-- wp:prc-block/form-captcha /-->

PHP rendering

Fully server-rendered in src/form-captcha/class-form-captcha.php.

  1. Registers Turnstile (explicit render + onloadTurnstileCallback).
  2. Outputs a container with data-wp-interactive="prc-block/form-captcha", targetNamespace pointing at prc-block/form, data-wp-watch="callbacks.onInit", and data-wp-bind--hidden on captcha visibility.
  3. Inner element carries data-sitekey.

Frontend interactivity

Store namespace: prc-block/form-captcha

Callbacks

CallbackDescription
onInitWatches parent captchaHidden. When false, calls turnstile.render(). On success, sets captchaToken and captchaPassed on the parent form context so onCaptchaPassing can submit.

Interaction flow

  1. User clicks submit.
  2. Form onSubmit sets captchaHidden = false.
  3. Captcha onInit renders Turnstile.
  4. User completes the challenge.
  5. Parent gets captchaPassed = true.
  6. Form onCaptchaPassing runs sendSubmission.

Turnstile client errors

view.js registers an error-callback so recoverable Cloudflare errors can retry without throwing (for example code 300031).

OutcomeBehavior
Recoverable errorMay retry; widget stays mounted
Non-retryable (NON_RETRYABLE_TURNSTILE_CODES, e.g. invalid site key)turnstile-error on parent form context; submission blocked
Repeated failuresWidget removed via turnstile.remove(); captcha state resets

User-facing copy: getTurnstileErrorMessage(). See Cloudflare Turnstile client error codes.

Was this helpful?