OliWeb Proof-of-Work for Cap self-updates
WordPress plugin for Cap — self-hosted proof-of-work CAPTCHA integration for forms and comments.
by OliWeb · github.com/oliweb-ch/oliweb-proof-of-work-for-cap · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/oliweb-ch/oliweb-proof-of-work-for-cap/archive/refs/heads/main.zipShips its own WordPress updater (Plugin Update Checker), so new versions show up under Dashboard → Updates.
WordPress plugin to integrate Cap — a self-hosted proof-of-work CAPTCHA — into WordPress forms.
No external dependencies: built entirely on native WordPress APIs. The WebAssembly module is bundled locally within the plugin.
Requirements
- PHP 8.2+
- WordPress 6.4+
- A self-hosted Cap instance
Installation
- Copy the
tilivier-pow-for-cap/folder intowp-content/plugins/ - Activate the plugin from Plugins in the WordPress admin
- Go to Settings > PoW for Cap and enter your endpoint and secret key
The plugin ships with all required assets (JS, CSS, WASM). No build step or additional download required.
Configuration
Go to Settings > PoW for Cap in the WordPress admin.
| Field | Description | Default |
|---|---|---|
| Endpoint URL | Full URL of your Cap instance, including the site key (e.g. https://cap.example.com/your-site-key/) |
— |
| Secret Key | Secret key generated in the Cap dashboard (never expose client-side) | — |
| Token Field Name | Name of the hidden field injected by the widget | cap-token |
| Timeout (seconds) | Request timeout for /siteverify calls |
5 |
| Fail Open | If checked, allows requests through on Cap communication errors | unchecked |
| Hide Attribution Link | If checked, hides the "Cap" attribution link at the bottom right of the widget | unchecked |
Fail-open mode
By default, any communication error with the Cap instance (network failure, timeout, 5xx error) blocks the request. Enabling Fail Open reverses this behaviour: infrastructure errors silently pass the request through.
Errors covered by Fail Open:
- Network error or timeout (
WP_Errorreturned by the WordPress HTTP API) - Non-2xx HTTP response (5xx, 4xx returned by the Cap server)
- Response that cannot be decoded as valid JSON
Never covered by Fail Open:
- Missing or empty token — unconditionally rejected. A missing token is not an infrastructure error; it means no verification was attempted.
- Explicitly invalid token (
success: falsein the JSON response) — always rejected.
Usage
Native integrations
The plugin automatically integrates with the following WordPress forms upon activation:
| Form | Widget insertion | Validation |
|---|---|---|
| Comments | comment_form_after_fields |
preprocess_comment |
| Login | login_form |
wp_authenticate_user |
| Registration | register_form |
registration_errors |
| WooCommerce checkout | woocommerce_after_checkout_billing_form |
woocommerce_checkout_process |
| Gravity Forms | gform_submit_button |
gform_validation |
WooCommerce and Gravity Forms integrations are only active if the corresponding plugins are installed and activated.
Shortcode [tpow_widget]
Insert the Cap widget into any page, post, or form builder:
[tpow_widget]
With CSP nonce:
[tpow_widget nonce="your-nonce"]
The shortcode automatically enqueues the widget JS, CSS, and WASM, as well as window.TPOW_CONFIG.
Programmatic mode — [tpow_programmatic]
For cases where you want to trigger Cap verification without displaying a visible widget (SPA, multi-step forms, custom integration):
[tpow_programmatic field="cap-token" id="tpow-token"]
| Attribute | Description | Default |
|---|---|---|
field |
Name of the <input type="hidden"> |
cap-token |
id |
HTML ID of the field | tpow-token |
The shortcode enqueues assets and inserts a hidden field. The endpoint and field name are exposed via window.TPOW_CONFIG, available as soon as the script loads.
Example:
[tpow_programmatic field="cap-token" id="my-cap-token"]
<script type="module">
document.getElementById('submit-btn').addEventListener('click', async (e) => {
e.preventDefault();
const cap = new Cap({ apiEndpoint: window.TPOW_CONFIG.apiEndpoint });
cap.addEventListener('progress', (event) => {
console.log(`Solving… ${event.detail.progress}%`);
});
const { token } = await cap.solve();
document.getElementById('my-cap-token').value = token;
e.target.closest('form').submit();
});
</script>
window.TPOW_CONFIG is injected automatically by wp_add_inline_script when assets are enqueued (via [tpow_widget], [tpow_programmatic], or any native integration):
window.TPOW_CONFIG = {
apiEndpoint: "https://cap.example.com/your-site-key/",
tokenField: "cap-token"
};
CSP
The widget relies on Web Workers and WebAssembly. A strict CSP must include:
Content-Security-Policy:
script-src 'nonce-{nonce}' 'strict-dynamic';
worker-src blob:;
wasm-unsafe-eval;
connect-src 'self';
worker-src blob: — required because the widget spawns workers via Blob URLs.
wasm-unsafe-eval — required for WebAssembly hash computation.
connect-src 'self' — sufficient for WASM, bundled locally within the plugin (no requests to any external CDN).
Uninstallation
Uninstalling via the WordPress interface automatically removes all registered database options:
tpow_endpointtpow_secrettpow_token_fieldtpow_timeouttpow_fail_open
License
MIT — see LICENSE