CardFence

Developer reference

Code lives under the CheckoutShield\ namespace in includes/. The prefix for options, tables, hooks and the cookie is cksh_.

Filters

cksh_client_ip

Change the client IP CardFence uses (after the configured IP source has been applied).

add_filter( 'cksh_client_ip', function ( $ip, $remote_addr ) {
	// e.g. a custom header set by your own trusted edge.
	return $_SERVER['HTTP_X_MY_EDGE_IP'] ?? $ip;
}, 10, 2 );

Must return a valid IP. Invalid values fall back to 0.0.0.0.

cksh_rule_verdict

Add your own blocking rules. Return a reason slug to block, or the incoming value to continue. Runs after the allow and block lists and the store-manager check. It also respects Monitor mode.

add_filter( 'cksh_rule_verdict', function ( $reason, $context, $ip, $email ) {
	if ( '' !== $reason ) {
		return $reason; // another rule already decided.
	}
	if ( str_ends_with( $email, '@competitor.example' ) ) {
		return 'competitor';
	}
	return '';
}, 10, 4 );

$context is one of store_checkout, store_order_pay, classic_checkout, order_pay, add_payment_method, or wc_ajax:{action}. The reason appears in the activity log.

cksh_denied_message

Change the message a refused buyer sees.

add_filter( 'cksh_denied_message', function ( $message, $kind, $reason ) {
	// $kind: blocked | rate_limited | session | challenge
	return 'blocked' === $kind ? 'Please call us on 555-0100 to complete your order.' : $message;
}, 10, 3 );

cksh_count_async_failure

Decide whether a payment failure reported outside a checkout request (a gateway webhook or cron) counts towards blocks and attack mode. By default, only orders created via checkout or store-api in the last 24 hours count.

add_filter( 'cksh_count_async_failure', function ( $counts, $order ) {
	return $counts || 'my-headless-app' === $order->get_created_via();
}, 10, 2 );

cksh_is_payment_page

Mark extra pages (for example a custom one-page checkout) as payment pages, so they get the browser-token cookie.

add_filter( 'cksh_is_payment_page', function ( $is ) {
	return $is || is_page( 'express-checkout' );
} );

cksh_disposable_domains (Pro)

Change the disposable-email domain list.

add_filter( 'cksh_disposable_domains', function ( $domains ) {
	$domains[] = 'throwaway.example';
	return array_diff( $domains, array( 'trashmail.com' ) );
} );

cksh_ip_country (Pro)

Supply or override the two-letter country used by the country rule, for example from your own geolocation.

add_filter( 'cksh_ip_country', function ( $country, $ip ) {
	return $country ?: my_geo_lookup( $ip ); // '' = unknown (allowed).
}, 10, 2 );

Actions

Action Arguments Fires when
cksh_attack_started $source (auto or manual), $minutes Attack mode switches on (not when it is extended).
cksh_auto_blocked $kind (ip or email), $value, $reason (rate_limit or failures), $minutes An IP or email is blocked automatically.
cksh_fs_loaded none The Freemius SDK (or the stub) is ready.
add_action( 'cksh_attack_started', function ( $source, $minutes ) {
	my_pager_alert( "Card-testing attack: attack mode on for {$minutes} min ({$source})" );
}, 10, 2 );

Block checkout extension data

The checkout block sends the browser token and Turnstile response as Store API extension data under the cardfence-for-woocommerce namespace:

{ "extensions": { "cardfence-for-woocommerce": { "token": "1760000000.ab12…", "turnstile": "0.xyz…" } } }

A headless storefront that wants to pass the browser check must load a payment page to get the cksh_sid cookie and a token. Simpler options: keep Browser check on Log only or During attacks, or allow-list your storefront's servers.

Crash protection

Every hook CardFence registers goes through CheckoutShield\Core\Safe:

Hook type When it throws
Action Does nothing.
Filter Returns its input unchanged.
Checkout checks Allow the checkout (fail open).

Caught errors are logged (CardFence caught an error … and let the request continue) and the latest one is stored in the cksh_last_error option for a wp-admin notice. Your own callbacks on cksh_* filters run inside that guard, so an exception in them can't take the checkout down either.

Because the hooks are registered through closures, remove_action() / remove_filter() can't target them by callback. To switch a behavior off, use the plugin's settings or filters instead.

Constants

Constant Where Effect
CARDFENCE_FS_PLUGIN_ID, CARDFENCE_FS_PUBLIC_KEY wp-config.php Override the Freemius product credentials (for staging or development).
CARDFENCE_FS_OFF wp-config.php true keeps the Freemius SDK off and uses the built-in stub. For development and the test suites only.
CKSH_DEV_UNLOCK wp-config.php Unlocks Pro for local development, only when WP_DEBUG is also true and the Pro code is present. It has no effect in the free build.

Data the plugin stores

What Name
Settings option cksh_settings
Attack-mode state option cksh_attack (autoloaded)
Versions options cksh_version, cksh_db_version
Last weekly report (Pro) option cksh_last_report
Event log table {prefix}cksh_events: id, created_at (UTC), type, context, ip, email, order_id, reason, detail, hits
Temporary blocks table {prefix}cksh_blocks: id, kind, value, reason, source, created_at, expires_at
Attack-order flag order meta _cksh_suspect (HPOS and legacy)
Browser-token session cookie cksh_sid (session, HttpOnly, SameSite=Lax)
Scheduled tasks cksh_daily (clean-up), cksh_weekly_report and cksh_cleanup (Pro)

IPv6 addresses are stored per /64 network (2001:db8:1:2::/64).

Code map

Folder Contents
includes/Engine/ Guard (the decision engine), Failures, AttackMode, Suspects
includes/Integration/ StoreApi (block checkout), Classic (classic forms and wc-ajax), CheckoutBlocks (front-end script data)
includes/Detect/ Ip, Token, Turnstile
includes/Store/ Events, Blocks (custom tables)
includes/Admin/ Admin (screens), Actions (form handlers), Labels
includes/Freemius/ Gate (plan checks), Stub
includes/Pro/ Premium-only modules. Freemius strips this folder from the free build.
views/ Admin screen templates