Developer Guide
Developer Guide#
Bouncer is extensible through hooks, filters, a public API, and the ability to register custom CAPTCHA providers.
Action hooks#
cfwc_loaded#
Fires after the plugin is fully initialized. Safe to extend.
add_action( 'cfwc_loaded', function() {
// Plugin is ready
});
cfwc_register_providers#
Register custom CAPTCHA providers. The manager’s register() method takes a single argument: the provider instance.
add_action( 'cfwc_register_providers', function( $manager ) {
$manager->register( new My_Custom_Provider() );
});
Timing: as of version 1.0.4 this action fires on init (priority 0), so you can hook it from a plugin or from your theme’s functions.php. In 1.0.3 and earlier it fired while plugins were still loading, before theme code was read, so it could only be hooked from a plugin. A small plugin remains the recommended home for provider code either way, so it survives theme switches.
See Custom providers below.
cfwc_before_render / cfwc_after_render#
Fires before and after the CAPTCHA widget renders on a form.
add_action( 'cfwc_before_render', function( $form_type, $args ) {
// Add custom markup before the CAPTCHA widget
}, 10, 2 );
add_action( 'cfwc_after_render', function( $form_type, $args ) {
// Add custom markup after the CAPTCHA widget
}, 10, 2 );
cfwc_before_verify#
Fires before CAPTCHA verification begins.
add_action( 'cfwc_before_verify', function( $form_type ) {
// Log or modify state before verification
});
cfwc_verified#
Fires on successful CAPTCHA verification.
add_action( 'cfwc_verified', function( $form_type, $result ) {
// Log successful verification, update stats, etc.
}, 10, 2 );
cfwc_failed#
Fires on failed CAPTCHA verification.
add_action( 'cfwc_failed', function( $form_type, $error ) {
// Custom logging, notifications, etc.
// $error is a WP_Error object
}, 10, 2 );
cfwc_after_verification#
Fires after any CAPTCHA verification completes (success or failure). Used by the global rate limiter. Available since 1.0.4.
add_action( 'cfwc_after_verification', function( $passed, $form_type ) {
// $passed is boolean, $form_type is the form identifier
}, 10, 2 );
Filter hooks#
cfwc_skip_verification#
Skip CAPTCHA for specific conditions.
add_filter( 'cfwc_skip_verification', function( $skip, $form_type, $context ) {
// Skip CAPTCHA on checkout for orders over $500 (trust high-value customers)
if ( $form_type === 'wc_checkout_block' && WC()->cart->get_total( 'edit' ) > 500 ) {
return true;
}
return $skip;
}, 10, 3 );
cfwc_form_enabled#
Override whether a form type is protected.
add_filter( 'cfwc_form_enabled', function( $enabled, $form_type ) {
// Disable CAPTCHA on login during business hours
if ( $form_type === 'wc_login' ) {
$hour = (int) current_time( 'G' );
if ( $hour >= 9 && $hour < 17 ) {
return false;
}
}
return $enabled;
}, 10, 2 );
cfwc_supported_forms#
Add custom form types to the supported forms list.
add_filter( 'cfwc_supported_forms', function( $forms ) {
$forms['my_custom_form'] = [
'label' => 'My Custom Form',
'category' => 'custom',
];
return $forms;
});
cfwc_error_message#
Customize error messages shown to users.
add_filter( 'cfwc_error_message', function( $message, $code, $provider ) {
if ( $code === 'verification_failed' ) {
return 'Security check failed. Please try again.';
}
return $message;
}, 10, 3 );
cfwc_widget_container_class#
Customize the CSS class on the CAPTCHA widget container.
add_filter( 'cfwc_widget_container_class', function( $class, $form_type ) {
return $class . ' my-custom-class';
}, 10, 2 );
cfwc_verification_request_body#
Modify the API request body sent to the CAPTCHA provider.
add_filter( 'cfwc_verification_request_body', function( $body, $provider_id ) {
// Add custom parameters
$body['custom_param'] = 'value';
return $body;
}, 10, 2 );
cfwc_verification_timeout#
Adjust the API request timeout (default 30 seconds).
add_filter( 'cfwc_verification_timeout', function( $timeout, $provider_id ) {
return 10; // 10 seconds
}, 10, 2 );
cfwc_should_load_assets#
Force CAPTCHA assets to load on specific pages (assets normally only load on pages with protected forms).
add_filter( 'cfwc_should_load_assets', function( $should_load ) {
if ( is_page( 'custom-checkout' ) ) {
return true;
}
return $should_load;
});
cfwc_get_sections#
Add or modify the sections shown on the settings page (WooCommerce > Settings > Bouncer).
add_filter( 'cfwc_get_sections', function( $sections ) {
$sections['my_section'] = 'My Section';
return $sections;
});
cfwc_get_settings_{section}#
Modify the settings fields of a specific section. The section slug is appended to the filter name: forms, security, fraud, notifications, advanced, license, or an empty string for General (cfwc_get_settings_). Fields use the WooCommerce Settings API format.
add_filter( 'cfwc_get_settings_advanced', function( $settings ) {
$settings[] = [
'title' => 'My custom option',
'id' => 'my_custom_option',
'type' => 'checkbox',
'default' => 'no',
];
return $settings;
});
cfwc_recaptcha_v3_threshold#
Override the reCAPTCHA v3 score threshold programmatically.
add_filter( 'cfwc_recaptcha_v3_threshold', function( $threshold ) {
return 0.7; // Stricter than default
});
cfwc_honeypot_min_time#
Override the honeypot minimum submission time.
add_filter( 'cfwc_honeypot_min_time', function( $min_time ) {
return 5; // 5 seconds instead of default 3
});
cfwc_fraud_rules#
Register custom fraud scoring rules. Each rule must implement the CFWC\Fraud\Rule_Interface.
add_filter( 'cfwc_fraud_rules', function( $rules ) {
$rules[] = new My_Custom_Fraud_Rule();
return $rules;
});
cfwc_fraud_score_result#
Modify the fraud score result before it’s saved to the order.
add_filter( 'cfwc_fraud_score_result', function( $result, $order ) {
// $result contains 'score', 'level', 'details'
return $result;
}, 10, 2 );
cfwc_geoip_country_code#
Override the GeoIP-resolved country code.
add_filter( 'cfwc_geoip_country_code', function( $country_code, $ip ) {
return $country_code;
}, 10, 2 );
cfwc_should_block_request#
Block form submissions before CAPTCHA verification runs. The global rate limiter hooks this to reject bursts of requests site-wide. Available since 1.0.4.
add_filter( 'cfwc_should_block_request', function( $should_block ) {
// Return true to reject the submission
return $should_block;
});
Public API#
Access the plugin instance and its components:
$plugin = CFWC\Plugin::instance();
Render CAPTCHA on a custom form#
// In your form template
$plugin->render( 'my_custom_form', [
'container_class' => 'my-captcha-wrapper',
] );
Verify CAPTCHA on form submission#
// In your form handler
$result = $plugin->verify( 'my_custom_form' );
if ( is_wp_error( $result ) ) {
// Verification failed
$error_message = $result->get_error_message();
} else {
// Verification passed, process form
}
Render CAPTCHA via shortcode#
Use [cfwc_captcha] in any page or template. For programmatic rendering:
echo do_shortcode( '[cfwc_captcha theme="dark" size="compact"]' );
Verify the shortcode CAPTCHA via AJAX:
// POST to admin-ajax.php with action=cfwc_verify_shortcode
// Include cfwc_shortcode_nonce from the rendered form
Access settings#
$settings = $plugin->settings();
$provider = $settings->get( 'provider' );
$site_key = $settings->get( 'site_key' );
$is_debug = $settings->get( 'enable_debug_logging' );
Access provider manager#
$providers = $plugin->providers();
// Get active provider
$active = $plugin->provider();
// Get all registered providers
$all = $providers->get_all();
// Check if a provider is registered
$exists = $providers->exists( 'turnstile' );
Custom providers#
The simplest path is extending CFWC\Providers\Abstract_Provider, which is what the built-in providers do. It covers most of Provider_Interface for you; the only abstract method is render_widget(). Set the $id, $name, and $token_field properties and override get_description(), verify(), and test_connection().
Put the code in a small plugin so it survives theme switches. Keep the class in its own file: it declares a namespace, and a namespace declaration must be the first statement in its file.
<?php
/**
* Plugin Name: My Custom Provider for Bouncer
*/
defined( 'ABSPATH' ) || exit;
add_action( 'cfwc_register_providers', function( $manager ) {
require_once __DIR__ . '/class-my-custom-provider.php';
$manager->register( new \CFWC\Providers\My_Custom_Provider() );
});
And in class-my-custom-provider.php:
<?php
namespace CFWC\Providers;
defined( 'ABSPATH' ) || exit;
class My_Custom_Provider extends Abstract_Provider {
protected $id = 'my_provider';
protected $name = 'My Custom Provider';
protected $token_field = 'my_provider_token';
protected $requires_keys = false;
public function get_description() {
return 'Description of my provider, shown on the settings page.';
}
protected function render_widget( $form_type, $args ) {
// Output the CAPTCHA widget HTML.
echo '<div id="my-provider-' . esc_attr( $form_type ) . '"></div>';
}
public function verify( $token = '' ) {
// Verify the response. Return true on success,
// or a WP_Error (via $this->create_error()) on failure.
return true;
}
public function test_connection( $site_key, $secret_key ) {
// Called from the settings page key test. Return true
// or a WP_Error.
return true;
}
}
If you build on Provider_Interface directly instead of the abstract class, you must provide all of its methods: get_id(), get_name(), get_description(), requires_api_keys(), get_api_key_url(), render( $form_type, $args ), verify( $token ), get_token_field_name(), and test_connection( $site_key, $secret_key ).
The custom provider will appear in the provider dropdown on the settings page.
Logging#
When debug logging is enabled, the plugin logs to WooCommerce’s logging system:
- Verification attempts (success and failure)
- Rate limit events (lockouts, releases)
- Provider errors (API timeouts, invalid responses)
- IP blocklist matches
View logs at WooCommerce > Status > Logs and filter by source captcha-for-woocommerce.
// Log programmatically (only writes when debug logging is enabled)
\CFWC\Logger::log( 'Custom log message', [ 'context' => 'value' ], 'info' );
Form type identifiers#
When working with hooks, use these form type string identifiers:
| Form | ID |
|---|---|
| WordPress Login | wp_login |
| WordPress Registration | wp_register |
| WordPress Lost Password | wp_lost_password |
| WordPress Comments | wp_comment |
| WooCommerce Login | wc_login |
| WooCommerce Registration | wc_register |
| WooCommerce Lost Password | wc_lost_password |
| Classic Checkout | wc_checkout_classic |
| Block Checkout | wc_checkout_block |
| Pay for Order | wc_pay_order |
| Product Vendors | wcpv_registration |
| Subscriptions | wc_subscriptions |
| Memberships | wc_memberships |
| WordPress Reset Password | wp_reset_password |
| WooCommerce Reset Password | wc_reset_password |
| Product Reviews | wc_review |
| Order Tracking | wc_order_tracking |
| WooCommerce Bookings | wc_bookings |
| Elementor Pro Forms | elementor_form |
| Shortcode | shortcode |