504 lines
17 KiB
PHP
504 lines
17 KiB
PHP
<?php
|
|
/**
|
|
* @package ogre-captcha
|
|
* @author cleverogre
|
|
* @copyright 2026 CleverOgre
|
|
* @license GLP-3.0-or-later
|
|
* @version 1.2.5
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
namespace Ogre\Captcha;
|
|
|
|
use Ogre\Singleton;
|
|
use Ogre\Captcha as Plugin;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
final class Settings {
|
|
use Singleton;
|
|
|
|
const CAPABILITY = 'manage_options';
|
|
const DEFAULT_INSTANCE_URL = 'https://captcha.cleverogre.com';
|
|
|
|
public const LOCATION_LOGIN_PAGE = 'login_page';
|
|
public const LOCATION_REGISTRATION_PAGE = 'registration_page';
|
|
public const LOCATION_LOST_PASSWORD_FORM = 'lost_password_page';
|
|
public const LOCATION_LOGIN_FORM = 'login_form';
|
|
public const LOCATION_COMMENT_FORM = 'comment_form';
|
|
public const LOCATION_POST_PASSWORD_FORM = 'post_password_form';
|
|
public const WP_LOCATIONS = [
|
|
self::LOCATION_LOGIN_PAGE,
|
|
self::LOCATION_REGISTRATION_PAGE,
|
|
self::LOCATION_LOST_PASSWORD_FORM,
|
|
self::LOCATION_LOGIN_FORM,
|
|
self::LOCATION_COMMENT_FORM,
|
|
self::LOCATION_POST_PASSWORD_FORM,
|
|
];
|
|
|
|
public const LOCATION_WC_LOGIN = 'wc_login';
|
|
public const LOCATION_WC_LOST_PASSWORD = 'wc_lost_password';
|
|
public const LOCATION_WC_REGISTER = 'wc_register';
|
|
public const LOCATION_WC_CHECKOUT = 'wc_checkout';
|
|
public const WC_LOCATIONS = [
|
|
self::LOCATION_WC_LOGIN,
|
|
self::LOCATION_WC_LOST_PASSWORD,
|
|
self::LOCATION_WC_REGISTER,
|
|
self::LOCATION_WC_CHECKOUT,
|
|
];
|
|
|
|
public const ALL_LOCATIONS = [
|
|
self::LOCATION_LOGIN_PAGE,
|
|
self::LOCATION_REGISTRATION_PAGE,
|
|
self::LOCATION_LOST_PASSWORD_FORM,
|
|
self::LOCATION_LOGIN_FORM,
|
|
self::LOCATION_COMMENT_FORM,
|
|
self::LOCATION_POST_PASSWORD_FORM,
|
|
self::LOCATION_WC_LOGIN,
|
|
self::LOCATION_WC_LOST_PASSWORD,
|
|
self::LOCATION_WC_REGISTER,
|
|
self::LOCATION_WC_CHECKOUT,
|
|
];
|
|
|
|
public const WIDGET_TYPE_STANDARD = 'standard';
|
|
public const WIDGET_TYPE_FLOATING = 'floating';
|
|
public const WIDGET_TYPES = [
|
|
self::WIDGET_TYPE_STANDARD,
|
|
self::WIDGET_TYPE_FLOATING,
|
|
];
|
|
|
|
protected function __construct() {
|
|
add_action('admin_menu', [$this, 'menu']);
|
|
add_action('admin_init', [$this, 'init']);
|
|
}
|
|
|
|
private static function get(string $key = '') {
|
|
$data = (array) get_option(Plugin::get_id(), []);
|
|
if (!empty($key)) return array_key_exists($key, $data) ? $data[$key] : null;
|
|
return $data;
|
|
}
|
|
|
|
private static function has(string $key):bool {
|
|
return array_key_exists($key, self::get());
|
|
}
|
|
|
|
private static function set(string $key, $value = null):void {
|
|
$data = self::get();
|
|
if (is_null($value) && isset($data[$key])) {
|
|
unset($data[$key]);
|
|
} else {
|
|
$data[$key] = $value;
|
|
}
|
|
update_option(Plugin::get_id(), $data);
|
|
}
|
|
|
|
private static function is_checked(string $name, string $value, string|null $default = null):bool {
|
|
if (!is_null($default) && !self::has($name)) return $value == $default;
|
|
return in_array($value, (array) self::get($name));
|
|
}
|
|
|
|
public static function get_instance_url(string $path = ''):string {
|
|
$url = (string) self::get('instance_url');
|
|
if (empty($url)) $url = self::DEFAULT_INSTANCE_URL;
|
|
if (!wp_http_validate_url($url)) return '';
|
|
if (!empty($path)) {
|
|
$url = sprintf(
|
|
'%s/%s',
|
|
untrailingslashit(Settings::get_instance_url()),
|
|
$path
|
|
);
|
|
}
|
|
return $url;
|
|
}
|
|
|
|
public static function set_instance_url(string $value):bool {
|
|
if (!wp_http_validate_url($value)) return false;
|
|
self::set('instance_url', $value);
|
|
return true;
|
|
}
|
|
|
|
public static function get_site_key():string {
|
|
return (string) self::get('site_key');
|
|
}
|
|
|
|
public static function set_site_key(string $value):bool {
|
|
self::set('site_key', $value);
|
|
return true;
|
|
}
|
|
|
|
public static function get_secret_key():string {
|
|
return (string) self::get('secret_key');
|
|
}
|
|
|
|
public static function set_secret_key(string $value):bool {
|
|
self::set('secret_key', $value);
|
|
return true;
|
|
}
|
|
|
|
public static function is_connected():bool {
|
|
return !empty(self::get_site_key()) && !empty(self::get_secret_key());
|
|
}
|
|
|
|
public static function get_form_locations():array {
|
|
$form_locations = (array) self::get('form_locations');
|
|
if (Plugin::is_woocommerce_active()) {
|
|
$form_locations = array_merge(
|
|
$form_locations,
|
|
(array) self::get('wc_form_locations')
|
|
);
|
|
}
|
|
return $form_locations;
|
|
}
|
|
|
|
public static function is_form_location_enabled(string $name):bool {
|
|
return in_array($name, self::get_form_locations());
|
|
}
|
|
|
|
public static function set_form_location(string $name, bool $enabled):bool {
|
|
if (in_array($name, self::WP_LOCATIONS)) {
|
|
$key = 'form_locations';
|
|
} else if (in_array($name, self::WC_LOCATIONS)) {
|
|
$key = 'wc_form_locations';
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
$value = (array) self::get($key);
|
|
if (!!$enabled && !in_array($name, $value)) {
|
|
$value[] = $name;
|
|
} else if (!$enabled && in_array($name, $value)) {
|
|
unset($value[array_search($name, $value)]);
|
|
}
|
|
self::set($key, $value);
|
|
|
|
return true;
|
|
}
|
|
|
|
public static function is_login_page_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_LOGIN_PAGE);
|
|
}
|
|
|
|
public static function is_registration_page_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_REGISTRATION_PAGE);
|
|
}
|
|
|
|
public static function is_lost_password_form_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_LOST_PASSWORD_FORM);
|
|
}
|
|
|
|
public static function is_login_form_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_LOGIN_FORM);
|
|
}
|
|
|
|
public static function is_comment_form_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_COMMENT_FORM);
|
|
}
|
|
|
|
public static function is_post_password_form_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_POST_PASSWORD_FORM);
|
|
}
|
|
|
|
public static function is_wc_login_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_WC_LOGIN);
|
|
}
|
|
|
|
public static function is_wc_lost_password_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_WC_LOST_PASSWORD);
|
|
}
|
|
|
|
public static function is_wc_register_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_WC_REGISTER);
|
|
}
|
|
|
|
public static function is_wc_checkout_enabled():bool {
|
|
return self::is_form_location_enabled(self::LOCATION_WC_CHECKOUT);
|
|
}
|
|
|
|
public static function get_widget_type():string {
|
|
$value = self::get('widget_type');
|
|
if (is_array($value) && !empty($value)) $value = array_values($value)[0];
|
|
if (!is_string($value)) $value = '';
|
|
return in_array($value, self::WIDGET_TYPES) ? $value : self::WIDGET_TYPE_STANDARD;
|
|
}
|
|
|
|
public static function is_widget_floating():bool {
|
|
return self::get_widget_type() === self::WIDGET_TYPE_FLOATING;
|
|
}
|
|
|
|
public static function set_widget_type(string $value):bool {
|
|
if (!in_array($value, self::WIDGET_TYPES)) return false;
|
|
self::set('widget_type', $value);
|
|
return true;
|
|
}
|
|
|
|
public function menu() {
|
|
if (!current_user_can(self::CAPABILITY)) return;
|
|
add_options_page(
|
|
sprintf(
|
|
Plugin::__('%s Settings'),
|
|
Plugin::get_title()
|
|
),
|
|
Plugin::__('CAPTCHA'),
|
|
self::CAPABILITY,
|
|
Plugin::get_id(),
|
|
[$this, 'page']
|
|
);
|
|
}
|
|
|
|
public function init() {
|
|
register_setting(Plugin::get_id(), Plugin::get_id());
|
|
|
|
add_settings_section(
|
|
'default',
|
|
Plugin::__('Cap API Credentials'),
|
|
[$this, 'section'],
|
|
Plugin::get_id(),
|
|
[
|
|
'description' => Plugin::__('The configuration settings for your Cap CAPTCHA API connection.'),
|
|
]
|
|
);
|
|
|
|
add_settings_field(
|
|
Plugin::get_id() . '_instance_url',
|
|
Plugin::__('Instance URL'),
|
|
[$this, 'field'],
|
|
Plugin::get_id(),
|
|
args: [
|
|
'name' => 'instance_url',
|
|
'placeholder' => Plugin::__('https://captcha.cleverogre.com/'),
|
|
'description' => Plugin::__('Provide the base URL to an instance of Cap. Defaults to CleverOgre\'s CAPTCHA server.'),
|
|
]
|
|
);
|
|
|
|
add_settings_field(
|
|
Plugin::get_id() . '_site_key',
|
|
Plugin::__('Site key'),
|
|
[$this, 'field'],
|
|
Plugin::get_id(),
|
|
args: [
|
|
'name' => 'site_key',
|
|
'description' => Plugin::__('Provide your Cap site key.'),
|
|
'attributes' => [
|
|
'autocomplete' => 'off',
|
|
],
|
|
]
|
|
);
|
|
|
|
add_settings_field(
|
|
Plugin::get_id() . '_secret_key',
|
|
Plugin::__('Secret key'),
|
|
[$this, 'field'],
|
|
Plugin::get_id(),
|
|
args: [
|
|
'name' => 'secret_key',
|
|
'description' => Plugin::__('Provide your Cap secret key.'),
|
|
'type' => 'password',
|
|
'attributes' => [
|
|
'autocomplete' => 'off',
|
|
],
|
|
]
|
|
);
|
|
|
|
add_settings_section(
|
|
'forms',
|
|
Plugin::__('Forms'),
|
|
[$this, 'section'],
|
|
Plugin::get_id(),
|
|
[
|
|
'description' => Plugin::__('Define which forms you would like to secure with Cap.'),
|
|
]
|
|
);
|
|
|
|
add_settings_field(
|
|
Plugin::get_id() . '_form_locations',
|
|
Plugin::__('WordPress form locations'),
|
|
[$this, 'checkbox_field'],
|
|
Plugin::get_id(),
|
|
'forms',
|
|
[
|
|
'name' => 'form_locations',
|
|
'options' => [
|
|
self::LOCATION_LOGIN_PAGE => Plugin::__('Login page'),
|
|
self::LOCATION_REGISTRATION_PAGE => Plugin::__('Registration page'),
|
|
self::LOCATION_LOST_PASSWORD_FORM => Plugin::__('Lost password page'),
|
|
self::LOCATION_LOGIN_FORM => Plugin::__('Custom login form'),
|
|
self::LOCATION_COMMENT_FORM => Plugin::__('Comment form'),
|
|
self::LOCATION_POST_PASSWORD_FORM => Plugin::__('Password-protected posts and pages'),
|
|
],
|
|
'select_all' => true,
|
|
'description' => Plugin::__('Custom login form requires login page to also be enabled.'),
|
|
]
|
|
);
|
|
|
|
if (Plugin::is_woocommerce_active()) {
|
|
add_settings_field(
|
|
Plugin::get_id() . '_wc_form_locations',
|
|
Plugin::__('WooCommerce form locations'),
|
|
[$this, 'checkbox_field'],
|
|
Plugin::get_id(),
|
|
'forms',
|
|
[
|
|
'name' => 'wc_form_locations',
|
|
'options' => [
|
|
self::LOCATION_WC_LOGIN => Plugin::__('Login form'),
|
|
self::LOCATION_WC_LOST_PASSWORD => Plugin::__('Lost password form'),
|
|
self::LOCATION_WC_REGISTER => Plugin::__('Register form'),
|
|
self::LOCATION_WC_CHECKOUT => Plugin::__('Checkout form'),
|
|
],
|
|
'select_all' => true,
|
|
]
|
|
);
|
|
}
|
|
|
|
add_settings_section(
|
|
'widget',
|
|
Plugin::__('Widget'),
|
|
[$this, 'section'],
|
|
Plugin::get_id(),
|
|
[
|
|
'description' => Plugin::__('Change how the Cap widget is displayed on the frontend.'),
|
|
]
|
|
);
|
|
|
|
add_settings_field(
|
|
Plugin::get_id() . '_widget_type',
|
|
Plugin::__('Widget type'),
|
|
[$this, 'checkbox_field'],
|
|
Plugin::get_id(),
|
|
'widget',
|
|
[
|
|
'type' => 'radio',
|
|
'name' => 'widget_type',
|
|
'options' => [
|
|
self::WIDGET_TYPE_STANDARD => Plugin::__('Standard (default)'),
|
|
self::WIDGET_TYPE_FLOATING => Plugin::__('Floating'),
|
|
],
|
|
'default' => self::WIDGET_TYPE_STANDARD,
|
|
'description' => Plugin::__('Not sure which type you want to use? <a href="https://trycap.dev/guide/demo.html" target="_blank">View the demo</a> to try them out.'),
|
|
]
|
|
);
|
|
|
|
|
|
}
|
|
|
|
public function page() {
|
|
if (!current_user_can(self::CAPABILITY)) return;
|
|
|
|
// Show error/update messages
|
|
settings_errors(Plugin::get_id());
|
|
?>
|
|
<div class="wrap">
|
|
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
|
<form action="options.php" method="post"><?php
|
|
settings_fields(Plugin::get_id());
|
|
do_settings_sections(Plugin::get_id());
|
|
submit_button();
|
|
?></form>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
public function section(array $args):void {
|
|
if (!empty($args['description'] ?? '')) {
|
|
echo wpautop($args['description']);
|
|
}
|
|
}
|
|
|
|
public function field(array $args):void {
|
|
if (empty($args['name'] ?? '')) return;
|
|
|
|
$attributes = [
|
|
'type' => $args['type'] ?? 'text',
|
|
'class' => 'regular-text',
|
|
'name' => sprintf(
|
|
'%s[%s]',
|
|
Plugin::get_id(),
|
|
$args['name']
|
|
),
|
|
'id' => $args['name'],
|
|
'value' => (string) self::get($args['name']),
|
|
];
|
|
if ($args['readonly'] ?? false) $attributes['readonly'] = 'readonly';
|
|
if ($args['required'] ?? false) $attributes['required'] = 'required';
|
|
|
|
if (!empty($args['placeholder'] ?? '')) {
|
|
$attributes['placeholder'] = $args['placeholder'];
|
|
}
|
|
|
|
if (!empty($args['description'] ?? '')) {
|
|
$attributes['describedby'] = $args['name'] . '-description';
|
|
}
|
|
|
|
if (isset($args['attributes']) && is_array($args['attributes'])) {
|
|
$attributes = array_merge($attributes, $args['attributes']);
|
|
}
|
|
|
|
printf(
|
|
'<input %s />',
|
|
implode(
|
|
' ',
|
|
array_map(
|
|
fn (string $name, string $value): string => sprintf(
|
|
'%s="%s"',
|
|
$name,
|
|
esc_attr($value)
|
|
),
|
|
array_keys($attributes),
|
|
array_values($attributes)
|
|
)
|
|
)
|
|
);
|
|
|
|
if (!empty($args['description'] ?? '')) {
|
|
printf(
|
|
'<p class="description" id="%s-description">%s</p>',
|
|
esc_attr($args['name']),
|
|
nl2br($args['description'])
|
|
);
|
|
}
|
|
}
|
|
|
|
public function checkbox_field(array $args):void {
|
|
if (empty($args['name'] ?? '') || empty($args['options'] ?? [])) return;
|
|
|
|
if (!!($args['select_all'] ?? false) && ($args['type'] ?? 'checkbox') == 'checkbox') {
|
|
printf(
|
|
'<label><input type="checkbox" onClick="document.getElementsByName(\'%s[%s][]\').forEach(element => { element.checked = this.checked });"> %s</label><br>',
|
|
esc_attr(Plugin::get_id()),
|
|
esc_attr($args['name']),
|
|
Plugin::esc_html__('Select All')
|
|
);
|
|
}
|
|
|
|
echo implode('<br>', array_map(
|
|
fn (string $name, string $label):string => sprintf(
|
|
'<label><input type="%s" name="%s[%s]%s" value="%s" %s> %s</label>',
|
|
esc_attr($args['type'] ?? 'checkbox'),
|
|
esc_attr(Plugin::get_id()),
|
|
esc_attr($args['name']),
|
|
(($args['type'] ?? 'checkbox') ? '[]' : ''),
|
|
esc_attr($name),
|
|
checked(self::is_checked($args['name'], $name, $args['default'] ?? null), display: false),
|
|
esc_html($label)
|
|
),
|
|
array_keys($args['options']),
|
|
array_values($args['options'])
|
|
));
|
|
|
|
if (!empty($args['description'] ?? '')) {
|
|
printf(
|
|
'<p class="description" id="%s-description">%s</p>',
|
|
esc_attr($args['name']),
|
|
nl2br($args['description'])
|
|
);
|
|
}
|
|
}
|
|
|
|
public static function get_url():string {
|
|
return admin_url('options-general.php?page=' . Plugin::get_id());
|
|
}
|
|
|
|
}
|
|
|
|
Settings::instance();
|