# defender-security/6.2.3/src/model/setting/class-captcha.php

Defender Security – Malware Scanner, Login Security &amp; Firewall, version 6.2.3. 420 lines.

- Page: https://pluginprobe.com/plugins/defender-security/6.2.3/code/src/model/setting/class-captcha.php
- Raw: https://pluginprobe.com/plugins/defender-security/6.2.3/raw/src/model/setting/class-captcha.php
- Modified: 2026-07-13T09:36:42+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/defender-security/6.2.3/code/src/model/setting/class-captcha.php#L10-L20`.

```php
<?php
/**
 * Handle Captcha settings.
 *
 * @package WP_Defender\Model\Setting
 */

namespace WP_Defender\Model\Setting;

use Calotes\Model\Setting;

/**
 * Model for Captcha settings.
 */
class Captcha extends Setting {
	/**
	 * Turnstile provider key.
	 */
	const TURNSTILE = 'turnstile';

	/**
	 * Option name.
	 * We'll keep the current table for all Captcha for backward compatibility. There's no need to edit the table name to store settings in the database.
	 *
	 * @var string
	 */
	protected $table = 'wd_recaptcha_settings';

	/**
	 * Feature status.
	 *
	 * @var bool
	 * @defender_property
	 */
	public $enabled = false;

	/**
	 * Captcha Provider.
	 *
	 * @var string
	 * @defender_property
	 */
	public $provider = 'recaptcha';

	/**
	 * Active Captcha type.
	 *
	 * @var string
	 * @defender_property
	 * @rule required
	 * @rule in[v2_checkbox,v2_invisible,v3_recaptcha,turnstile]
	 */
	public $active_type = 'v2_checkbox';

	/**
	 * Data for v2 checkbox reCaptcha.
	 *
	 * @var array
	 * @defender_property
	 */
	public $data_v2_checkbox;

	/**
	 * Data for v2 invisible reCaptcha.
	 *
	 * @var array
	 * @defender_property
	 */
	public $data_v2_invisible;

	/**
	 * Data for v3 reCaptcha.
	 *
	 * @var array
	 * @defender_property
	 */
	public $data_v3_recaptcha;

	/**
	 * Data for Cloudflare Turnstile.
	 *
	 * @var array
	 * @defender_property
	 */
	public $data_turnstile;

	/**
	 * Language for Captcha.
	 *
	 * @var string
	 * @defender_property
	 * @rule required
	 */
	public $language = '';

	/**
	 * Message for reCaptcha.
	 *
	 * @var string
	 * @defender_property
	 * @sanitize sanitize_textarea_field
	 */
	public $message = '';

	/**
	 * Locations for Captcha.
	 *
	 * @var array
	 * @defender_property
	 * @rule required
	 */
	public $locations = array();

	/**
	 * Flag to detect WooCommerce.
	 *
	 * @var bool
	 * @defender_property
	 */
	public $detect_woo = false;

	/**
	 * Checked locations for WooCommerce.
	 *
	 * @var array
	 * @defender_property
	 * @rule required
	 */
	public $woo_checked_locations = array();

	/**
	 * Flag to detect BuddyPress.
	 *
	 * @var bool
	 * @defender_property
	 */
	public $detect_buddypress = false;

	/**
	 * Checked locations for BuddyPress.
	 *
	 * @var array
	 * @defender_property
	 * @rule required
	 */
	public $buddypress_checked_locations = array();

	/**
	 * Flag to disable Captcha for known users.
	 *
	 * @var bool
	 * @defender_property
	 */
	public $disable_for_known_users = true;

	/**
	 * Rules for validating the Captcha settings.
	 *
	 * @var array
	 */
	protected $rules = array(
		array( array( 'enabled', 'detect_woo', 'detect_buddypress' ), 'boolean' ),
		array( array( 'active_type' ), 'in', array( 'v2_checkbox', 'v2_invisible', 'v3_recaptcha', self::TURNSTILE ) ),
	);

	/**
	 * Retrieves the default values for the Captcha settings.
	 *
	 * @return array An associative array containing the default values.
	 */
	public function get_default_values(): array {
		return array(
			'message'           => esc_html__( 'reCAPTCHA verification failed. Please try again.', 'defender-security' ),
			'turnstile_message' => esc_html__( 'Turnstile verification failed. Please try again.', 'defender-security' ),
		);
	}

	/**
	 *  Load default values.
	 *
	 * @return void
	 */
	protected function before_load(): void {
		$default_values          = $this->get_default_values();
		$this->provider          = 'recaptcha';
		$this->message           = $default_values['message'];
		$this->language          = 'automatic';
		$this->data_v2_checkbox  = array(
			'key'      => '',
			'secret'   => '',
			'verified' => false,
			'size'     => 'normal',
			'style'    => 'light',
		);
		$this->data_v2_invisible = array(
			'key'      => '',
			'secret'   => '',
			'verified' => false,
		);
		$this->data_v3_recaptcha = array(
			'key'       => '',
			'secret'    => '',
			'verified'  => false,
			'threshold' => '0.5',
		);
		$this->data_turnstile    = array(
			'key'      => '',
			'secret'   => '',
			'verified' => false,
			'size'     => 'normal',
			'style'    => 'auto',
			'message'  => $default_values['turnstile_message'],
			'language' => 'auto',
		);
	}

	/**
	 * Backfill new keys (e.g. 'verified') into data arrays loaded from settings saved by an older version.
	 *
	 * @return void
	 */
	protected function after_load(): void {
		$this->data_v2_checkbox  = wp_parse_args( $this->data_v2_checkbox, array( 'verified' => false ) );
		$this->data_v2_invisible = wp_parse_args( $this->data_v2_invisible, array( 'verified' => false ) );
		$this->data_v3_recaptcha = wp_parse_args( $this->data_v3_recaptcha, array( 'verified' => false ) );
		$this->data_turnstile    = wp_parse_args( $this->data_turnstile, array( 'verified' => false ) );
	}

	/**
	 * Checks if the given Captcha type is valid and has all the necessary data.
	 *
	 * @param  string $active_type  The Captcha type to check.
	 *
	 * @return bool Returns true if the Captcha type is valid and has all the necessary data, false otherwise.
	 */
	private function check_captcha_type( string $active_type ): bool {
		if (
			'v2_checkbox' === $active_type
			&& '' !== $this->data_v2_checkbox['key']
			&& '' !== $this->data_v2_checkbox['secret']
		) {
			return true;
		} elseif (
			'v2_invisible' === $active_type
			&& '' !== $this->data_v2_invisible['key']
			&& '' !== $this->data_v2_invisible['secret']
		) {
			return true;
		} elseif (
			'v3_recaptcha' === $active_type
			&& '' !== $this->data_v3_recaptcha['key'] && '' !== $this->data_v3_recaptcha['secret']
		) {
			return true;
		} elseif (
			self::TURNSTILE === $active_type &&
			'' !== $this->data_turnstile['key'] &&
			'' !== $this->data_turnstile['secret']
		) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Checks if the CAPTCHA is active.
	 *
	 * @return bool Returns true if the CAPTCHA is active, false otherwise.
	 */
	public function is_active(): bool {
		$hook_name = self::TURNSTILE === $this->active_type ? 'wd_turnstile_enable' : 'wd_recaptcha_enable';
		$enable    = apply_filters(
			$hook_name,
			$this->enabled
			&& '' !== $this->active_type
			&& '' !== $this->language
			// For each Captcha type.
			&& $this->check_captcha_type( $this->active_type )
		);

		return is_bool( $enable ) ? $enable : (bool) $enable;
	}

	/**
	 * Is activated any default location?
	 *
	 * @return bool
	 */
	public function enable_default_location(): bool {
		return array() !== $this->locations;
	}

	/**
	 * Level#2 check by any activated location. Only if the plugin is enabled.
	 *
	 * @return bool
	 */
	public function enable_woo_location(): bool {
		return $this->detect_woo && array() !== $this->woo_checked_locations;
	}

	/**
	 * Level#2 check by deactivated locations. Only if the plugin is enabled.
	 *
	 * @return bool
	 */
	public function is_unchecked_woo_locations(): bool {
		return $this->detect_woo && array() === $this->woo_checked_locations;
	}

	/**
	 * Level#1 check. If the plugin is disabled, there is no point further.
	 *
	 * @param  bool $is_woo_activated  Whether WooCommerce is activated or not.
	 *
	 * @return bool
	 */
	public function check_woo_locations( $is_woo_activated ): bool {
		if ( ! $is_woo_activated ) {
			return false;
		}

		return $this->enable_woo_location();
	}

	/**
	 * Level#2 check by any activated location. Only if the plugin is enabled.
	 *
	 * @return bool
	 */
	public function enable_buddypress_location(): bool {
		return $this->detect_buddypress && array() !== $this->buddypress_checked_locations;
	}

	/**
	 * Level#2 check by deactivated locations. Only if the plugin is enabled.
	 *
	 * @return bool
	 */
	public function is_unchecked_buddypress_locations(): bool {
		return $this->detect_buddypress && array() === $this->buddypress_checked_locations;
	}

	/**
	 * Level#1 Checks if the BuddyPress locations are valid and have all the necessary data.
	 *
	 * @param  bool $is_buddypress_activated  Whether BuddyPress is activated or not.
	 *
	 * @return bool Returns true if the BuddyPress locations are valid and have all the necessary data, false otherwise.
	 */
	public function check_buddypress_locations( $is_buddypress_activated ): bool {
		if ( ! $is_buddypress_activated ) {
			return false;
		}

		return $this->enable_buddypress_location();
	}

	/**
	 * Define settings labels.
	 *
	 * @return array
	 */
	public function labels(): array {
		return array(
			'enabled'                 => self::get_module_name(),
			'active_type'             => esc_html__( 'Configure CAPTCHA', 'defender-security' ),
			'v2_checkbox'             => esc_html__( 'V2 Checkbox', 'defender-security' ),
			'v2_invisible'            => esc_html__( 'V2 Invisible', 'defender-security' ),
			'v3_recaptcha'            => esc_html__( 'reCAPTCHA V3', 'defender-security' ),
			'language'                => esc_html__( 'Language', 'defender-security' ),
			'message'                 => esc_html__( 'Error Message', 'defender-security' ),
			'locations'               => esc_html__( 'CAPTCHA Locations', 'defender-security' ),
			'detect_woo'              => esc_html__( 'WooCommerce', 'defender-security' ),
			'detect_buddypress'       => esc_html__( 'BuddyPress', 'defender-security' ),
			'disable_for_known_users' => esc_html__( 'Disable for logged in users', 'defender-security' ),
		);
	}

	/**
	 * Disable for logged in users or enable.
	 *
	 * @return bool
	 */
	public function display_for_known_users(): bool {
		return ! ( $this->disable_for_known_users && is_user_logged_in() );
	}

	/**
	 * Get module name.
	 *
	 * @return string
	 */
	public static function get_module_name(): string {
		return esc_html__( 'CAPTCHA', 'defender-security' );
	}

	/**
	 * Get active captcha data based on provider and active type.
	 *
	 * @param string|null $provider The provider name.
	 * @param string|null $active_type The active type.
	 *
	 * @return array The captcha data for the specified provider.
	 */
	public function get_active_captcha_data( ?string $provider = null, ?string $active_type = null ): array {
		$provider    = $provider ?? $this->provider;
		$active_type = $active_type ?? $this->active_type;
		if ( self::TURNSTILE === $provider ) {
			return $this->data_turnstile;
		}
		return match ( $active_type ) {
			'v2_checkbox' => $this->data_v2_checkbox,
			'v2_invisible' => $this->data_v2_invisible,
			'v3_recaptcha' => $this->data_v3_recaptcha,
			default => array(),
		};
	}
}

```
