Turnstile for HivePress WP Registry grade A. No security issues foundWP RegistryNo security issues foundOpen the reportA
Acts as a bridge between HivePress and the free Cloudflare Turnstile plugin
Install
Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/irapidchris-del/turnstile-for-hivepress/releases/download/v2.4.1/turnstile-for-hivepress.zipProtects HivePress forms with Cloudflare Turnstile, using HivePress's own native captcha field system for full modal and AJAX support.
Requirements
| Plugin | Required |
|---|---|
| HivePress | yes |
| Simple Cloudflare Turnstile | yes |
| HivePress Bookings | optional (adds Confirm Booking) |
| HivePress Claim Listings | optional (adds Claim Listing) |
| HivePress Marketplace | optional (adds Dispute Order) |
| HivePress Requests | optional (adds Submit Request / Submit Offer) |
| HivePress Reviews | optional (adds Write a Review / Reply to Review) |
| HivePress Messages | optional (adds Send Message) |
Enter your Turnstile Site Key and Secret Key in Settings → Simple Cloudflare Turnstile first.
Setup
- Install and activate the plugin.
- Go to Settings → Simple Cloudflare Turnstile and enter your keys.
- Open the HivePress accordion at the bottom of that page.
- Tick the forms you want to protect under Protected Forms and Save.
Protected forms
The form list is built dynamically from whatever HivePress reports as captcha-capable, so any extension that registers a captcha-enabled form appears automatically. With the common extensions installed the options are:
| Form | Source |
|---|---|
| Login User | Core |
| Register User | Core |
| Reset Password | Core |
| Submit Listing | Core |
| Report Listing | Core |
| Confirm Booking | Bookings |
| Claim Listing | Claim Listings |
| Dispute Order | Marketplace |
| Submit Request | Requests |
| Submit Offer | Requests |
| Write a Review | Reviews |
| Reply to Review | Reviews |
| Send Message | Messages |
How it works
This plugin mirrors HivePress's own reCAPTCHA implementation
(includes/components/class-form.php), but renders a Cloudflare Turnstile
widget instead of Google reCAPTCHA.
For each protected form it uses the same three HivePress hooks core uses:
hivepress/v1/forms/{form}/meta- flips the form'scaptchameta flag to true.hivepress/v1/forms/{form}- injects a real HivePress field of typehptu_turnstile.hivepress/v1/forms/{form}/errors- verifies the token viacfturnstile_check().
Because the widget is added as a genuine form field (rendered inside
hp-form__fields), rather than as footer HTML, it appears correctly in every
context HivePress supports - including the login, register and reset-password
modal popups - with no per-modal special-casing.
The custom field class is declared in HivePress's own \HivePress\Fields
namespace (as \HivePress\Fields\Hptu_Turnstile) so HivePress resolves the
field type hptu_turnstile to it directly.
Modal rendering
Cloudflare's auto-render breaks on elements that are hidden at page load, which
is the case for modal forms (HivePress prints them hidden in the page footer).
To handle this, the Cloudflare API is loaded in explicit mode
(api.js?render=explicit, so nothing auto-renders) and js/turnstile-render.js
renders each widget itself:
- Page widgets render as soon as they become visible (IntersectionObserver, with a MutationObserver re-scan for AJAX-injected forms).
- Modal widgets render only on FancyBox's
afterShow- after HivePress has moved the modal's DOM node into the FancyBox overlay - and are torn down on close, so every open renders a fresh, working widget. - Form submission is gated until a fresh token is present, and widgets are reset after each HivePress AJAX submission (tokens are single-use).
The widget div deliberately does not use Cloudflare's cf-turnstile
class name, so that if the Simple Cloudflare Turnstile plugin loads its own
auto-render copy of the API on the same page (e.g. to protect the comment
form), it never touches this plugin's widgets. If both API copies do end up
enqueued on one page, this plugin drops its own copy and shares SCT's.
All keys, theme, language, size, appearance and server-side verification come from the Simple Cloudflare Turnstile plugin, so its settings apply automatically.
Using HivePress's built-in reCAPTCHA at the same time
HivePress's own reCAPTCHA (Settings → Integrations) and this plugin share HivePress's captcha field system. If reCAPTCHA keys are configured, every form protected by this plugin will show both widgets and require both to pass, even when that form is not ticked in HivePress's own Protected Forms list (HivePress keys its captcha handling off the shared meta flag this plugin flips). If you are migrating to Turnstile, remove the reCAPTCHA keys from HivePress settings. A warning is shown in the settings panel when this situation is detected.
The WordPress login page
inc/login.php is the one part of this plugin that is not about HivePress
forms. Simple Cloudflare Turnstile can put its widget on the wp-login.php
login, register and reset-password forms, and Cloudflare draws the standard
widget at a fixed 300px. WordPress gives that form a 270px content column
(wp-admin/css/login.css: #login { width: 320px }, .login form takes 24px
of padding each side plus a 1px border), so the widget was drawn 30px wider
than the username and password fields. SCT then pulls it 15px to the left on
this page (inc/turnstile.php, cfturnstile_admin_styles()), spreading the
extra 30px evenly, which leaves it hanging over both edges of the field
column.
The plugin adds inline CSS on that page, attached to WordPress's own login
stylesheet handle. It undoes SCT's 15px pull, so the widget starts where the
fields start, then scales it to the field width with a CSS transform - the
same technique fitWidget() in js/turnstile-render.js uses for narrow
modals, which keeps the Cloudflare iframe fully clickable. The margin override
needs !important, because SCT writes that margin against the widget's
generated id and an id beats any selector built from classes.
Nothing is added to wp-login.php in JavaScript: a script error on that page costs the owner access to their own site, and every measurement involved is a WordPress core constant.
The CSS is only printed when SCT is configured and one of its three WordPress
form options is switched on. The compact size (150px) gets the alignment but
no scaling, because it already fits. Sites whose login page has been restyled
to a different width can filter tfhp_login_form_width to the width their
fields are drawn at.
Cloudflare outage behaviour
The plugin honours Simple Cloudflare Turnstile's failsafe setting. When the failsafe is enabled and Cloudflare is unreachable, protected HivePress forms temporarily submit without a challenge, exactly like SCT's own forms. Without the failsafe, submissions are rejected until Cloudflare recovers. Client-side, the submit gate also stands down if the Turnstile script never loads, so forms are never bricked by an outage; the server remains the authority.
Updates
The plugin updates itself from this repository's GitHub Releases using
WordPress's own native update mechanism (the update_plugins_github.com filter,
WP 5.8+, keyed off the plugin's Update URI header) - no third-party library.
New versions appear on your Plugins screen like any other plugin: update
notice, "View details" changelog, and one-click update, with no WordPress.org
listing needed.
WordPress checks automatically; you can force a check via Dashboard → Updates → Check again, or the plugin's Check for updates link on the Plugins screen.
To always download the latest version directly:
https://github.com/irapidchris-del/turnstile-for-hivepress/releases/latest/download/turnstile-for-hivepress.zip
(Maintainers: see RELEASING.md for the release process.)
Changelog
2.3.1
- A solved captcha is no longer wiped while you are still filling the form in. The widget was reset by any background request HivePress made, which on the listing submission form meant every photo upload and every tag suggestion, so pressing Submit could answer "please verify that you are human" to somebody who just had. Only the form that was actually submitted is reset now.
- The captcha is no longer shown when Simple Cloudflare Turnstile is not active. Its settings stay in the database when it is deactivated, so a live Cloudflare widget carried on appearing on every protected form while nothing checked the answer, and any submission was accepted. The forms are now left unprotected and visibly so, and the existing admin notice explains what to reinstall.
- Simple Cloudflare Turnstile's "Failsafe Mode" no longer holds up page loading. Its check on whether Cloudflare is reachable was run while the page was being built, and with Cloudflare slow that added five seconds to the page for every visitor. The answer is now looked up in the background.
- Deleting the plugin now also clears the update check's own leftovers and cancels its background update check.
2.3.0
- The Turnstile widget on the WordPress login page now lines up with the
username and password fields. Cloudflare draws the standard widget at a
fixed 300px, which is 30px wider than the fields WordPress gives that page,
and Simple Cloudflare Turnstile nudges it a further 15px to the left there,
so it hung over both sides of the fields and ran into the edge of the login
box. The widget is now placed and sized to the same column as the fields,
and stays fully clickable. It applies only where Simple Cloudflare Turnstile
is protecting the WordPress login, registration or password reset form,
nothing else on that page is changed, and no JavaScript is added to it.
Sites whose login page has been restyled to a different width can set that
width with the new
tfhp_login_form_widthfilter.
2.2.3
- Checking for updates no longer holds up an admin page. The check ran while WordPress was building the Plugins screen, so on a site with several of these extensions one page load made one request to GitHub after another and could sit there for many seconds, once, before behaving normally again for hours. The check now runs in the background moments later. Pressing Check for updates still asks GitHub straight away, because you are waiting for that answer.
- "View details" is back on the Plugins screen. WordPress only offers that link for a plugin that has told it about itself, and this one stayed quiet whenever there was nothing to update to, which is almost always.
2.2.2
- Checking for updates no longer reports "Could not reach GitHub" when nothing is wrong. GitHub allows a server only a limited number of anonymous update checks each hour, shared by every plugin on the site. Update checks now read the release from github.com, which sets no such limit.
- A failed update check no longer hides an update that is genuinely waiting. The last successful answer is kept until a later check succeeds.
2.2.1
- Fixed the plugin's own link on the Plugins screen, which pointed at the community forum home page rather than the plugin's source.
2.2.0
- Deleting the plugin now keeps your settings. Your list of protected forms survives a delete and reinstall, and is only erased if you tick the new "Delete all data when this plugin is deleted" box in the HivePress section of the Turnstile settings page. WordPress shows its own warning about deleting data on the delete screen, but it does not apply here unless you tick that box.
- Renamed the internal captcha field class (
\HivePress\Fields\Turnstileto\HivePress\Fields\Hptu_Turnstile, field typeturnstiletohptu_turnstile) so it can never clash with HivePress core or a future official extension. HivePress has said it may add its own Turnstile integration, and without this an update to HivePress could have quietly replaced this plugin's widget with a different one. - Added a Donate link to the plugin's row on the Plugins screen and to its "View details" popup.
- Update checks no longer send your site address or WordPress version to GitHub; the request now identifies only the plugin and its version.
- Corrected the author credit shown on the Plugins screen.
2.1.3
- Fixed the widget overflowing narrow modals on small phones. Cloudflare draws the standard widget at a fixed 300px, so inside tight popups (viewports around 350px and below) it ran past the modal edge and clipped. The widget now scales down to fit its container, stays fully interactive, and re-fits on rotation or resize. Verified at 320px, 360px and 390px. Found during the staging pass on a real-device viewport.
2.1.2
- Translations now load through WordPress's own just-in-time mechanism from the plugin headers, matching HivePress core and every official extension. Translate via Loco Translate into the WordPress languages folder; the bundled template file (.pot) is regenerated with the official WordPress tooling.
- Full compatibility sweep against every captcha-capable form from all 18 HivePress extensions (14 forms), all six official themes, the Social Login extension, and the Autoptimize JS/CSS optimiser.
2.1.1
- The plugin now honours Simple Cloudflare Turnstile's Cloudflare-down failsafe: when it is enabled and Cloudflare is unreachable, protected forms submit without a challenge instead of being blocked for the whole outage. The submit gate also stands down client-side if the Turnstile script never loads, letting the server decide.
- Submitting a protected form before completing the widget now shows a clear message in the form instead of silently doing nothing.
- The SCT "failure message" option now works on HivePress forms: the message appears below the widget when Turnstile reports an error and clears on success.
- Fixed the coexistence warning wording: with HivePress reCAPTCHA keys set, every Turnstile-protected form shows both captchas regardless of the HivePress form selection.
- The manual update check now distinguishes "GitHub unreachable" from "no installable release published yet".
- Added Claim Listing, Submit Request and Submit Offer to the documented form list (auto-discovery already found them).
- Added a Settings quick link on the Plugins screen; script versions now include the file modification time so updates can never serve stale JavaScript from browser caches.
- Housekeeping: author credit links to the HivePress community profile, WordPress/PHP requirement headers corrected, uninstall also removes the cached release lookup.
2.1.0
- Added self-updating from GitHub Releases using WordPress's native
update_plugins_github.comfilter (WP 5.8+) - no third-party library. New versions show on the Plugins screen with update notifications, a "View details" changelog, one-click updates, and a "Check for updates" row action. - Updates install a fixed-name release asset built with a version-less top folder, so WordPress always lands the plugin in the correct directory.
- Added a GitHub Actions release workflow that builds and attaches the release asset automatically.
2.0.8
- Pre-release audit: every integration point was verified against the actual HivePress and Simple Cloudflare Turnstile source code (form filter cascade, field class contract, settings hooks, option names and verification API).
- Removed the
cf-turnstileclass from the widget container. When SCT loads its own auto-render copy of the Cloudflare API on the same page (e.g. for the comment form), it auto-renders every.cf-turnstileelement - including our hidden modal widgets, breaking them. Our widgets are rendered explicitly via.tfhp-turnstileand no longer need (or want) Cloudflare's class name. - If both this plugin's and SCT's copies of the Cloudflare API end up on the
same page, ours is now dropped before printing so only one copy loads
(Cloudflare recommends a single
api.jsper page). - Added a settings-panel warning when HivePress's built-in reCAPTCHA is also configured: forms protected by both will show and enforce both captchas.
- Frontend scripts and resource hints are no longer output when HivePress is inactive but form selections remain saved.
- Hardening: explicit
manage_optionscapability check in the settings save handler (the WordPress options flow already enforces it). - Uninstall cleanup moved to
uninstall.php(WordPress's preferred mechanism). - Dependency notices are now translatable; added
Requires at least,Requires PHPandDomain Pathheaders and textdomain loading. - Fixed the README version (it still said 2.0.0) and corrected the stale
data-execution="execute"description of how modal rendering works.
2.0.7
- Fixed the widget going missing when switching between login / register / reset-password and back. HivePress switches modals with $.fancybox.close() + $.fancybox.open() in quick succession; in that race FancyBox's afterClose can be skipped, leaving the modal's widget flagged as "already rendered" with a now-broken iframe, so returning to it showed no widget. Each modal open is now fully self-healing: it tears down any stale widget in that modal and renders a fresh one every time, so the widget shows reliably no matter how many times you switch back and forth.
2.0.6
- Eliminated the "postMessage origin" error storm. HivePress modals are opened with FancyBox, which MOVES the modal's DOM node into its overlay (and back on close). Rendering the Turnstile widget before/during that move broke the widget's iframe handshake. Modal widgets now render only after FancyBox finishes opening (afterShow), and are fully removed on close so the next open renders cleanly in the relocated node.
- The DOM observer no longer watches attribute changes (it was firing on every class/style change during the modal animation), removing the render storm.
- Page (non-modal) forms are unchanged: they render as soon as they're visible.
2.0.5
- Fixed a fatal JS error ("':submit' is not a valid selector") that crashed the submit handler - :submit is a jQuery-only selector and is invalid in native querySelector. This was breaking the submit-gating and token handling.
- Stopped the Turnstile "postMessage origin" errors by (a) debouncing the DOM observer so the widget no longer renders during a modal's open animation, and (b) requiring the widget to have real width before rendering.
- Note: the /users/request-password/ 404 seen in the console is HivePress core REST behaviour (it probes with a trailing slash) and is unrelated to this plugin.
2.0.4
- Fixed the widget disappearing in 2.0.3: reverted to footer loading of the Cloudflare API (the head/async change interacted badly with JS-optimisation plugins).
- Made the render script independent of jQuery so the widget still renders even when a JS-optimisation plugin (e.g. FlyingPress "Delay JavaScript") delays jQuery. The optional token-reset and modal hooks attach once jQuery appears.
- Updated/expanded the delay & defer exclusion filters for FlyingPress, Perfmatters and WP Rocket, and added an in-settings note listing the exact keywords to exclude if the widget still doesn't show.
- Kept the 2.0.3 submit-gating fix (no submit until a fresh token is present).
2.0.3
- Fixed the wrong-password retry failure: the form now blocks submission until a fresh Turnstile token is present, so a consumed/empty token is never re-sent. This is the same submit-gating approach Simple Cloudflare Turnstile uses for the WordPress login form.
- Faster widget appearance: the Cloudflare API now loads async in the document head (instead of deferred in the footer) and a preconnect hint is added, so the widget renders with much less lag.
- Removed all plugin-side console output. Remaining console messages on the page originate from Cloudflare's own api.js and from JS-optimisation preloading; they are harmless.
2.0.2
- Fixed the "Please verify that you are human." error on valid submissions: the Turnstile widget is now reset after every HivePress form submission so a fresh, single-use token is issued for the next attempt (tokens are consumed on verification, so a stale token was being re-sent on retries).
- Removed turnstile.ready() - it is incompatible with async/defer loading of api.js (enforced by JS-optimisation plugins like FlyingPress). The widget now polls for the API and calls turnstile.render() directly, which is defer-safe.
- Loads the Cloudflare API under a dedicated handle in explicit mode and excludes it (and the render script) from FlyingPress / Perfmatters / WP Rocket JS delay/defer, fixing intermittent invisible widgets and preload warnings.
- Added retries when a modal opens so the widget renders reliably during the modal's open animation.
2.0.0
- Rewritten to use HivePress's native captcha field system.
- Single dynamic Protected Forms selector instead of per-form toggles.
- Full modal support (login / register / reset password) via a real form field plus explicit visibility-based widget rendering.
- Server-side verification via the form
/errorsfilter (no separate REST interception layer). - Form list now auto-discovers any captcha-capable form from any extension.
1.x
- Earlier footer-injection + REST-interception approach (superseded).
Releases
10 releases. Each count is every asset in that release; expand a row for the breakdown.