plugin = $plugin_instance;
$this->admin_pages = $admin_pages_instance;
}
public function register_settings() {
$page = 'advaipbl_settings_page';
register_setting('advaipbl_settings_group', ADVAIPBL_Main::OPTION_SETTINGS, [$this, 'sanitize_settings']);
register_setting('advaipbl_waf_rules_group', ADVAIPBL_Main::OPTION_WAF_RULES, ['sanitize_callback' => [$this, 'sanitize_waf_rules']]);
add_settings_section('advaipbl_general_settings_section', null, null, $page);
add_settings_field('advaipbl_enable_logging', __('Enable Logging', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'enable_logging', 'label' => __('Enable logging of events to the database.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_log_retention_days', __('Log Retention (days)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'log_retention_days', 'default' => 30, 'description' => __('Number of days to keep logs in the DB. 0 to disable automatic purging.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_log_timezone', __('Timezone for Logs', 'advanced-ip-blocker'), [$this, 'timezone_select_callback'], $page, 'advaipbl_general_settings_section');
add_settings_field('advaipbl_custom_block_message', __('Block Message', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'custom_block_message', 'label' => __('Message for blocked users. Leave blank for default messages.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_excluded_error_urls', __('Global URL Exclusions', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'excluded_error_urls', 'label' => __('Add one URL path or fragment per line. Requests containing these strings will bypass 404/403 error logging and all JavaScript challenges (Signature, Geo, and Endpoint).', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_show_admin_bar_menu', __( 'Admin Bar Menu', 'advanced-ip-blocker' ), [$this, 'switch_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'show_admin_bar_menu', 'label' => __( 'Show security menu in the WordPress admin bar', 'advanced-ip-blocker' )]);
add_settings_field('advaipbl_global_challenge_cookie_duration', __( 'Global Challenge Duration (Hours)', 'advanced-ip-blocker' ), [$this, 'text_field_callback'], $page, 'advaipbl_general_settings_section', ['name' => 'global_challenge_cookie_duration', 'default' => 4, 'description' => __( 'How long a visitor can access the site after passing a JS challenge (e.g. from Lockdowns, Login Page, XML-RPC or Advanced Rules). Set to 0 for the browser session only.', 'advanced-ip-blocker' )]);
add_settings_field('advaipbl_revoke_vip_passes_button', __('Global VIP Revocation', 'advanced-ip-blocker'), [$this, 'revoke_vip_passes_button_callback'], $page, 'advaipbl_general_settings_section');
add_settings_section('advaipbl_general_settings_section', null, null, $page);
add_settings_field(
'advaipbl_allow_telemetry',
__('Usage Tracking', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_general_settings_section',
[
'name' => 'allow_telemetry',
'id' => 'advaipbl_allow_telemetry',
'label' => __('Share anonymous usage data to help us improve the plugin.', 'advanced-ip-blocker'),
'description' => __('Learn More about what we collect.', 'advanced-ip-blocker')
]
);
add_settings_section('advaipbl_email_notifications_section', null, null, $page);
add_settings_field('advaipbl_enable_email_notifications', __('Enable Email Notifications', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_email_notifications_section', ['name' => 'enable_email_notifications', 'label' => __('Send an email when an IP is blocked.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_notification_frequency', __('Notification Frequency', 'advanced-ip-blocker'), [$this, 'notification_frequency_callback'], $page, 'advaipbl_email_notifications_section');
add_settings_field('advaipbl_notification_email', __('Notification Email', 'advanced-ip-blocker'), [$this, 'email_field_callback'], $page, 'advaipbl_email_notifications_section', ['name' => 'notification_email', 'label' => __('Leave empty to use the admin email.', 'advanced-ip-blocker')]);
add_settings_field( 'advaipbl_send_test_email_button', __( 'Send Test Email', 'advanced-ip-blocker' ), [ $this, 'send_test_email_button_callback' ], $page, 'advaipbl_email_notifications_section' );
// Sub-sección para Push
add_settings_section('advaipbl_push_notifications_section', null, null, $page);
add_settings_field('advaipbl_enable_push_notifications', __('Enable Push Notifications', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_push_notifications_section', ['name' => 'enable_push_notifications', 'label' => __('Send real-time alerts via webhooks.', 'advanced-ip-blocker')]);
// Este usará el 'large-text' por defecto, que es correcto para URLs.
add_settings_field('advaipbl_push_webhook_urls', __('Push Webhook URLs', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_push_notifications_section', ['name' => 'push_webhook_urls', 'description' => __('One URL per line.', 'advanced-ip-blocker')]);
// A este le especificamos que use 'regular-text'.
add_settings_field('advaipbl_push_mentions', __('Mentions to Trigger Push', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_push_notifications_section', ['name' => 'push_mentions', 'rows' => 3, 'class' => 'regular-text', 'description' => __('Optional. To force a push notification on Slack/Discord, add a mention like @here, @channel, or a specific @username. Add one per line if needed.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_push_critical_only', __('Send Critical Alerts Only', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_push_notifications_section', ['name' => 'push_critical_only', 'label' => __('Only send alerts for instant blocks (WAF, Honeypot, etc.), not for threshold-based blocks (404, Login).', 'advanced-ip-blocker')]);
add_settings_field( 'advaipbl_send_test_push_button', __( 'Send Test Notification', 'advanced-ip-blocker' ), [ $this, 'send_test_push_button_callback' ], $page, 'advaipbl_push_notifications_section' );
// --- Site Scanner Automation Settings ---
add_settings_section('advaipbl_scanner_settings_section', __('Site Scanner Automation', 'advanced-ip-blocker'), null, $page);
add_settings_field(
'advaipbl_enable_scheduled_scans',
__('Enable Scheduled Scans', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_scanner_settings_section',
[
'name' => 'enable_scheduled_scans',
'label' => __('Automatically run Deep Scans and email the report.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_scan_frequency',
__('Scan Frequency', 'advanced-ip-blocker'),
[$this, 'scan_frequency_callback'],
$page,
'advaipbl_scanner_settings_section'
);
add_settings_field(
'advaipbl_scan_notification_email',
__('Notification Email', 'advanced-ip-blocker'),
[$this, 'email_field_callback'],
$page,
'advaipbl_scanner_settings_section',
[
'name' => 'scan_notification_email',
'label' => __('Where to send the scan reports (leave blank for admin email).', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_send_test_scan_button',
__('Run Manual Scan & Email', 'advanced-ip-blocker'),
[$this, 'send_test_scan_button_callback'],
$page,
'advaipbl_scanner_settings_section'
);
// Automation & Trigger Rules
add_settings_field(
'advaipbl_scan_email_trigger',
__('Alert Trigger Rule', 'advanced-ip-blocker'),
[$this, 'select_field_callback'],
$page,
'advaipbl_scanner_settings_section',
[
'name' => 'scan_email_trigger',
'options' => [
'any_issue' => __('Send email when ANY issue is found (Updates, Vulnerabilities, Env Errors)', 'advanced-ip-blocker'),
'vulnerabilities_only' => __('Agency Mode: ONLY send email if Critical Vulnerabilities (CVEs) or Blacklists are detected. (Ignores standard updates)', 'advanced-ip-blocker'),
'always' => __('Always send report, even if the site is completely clean.', 'advanced-ip-blocker')
],
'default' => 'any_issue',
'label' => __('Choose when the automatic scan should notify you.', 'advanced-ip-blocker')
]
);
// Granular Scan Checks
add_settings_field('advaipbl_scan_check_vulnerabilities', __('Check Vulnerabilities (CVE)', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_vulnerabilities', 'default' => '1', 'label' => __('Enable scanning active plugins and themes against the known vulnerabilities database.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_scan_check_ssl', __('Check SSL Certificate', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_ssl', 'default' => '1', 'label' => __('Enable SSL/TLS certificate validation.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_scan_check_updates', __('Check Updates', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_updates', 'default' => '1', 'label' => __('Enable core, plugin, and theme update checks.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_scan_check_php', __('Check PHP Version', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_php', 'default' => '1', 'label' => __('Enable PHP version compatibility checks.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_scan_check_wp', __('Check WordPress Version', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_wp', 'default' => '1', 'label' => __('Enable WordPress core version checks.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_scan_check_debug', __('Check Debug Mode', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_scanner_settings_section', ['name' => 'scan_check_debug', 'default' => '1', 'label' => __('Enable WP_DEBUG status checks.', 'advanced-ip-blocker')]);
add_settings_section(
'advaipbl_ip_detection_section',
null,
null,
$page
);
add_settings_field(
'advaipbl_trusted_proxies',
__('Trusted Proxies', 'advanced-ip-blocker'),
[$this, 'textarea_field_callback'],
$page,
'advaipbl_ip_detection_section',
[
'name' => 'trusted_proxies',
'rows' => 10,
'label' => __('Define which proxy servers you trust to provide the real visitor IP address. The plugin will only trust headers like X-Forwarded-For if the request comes from one of these IPs, preventing IP spoofing.', 'advanced-ip-blocker'),
'description' => __('Enter one IP, CIDR range, or ASN per line. Use # for comments. Example:# Cloudflare', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/ip-detection-trusted-proxies-guide/'
]
);
// Sección Geolocation.
add_settings_section(
'advaipbl_geolocation_section',
null,
null,
$page
);
add_settings_field(
'advaipbl_geolocation_method',
__( 'Geolocation Method', 'advanced-ip-blocker' ),
[$this, 'geolocation_method_callback'],
$page,
'advaipbl_geolocation_section'
);
// --- AbuseIPDB Section ---
add_settings_section('advaipbl_abuseipdb_section', null, null, $page);
add_settings_field(
'advaipbl_enable_abuseipdb',
__('Enable AbuseIPDB Protection', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_abuseipdb_section',
[
'name' => 'enable_abuseipdb',
'label' => __('Activate real-time IP reputation checking.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/abuseipdb-integration-guide/'
]
);
add_settings_field(
'advaipbl_abuseipdb_api_key',
__('AbuseIPDB API Key', 'advanced-ip-blocker'),
[$this, 'text_field_callback'],
$page,
'advaipbl_abuseipdb_section',
[
'name' => 'abuseipdb_api_key',
'class' => 'regular-text',
'data_provider' => 'abuseipdb' // Usado por JS para el botón de verificar
]
);
add_settings_field(
'advaipbl_abuseipdb_threshold',
__('Blocking Confidence Score', 'advanced-ip-blocker'),
[$this, 'text_field_callback'],
$page,
'advaipbl_abuseipdb_section',
[
'name' => 'abuseipdb_threshold',
'default' => 90,
'description' => __('Block IPs with an abuse confidence score of this value or higher (0-100). Recommended: 90 or 100.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_abuseipdb_action',
__('Action on High Score', 'advanced-ip-blocker'),
[$this, 'action_select_callback'],
$page,
'advaipbl_abuseipdb_section',
[
'name' => 'abuseipdb_action',
'description' => __('Choose whether to block high-risk IPs immediately or to present them with a JavaScript challenge.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_duration_abuseipdb',
__('Block Duration (minutes)', 'advanced-ip-blocker'),
[$this, 'text_field_callback'],
$page,
'advaipbl_abuseipdb_section',
[
'name' => 'duration_abuseipdb',
'default' => 1440, // 24 horas
'description' => __('How long to block an IP flagged by AbuseIPDB. Set to 0 for a permanent block.', 'advanced-ip-blocker')
]
);
// --- AIB COMMUNITY NETWORK SECTION ---
add_settings_section('advaipbl_community_network_section', null, null, $page);
// --- V3 API Connection ---
add_settings_field(
'advaipbl_api_connection_status',
__('AIB Account Connection', 'advanced-ip-blocker'),
[$this, 'api_connection_status_callback'],
$page,
'advaipbl_community_network_section'
);
add_settings_field(
'advaipbl_api_token_v3',
__('API Token', 'advanced-ip-blocker'),
[$this, 'api_token_field_callback'],
$page,
'advaipbl_community_network_section',
[
'name' => 'api_token_v3',
'description' => __('Connecting to the Advanced IP Blocker cloud network gives you access to the community blocklist and deep site scanning.', 'advanced-ip-blocker'),
]
);
add_settings_field(
'advaipbl_enable_community_network',
__('Join Community Defense Network', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_community_network_section',
[
'name' => 'enable_community_network',
'label' => __('Enable Community Defense', 'advanced-ip-blocker'),
'description' => __('Participate in the global defense network. Your plugin will share anonymized attack data (Verified IPs) to help build the AIB Community Blocklist.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/aib-community-defense-network/'
]
);
add_settings_field(
'advaipbl_enable_community_blocking',
__('Enable Community Blocking', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_community_network_section',
[
'name' => 'enable_community_blocking',
'label' => __('Block visitors found in the global AIB Community Blocklist.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_community_blocking_action',
__('Action', 'advanced-ip-blocker'),
[$this, 'action_select_callback'], // Usamos el nuevo callback genérico
$page,
'advaipbl_community_network_section',
[
'name' => 'community_blocking_action',
'description' => __('Decide how to handle IPs listed in the community database.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_duration_aib_network',
__('Block Duration (minutes)', 'advanced-ip-blocker'),
[$this, 'text_field_callback'],
$page,
'advaipbl_community_network_section',
[
'name' => 'duration_aib_network',
'default' => 1440,
'description' => __('How long to block an IP listed in the community database. Set to 0 for a permanent block.', 'advanced-ip-blocker')
]
);
// API PROVIDER (solo para el método 'api')
add_settings_field(
'advaipbl_geolocation_provider',
__( 'API Provider', 'advanced-ip-blocker' ),
[$this, 'geolocation_provider_callback'],
$page,
'advaipbl_geolocation_section',
['class' => 'advaipbl-geolocation-api-option'] // Clase para JS
);
// API KEYS (solo para el método 'api')
add_settings_field('advaipbl_api_key_ip_apicom', 'ip-api.com ' . __('API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'api_key_ip_apicom', 'description' => __('Optional key for HTTPS access.', 'advanced-ip-blocker'), 'class' => 'api-key-field advaipbl-geolocation-api-option', 'data_provider' => 'ip-api.com']);
add_settings_field('advaipbl_api_key_ipinfocom', 'ipinfo.io ' . __('API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'api_key_ipinfocom', 'description' => __('API key is recommended for higher limits.', 'advanced-ip-blocker'), 'class' => 'api-key-field advaipbl-geolocation-api-option', 'data_provider' => 'ipinfo.io']);
add_settings_field('advaipbl_api_key_ipapicom', 'ipapi.com ' . __('API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'api_key_ipapicom', 'description' => __('API Key is required.', 'advanced-ip-blocker'), 'class' => 'api-key-field advaipbl-geolocation-api-option', 'data_provider' => 'ipapi.com']);
add_settings_field('advaipbl_api_key_ipstackcom', 'ipstack.com ' . __('API Key', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'api_key_ipstackcom', 'description' => __('API Key is required.', 'advanced-ip-blocker'), 'class' => 'api-key-field advaipbl-geolocation-api-option', 'data_provider' => 'ipstack.com']);
// MAXMIND (solo para el método 'local_db')
add_settings_field('advaipbl_maxmind_license_key', __( 'MaxMind License Key', 'advanced-ip-blocker' ), [$this, 'text_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'maxmind_license_key', 'class' => 'advaipbl-geolocation-db-option', 'description' => sprintf( wp_kses( /* translators: $s: Maxmind website URL */ __( 'Required for the Local Database method. Get a free key from the MaxMind website.', 'advanced-ip-blocker' ), ['a' => ['href' => [], 'target' => []]] ), 'https://www.maxmind.com/en/geolite2/signup' )]);
add_settings_field('advaipbl_geoip_db_status', __( 'Local Database Status', 'advanced-ip-blocker' ), [$this, 'geoip_db_status_callback'], $page, 'advaipbl_geolocation_section', ['class' => 'advaipbl-geolocation-db-option']);
// CACHE (siempre visible)
add_settings_field('advaipbl_clear_location_cache_button', __('Geolocation Cache', 'advanced-ip-blocker'), [$this, 'clear_cache_button_callback'], $page, 'advaipbl_geolocation_section');
// --- Geoblocking Section ---
add_settings_field('advaipbl_geoblock_separator', '', [$this, 'geoblock_separator_callback'], $page, 'advaipbl_geolocation_section');
add_settings_field('advaipbl_enable_geoblocking', __('Enable Geoblocking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_geolocation_section', ['name' => 'enable_geoblocking', 'label' => __('Activate country-based blocking.', 'advanced-ip-blocker'), 'description' => sprintf(__('Block access from entire countries. This feature requires a working Geolocation Provider to be configured above.', 'advanced-ip-blocker'))]);
add_settings_field('advaipbl_geoblock_countries', __( 'Blocked Countries', 'advanced-ip-blocker' ), [ $this, 'geoblock_countries_callback' ], $page, 'advaipbl_geolocation_section' );
add_settings_field('advaipbl_duration_geoblock', __( 'Geoblock Duration (min)', 'advanced-ip-blocker' ), [ $this, 'text_field_callback' ], $page, 'advaipbl_geolocation_section', ['name' => 'duration_geoblock', 'default' => 1440, 'description' => __( 'How long an IP from a blocked country will be blocked. Set to 0 for a permanent block.', 'advanced-ip-blocker' )]);
// --- Geo-Challenge Section ---
add_settings_field('advaipbl_geochallenge_separator', '', [$this, 'geochallenge_separator_callback'], $page, 'advaipbl_geolocation_section');
add_settings_field(
'advaipbl_enable_geo_challenge',
__('Enable Geo-Challenge', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_geolocation_section',
[
'name' => 'enable_geo_challenge',
'label' => __('Activate country-based JavaScript challenge.', 'advanced-ip-blocker'),
'description' => __('Instead of a hard block, this presents a quick, invisible JavaScript challenge...', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_geo_challenge_countries',
__( 'Challenged Countries', 'advanced-ip-blocker' ),
[ $this, 'geoblock_countries_callback' ],
$page,
'advaipbl_geolocation_section',
['type' => 'geo_challenge']
);
add_settings_field(
'advaipbl_geo_challenge_mode',
__( 'Challenge Mode', 'advanced-ip-blocker' ),
[ $this, 'challenge_mode_callback' ],
$page,
'advaipbl_geolocation_section',
[
'name' => 'geo_challenge_mode',
'default' => 'managed',
'description' => __( 'Automatic (Transparent) vs Managed (User must interact).', 'advanced-ip-blocker' )
]
);
add_settings_section('advaipbl_honeypot_settings_section', null, null, $page);
add_settings_field(
'advaipbl_enable_honeypot_blocking',
__('Enable Honeypot Blocking', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_honeypot_settings_section',
[
'name' => 'enable_honeypot_blocking',
'label' => __('Activate Honeypot trap protection.', 'advanced-ip-blocker'),
'description' => sprintf(/* translators: $s: Honeypot blocking rules URL */__('Manage Honeypot URLs in the Blocking Rules tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=rules&sub-tab=honeypot')),
'help_url' => 'https://advaipbl.com/honeypot-guide/'
]
);
add_settings_field('advaipbl_duration_honeypot', __('Honeypot Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_honeypot_settings_section', ['name' => 'duration_honeypot', 'default' => 1440, 'description' => __('Block duration for IPs that fall into a honeypot URL. Set to 0 for a permanent block.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_user_agent_settings_section', null, null, $page);
add_settings_field('advaipbl_enable_user_agent_blocking', __('Enable User-Agent Blocking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_user_agent_settings_section', ['name' => 'enable_user_agent_blocking', 'label' => __('Activate User-Agent based blocking.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: $s: User-Agent blocking rules URL */__('Manage User-Agent lists in the Blocking Rules tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=rules&sub-tab=user_agents'))]);
add_settings_field('advaipbl_duration_user_agent', __('User-Agent Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_user_agent_settings_section', ['name' => 'duration_user_agent', 'default' => 1440, 'description' => __('Block duration for IPs with a malicious User-Agent. Set to 0 for a permanent block.', 'advanced-ip-blocker')]);
add_settings_field(
'advaipbl_enable_bot_verification',
__('Verify Known Bots', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_user_agent_settings_section',
[
'name' => 'enable_bot_verification',
'label' => __('Enable reverse DNS verification for known crawlers (e.g., Googlebot, Bingbot).', 'advanced-ip-blocker'),
'description' => __('This prevents attackers from bypassing rules by faking their User-Agent. If an IP claims to be Googlebot but fails verification, it will be treated as a threat.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/verify-known-bots-rdns-guide/'
]
);
add_settings_field(
'advaipbl_enable_ai_bot_verification',
__('Verify AI Bots (CIDR)', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_user_agent_settings_section',
[
'name' => 'enable_ai_bot_verification',
'label' => __('Enable IP CIDR verification for AI crawlers (e.g., OpenAI, ChatGPT).', 'advanced-ip-blocker'),
'description' => __('Downloads official JSON IP lists from AI providers to verify their crawlers reliably, bypassing rDNS limitations.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/verify-ai-bots-cidr-guide/'
]
);
add_settings_field(
'advaipbl_enable_monitoring_bot_verification',
__('Verify Monitoring Bots (IP List)', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_user_agent_settings_section',
[
'name' => 'enable_monitoring_bot_verification',
'label' => __('Enable IP verification for Monitoring Bots (e.g., Uptime Robot, Pingdom).', 'advanced-ip-blocker'),
'description' => __('Downloads official IP lists from monitoring services to allow legitimate pings and block impersonators.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/verify-monitoring-bots-ip-list-complete-guide/'
]
);
add_settings_section('advaipbl_asn_protection_section', __('ASN Protection', 'advanced-ip-blocker'), null, $page);
add_settings_field(
'advaipbl_enable_spamhaus_asn',
__('Spamhaus ASN Protection', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_asn_protection_section',
[
'name' => 'enable_spamhaus_asn',
'label' => __('Enable automatic blocking using the Spamhaus ASN DROP list.', 'advanced-ip-blocker'),
'description' => __('Provides a powerful, auto-updating layer of protection against the worst networks on the internet. The list is refreshed daily.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/asn-blocking-guide/'
]
);
add_settings_field('advaipbl_enable_manual_asn', __('Manual ASN Protection', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_asn_protection_section', ['name' => 'enable_manual_asn', 'label' => __('Enable blocking based on your custom Manual ASN Blocklist.', 'advanced-ip-blocker'), 'description' => sprintf(/* translators: $s: ASN blocklist rules URL */__('Manage your custom list in the Blocking Rules tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=rules&sub-tab=asn_blocking'))]);
add_settings_field('advaipbl_duration_asn', __('ASN Block Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_asn_protection_section', ['name' => 'duration_asn', 'default' => 1440, 'description' => __('Duration to block IPs from both manual and automated ASN lists. Set to 0 for a permanent block.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_under_attack_section', __('Distributed Attack Protection (Auto-Panic)', 'advanced-ip-blocker'), null, $page);
add_settings_field(
'advaipbl_under_attack_mode',
__('Under Attack Mode', 'advanced-ip-blocker'),
[$this, 'select_field_callback'],
$page,
'advaipbl_under_attack_section',
[
'name' => 'under_attack_mode',
'options' => [
'off' => __('Off (Normal Operation)', 'advanced-ip-blocker'),
'auto' => __('Auto (Trigger on attack spikes)', 'advanced-ip-blocker'),
'manual' => __('Manual (Always On / Panic Mode)', 'advanced-ip-blocker')
],
'default' => 'off',
'label' => __('Activates a global JS Challenge for all non-whitelisted visitors to protect the server.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/distributed-attack-protection-auto-panic/'
]
);
add_settings_field('advaipbl_under_attack_threshold', __('Trigger Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_threshold', 'default' => 100, 'description' => __('Total blocks (from any module) required to auto-trigger the Panic Mode.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_under_attack_window', __('Detection Window (sec)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_window', 'default' => 60, 'description' => __('The time window in seconds in which the block threshold must be reached.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_under_attack_duration', __('Panic Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_duration', 'default' => 15, 'description' => __('How long the Global Challenge will stay active after being auto-triggered.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_under_attack_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_challenge_mode', 'default' => 'automatic', 'description' => __('Choose the type of JS challenge to serve during the Panic Mode.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_under_attack_notification_email', __('Emergency Email', 'advanced-ip-blocker'), [$this, 'email_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_notification_email', 'label' => __('Leave empty to use the standard admin email.', 'advanced-ip-blocker')]);
add_settings_field(
'advaipbl_under_attack_alerts',
__('Panic Alerts', 'advanced-ip-blocker'),
[$this, 'select_field_callback'],
$page,
'advaipbl_under_attack_section',
[
'name' => 'under_attack_alerts',
'options' => [
'always' => __('Send Always (Email & Push)', 'advanced-ip-blocker'),
'push_only' => __('Send Push Only (No Email)', 'advanced-ip-blocker'),
'disabled' => __('Disabled (Silent Mode)', 'advanced-ip-blocker')
],
'default' => 'always',
'description' => __('Choose how you want to be notified when Auto-Panic triggers.', 'advanced-ip-blocker')
]
);
add_settings_field('advaipbl_under_attack_excluded_urls', __('Panic Mode Exclusions', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_under_attack_section', ['name' => 'under_attack_excluded_urls', 'label' => __('Add one URI path or fragment per line (e.g., /wp-json/wc/v3/*). These URLs will NEVER be challenged during Panic Mode. Global Exclusions and WAF Exclusions are also automatically respected.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_waf_settings_section', null, null, $page);
add_settings_field(
'advaipbl_enable_waf',
__('Enable WAF', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_waf_settings_section',
[
'name' => 'enable_waf',
'label' => __('Activate the WAF to scan requests against your custom rules.', 'advanced-ip-blocker'),
'description' => sprintf(/* translators: $s: WAF blocking rules URL */__('Manage WAF rules in the Blocking Rules tab.', 'advanced-ip-blocker'), admin_url('admin.php?page=advaipbl_settings_page&tab=rules&sub-tab=waf')),
'help_url' => 'https://advaipbl.com/waf-rules-guide/'
]
);
add_settings_field('advaipbl_duration_waf', __('WAF Block Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_waf_settings_section', ['name' => 'duration_waf', 'default' => 1440, 'description' => __('Duration to block IPs that trigger a WAF rule. Set to 0 for a permanent block.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_waf_excluded_urls', __('Excluded URLs for WAF', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_waf_settings_section', ['name' => 'waf_excluded_urls', 'label' => __('Add one URL fragment per line. Requests to URLs containing these strings will not be scanned by the WAF. Use this for payment gateway webhooks or problematic AJAX actions.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_404_settings_section', null, null, $page);
// --- 404 Distributed Lockdown Settings ---
add_settings_field('advaipbl_enable_404_lockdown', __('Enable 404 Lockdown Mode', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'enable_404_lockdown', 'label' => __('Activate Distributed Attack Protection', 'advanced-ip-blocker'), 'description' => __('If enabled, a global "Lockdown" will be triggered when too many 404 errors occur from multiple IPs. During lockdown, ALL 404 visitors must solve a JS Challenge.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_404_event_threshold', __('Lockdown Trigger: Max Errors', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_event_threshold', 'default' => 50, 'description' => __('Total 404 errors allowed across the entire site...', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_404_ip_threshold', __('Lockdown Trigger: Min Unique IPs', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_ip_threshold', 'default' => 5, 'description' => __('...originating from at least this many unique IPs...', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_404_window', __('Lockdown Trigger: Time Window', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_window', 'default' => 10, 'description' => __('...within this many minutes.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_404_duration', __('Lockdown Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_duration', 'default' => 60, 'description' => __('How long the Lockdown Mode stays active.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_404_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'lockdown_404_challenge_mode', 'description' => __('Choose the type of JS challenge to serve during a 404 Lockdown.', 'advanced-ip-blocker')]);
// Separator
add_settings_field('advaipbl_404_separator', '', [$this, 'separator_callback'], $page, 'advaipbl_404_settings_section');
// --- Existing Single IP Settings ---
add_settings_field('advaipbl_threshold_404', __('Single IP: Block Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'threshold_404', 'default' => 10, 'description' => __('Block a specific IP if it generates this many 404 errors.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_transient_expiration_404', __('404 Time Window (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'transient_expiration_404', 'default' => 60, 'description' => __('Time period in which the error count must be reached.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_duration_404', __('404 Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_404_settings_section', ['name' => 'duration_404', 'default' => 120, 'description' => __('How long the IP will be blocked.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_403_settings_section', null, null, $page);
// --- 403 Distributed Lockdown Settings ---
add_settings_field('advaipbl_enable_403_lockdown', __('Enable 403 Lockdown Mode', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'enable_403_lockdown', 'label' => __('Activate Distributed Attack Protection', 'advanced-ip-blocker'), 'description' => __('If enabled, a global "Lockdown" will be triggered when too many 403 errors occur. During lockdown, ALL 403 visitors must solve a JS Challenge.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_403_event_threshold', __('Lockdown Trigger: Max Errors', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_event_threshold', 'default' => 50, 'description' => __('Total 403 errors allowed across the entire site...', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_403_ip_threshold', __('Lockdown Trigger: Min Unique IPs', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_ip_threshold', 'default' => 5, 'description' => __('...originating from at least this many unique IPs...', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_403_window', __('Lockdown Trigger: Time Window', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_window', 'default' => 10, 'description' => __('...within this many minutes.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_403_duration', __('Lockdown Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_duration', 'default' => 60, 'description' => __('How long the Lockdown Mode stays active.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_lockdown_403_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'lockdown_403_challenge_mode', 'description' => __('Choose the type of JS challenge to serve during a 403 Lockdown.', 'advanced-ip-blocker')]);
// Separator
add_settings_field('advaipbl_403_separator', '', [$this, 'separator_callback'], $page, 'advaipbl_403_settings_section');
add_settings_field('advaipbl_threshold_403', __('Single IP: Block Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'threshold_403', 'default' => 5, 'description' => __('Block a specific IP if it generates this many 403 errors.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_transient_expiration_403', __('403 Time Window (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'transient_expiration_403', 'default' => 30, 'description' => __('Time period in which the error count must be reached.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_duration_403', __('403 Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_403_settings_section', ['name' => 'duration_403', 'default' => 60, 'description' => __('How long the IP will be blocked.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_rate_limiting_section', null, null, $page);
add_settings_field('advaipbl_rate_limiting_enable', __('Enable Rate Limiting', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'rate_limiting_enable', 'label' => __('Temporarily block IPs that make too many requests.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_rate_limiting_limit', __('Request Limit', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'rate_limiting_limit', 'default' => 120, 'description' => __('Number of requests to allow within the time window.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_rate_limiting_window', __('Time Window (seconds)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'rate_limiting_window', 'default' => 60, 'description' => __('The time period in which the request count is measured.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_duration_rate_limit', __('Block Duration (minutes)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_rate_limiting_section', ['name' => 'duration_rate_limit', 'default' => 5, 'description' => __('How long the IP will be blocked after reaching the limit.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_login_settings_section', null, null, $page);
add_settings_field('advaipbl_threshold_login', __('Login Failure Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_settings_section', ['name' => 'threshold_login', 'default' => 5, 'description' => __('Number of failed logins to trigger a block.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_transient_expiration_login', __('Login Time Window (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_settings_section', ['name' => 'transient_expiration_login', 'default' => 60, 'description' => __('Time period in which the failure count must be reached.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_duration_login', __('Login Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_login_settings_section', ['name' => 'duration_login', 'default' => 120, 'description' => __('How long the IP will be blocked.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_advanced_login_section', null, null, $page);
add_settings_field('advaipbl_auto_whitelist_admin', __('Auto-Whitelist Admins', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_login_section', ['name' => 'auto_whitelist_admin', 'label' => __('Automatically add administrator IPs to the whitelist on successful login.', 'advanced-ip-blocker'), 'description' => __('Ideal for admins who travel or have dynamic IP addresses.', 'advanced-ip-blocker')]);
add_settings_field('advaipbl_disable_user_enumeration', __( 'REST API User Protection', 'advanced-ip-blocker' ), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_login_section', ['name' => 'disable_user_enumeration', 'label' => __( 'Disable User Enumeration via REST API', 'advanced-ip-blocker' )]);
add_settings_field('advaipbl_prevent_author_scanning', __( 'Author Scan Protection', 'advanced-ip-blocker' ), [$this, 'switch_field_callback'], $page, 'advaipbl_advanced_login_section', ['name' => 'prevent_author_scanning', 'label' => __( 'Prevent user enumeration via author scans', 'advanced-ip-blocker' )]);
add_settings_field(
'advaipbl_prevent_login_hinting',
__( 'Prevent Login Hinting', 'advanced-ip-blocker' ),
[$this, 'switch_field_callback'],
$page,
'advaipbl_advanced_login_section',
[
'name' => 'prevent_login_hinting',
'label' => __( 'Prevent WordPress from revealing whether a username or email exists on login failure.', 'advanced-ip-blocker' ),
'description' => __( 'Shows a generic error message for all login and "lost password" failures to prevent user enumeration.', 'advanced-ip-blocker' )
]
);
add_settings_field('advaipbl_restrict_login_page', __( 'Whitelist Login Access', 'advanced-ip-blocker' ), [ $this, 'restrict_login_page_callback' ], $page, 'advaipbl_advanced_login_section');
add_settings_field('advaipbl_login_restrict_countries', __( 'Whitelist Login Countries', 'advanced-ip-blocker' ), [ $this, 'geoblock_countries_callback' ], $page, 'advaipbl_advanced_login_section', [
'type' => 'login_restrict',
'description' => __('Select one or more countries that are allowed to access wp-login.php. If empty, all countries are allowed.', 'advanced-ip-blocker')
]);
add_settings_section('advaipbl_advanced_xmlrpc_section', null, null, $page);
add_settings_field('advaipbl_xmlrpc_protection_mode', __('XML-RPC Protection Mode', 'advanced-ip-blocker'), [$this, 'xmlrpc_protection_mode_callback'], $page, 'advaipbl_advanced_xmlrpc_section');
add_settings_field('advaipbl_duration_xmlrpc_block', __('XML-RPC Block Duration (min)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_advanced_xmlrpc_section', ['name' => 'duration_xmlrpc_block', 'default' => 1440, 'description' => __('How long to block IPs that make suspicious XML-RPC requests. Set to 0 for a permanent block.', 'advanced-ip-blocker')]);
// --- Campos para el nuevo Endpoint Lockdown ---advaipbl_advanced_xmlrpc_protection_section
add_settings_section('advaipbl_advanced_xmlrpc_protection_section', null, null, $page);
add_settings_field(
'advaipbl_enable_xmlrpc_lockdown',
__( 'XML-RPC Lockdown Mode', 'advanced-ip-blocker' ),
[$this, 'switch_field_callback'],
$page,
'advaipbl_advanced_xmlrpc_protection_section',
[
'name' => 'enable_xmlrpc_lockdown',
'label' => __( 'Enable automated protection against distributed XML-RPC attacks.', 'advanced-ip-blocker' ),
'description' => sprintf(/* translators: $s: Blocked Endpoints tab link. */__( 'When a sustained attack is detected, this mode will temporarily challenge all non-whitelisted traffic to
AS13335
# Varnish Server
192.168.0.1
# Nginx Proxy
127.0.0.1xmlrpc.php with a JavaScript verifier, stopping the attack without flooding your block list. Manage endpoints that are currently in "Lockdown Mode" in the Blocked Endpoints tab.', 'advanced-ip-blocker' ), admin_url('admin.php?page=advaipbl_settings_page&tab=ip_management&sub-tab=blocked_endpoints'))
]
);
add_settings_field(
'advaipbl_xmlrpc_lockdown_threshold',
__( 'Lockdown Threshold', 'advanced-ip-blocker' ),
[$this, 'text_field_callback'],
$page,
'advaipbl_advanced_xmlrpc_protection_section',
[
'name' => 'xmlrpc_lockdown_threshold',
'default' => 10,
'description' => __( 'Number of unique IP blocks on xmlrpc.php needed to trigger the lockdown.', 'advanced-ip-blocker' )
]
);
add_settings_field(
'advaipbl_xmlrpc_lockdown_window',
__( 'Lockdown Detection Window (min)', 'advanced-ip-blocker' ),
[$this, 'text_field_callback'],
$page,
'advaipbl_advanced_xmlrpc_protection_section',
[
'name' => 'xmlrpc_lockdown_window',
'default' => 15,
'description' => __( 'The time frame (in minutes) in which the threshold must be reached.', 'advanced-ip-blocker' )
]
);
add_settings_field(
'advaipbl_xmlrpc_lockdown_duration',
__( 'Lockdown Duration (min)', 'advanced-ip-blocker' ),
[$this, 'text_field_callback'],
$page,
'advaipbl_advanced_xmlrpc_protection_section',
[
'name' => 'xmlrpc_lockdown_duration',
'default' => 60,
'description' => __( 'How long the lockdown mode will remain active (in minutes).', 'advanced-ip-blocker' )
]
);
add_settings_field(
'advaipbl_xmlrpc_lockdown_challenge_mode',
__( 'Challenge Mode', 'advanced-ip-blocker' ),
[$this, 'challenge_mode_callback'],
$page,
'advaipbl_advanced_xmlrpc_protection_section',
[
'name' => 'xmlrpc_lockdown_challenge_mode',
'description' => __( 'Choose the type of JS challenge to serve to non-whitelisted XML-RPC traffic during lockdown.', 'advanced-ip-blocker' )
]
);
add_settings_section('advaipbl_login_lockdown_section', null, null, $page);
add_settings_field(
'advaipbl_enable_login_lockdown',
__( 'Login Page Lockdown Mode', 'advanced-ip-blocker' ),
[$this, 'switch_field_callback'],
$page,
'advaipbl_login_lockdown_section',
[
'name' => 'enable_login_lockdown',
'label' => __( 'Enable automated protection against distributed brute-force attacks.', 'advanced-ip-blocker' ),
'description' => sprintf(/* translators: $s: Blocked Endpoints tab link. */__( 'When a sustained brute-force attack is detected, this mode will temporarily challenge all non-whitelisted traffic to wp-login.php with a JavaScript verifier.Manage endpoints that are currently in "Lockdown Mode" in the Blocked Endpoints tab.', 'advanced-ip-blocker' ), admin_url('admin.php?page=advaipbl_settings_page&tab=ip_management&sub-tab=blocked_endpoints'))
]
);
add_settings_field(
'advaipbl_login_lockdown_event_threshold',
__( 'Lockdown Event Threshold', 'advanced-ip-blocker' ),
[$this, 'text_field_callback'],
$page,
'advaipbl_login_lockdown_section',
[
'name' => 'login_lockdown_event_threshold',
'default' => 50,
'description' => __( 'Total number of failed login attempts needed to trigger the lockdown.', 'advanced-ip-blocker' )
]
);
add_settings_field(
'advaipbl_login_lockdown_ip_threshold',
__( 'Lockdown Unique IP Threshold', 'advanced-ip-blocker' ),
[$this, 'text_field_callback'],
$page,
'advaipbl_login_lockdown_section',
[
'name' => 'login_lockdown_ip_threshold',
'default' => 10,
'description' => __( 'Minimum number of unique IPs that must contribute to the failed logins.', 'advanced-ip-blocker' )
]
);
add_settings_field(
'advaipbl_login_lockdown_window',
__( 'Lockdown Detection Window (min)', 'advanced-ip-blocker' ),
[$this, 'text_field_callback'],
$page,
'advaipbl_login_lockdown_section',
[
'name' => 'login_lockdown_window',
'default' => 5,
'description' => __( 'The time frame (in minutes) in which the thresholds must be reached.', 'advanced-ip-blocker' )
]
);
add_settings_field(
'advaipbl_login_lockdown_duration',
__( 'Lockdown Duration (min)', 'advanced-ip-blocker' ),
[$this, 'text_field_callback'],
$page,
'advaipbl_login_lockdown_section',
[
'name' => 'login_lockdown_duration',
'default' => 60,
'description' => __( 'How long the lockdown mode will remain active (in minutes).', 'advanced-ip-blocker' )
]
);
add_settings_field(
'advaipbl_login_lockdown_challenge_mode',
__( 'Challenge Mode', 'advanced-ip-blocker' ),
[$this, 'challenge_mode_callback'],
$page,
'advaipbl_login_lockdown_section',
[
'name' => 'login_lockdown_challenge_mode',
'description' => __( 'Choose the type of JS challenge to serve during a Login Page Lockdown.', 'advanced-ip-blocker' )
]
);
add_settings_section('advaipbl_recaptcha_section', null, null, $page);
add_settings_field('advaipbl_recaptcha_enable', __('Enable reCAPTCHA', 'advanced-ip-blocker'), [$this, 'recaptcha_enable_callback'], $page, 'advaipbl_recaptcha_section', ['help_url' => 'https://advaipbl.com/setup-google-recaptcha-protection/']);
add_settings_field('advaipbl_recaptcha_version', __('reCAPTCHA Version', 'advanced-ip-blocker'), [$this, 'recaptcha_version_callback'], $page, 'advaipbl_recaptcha_section');
add_settings_field('advaipbl_recaptcha_site_key', __('Site Key', 'advanced-ip-blocker'), [$this, 'recaptcha_site_key_callback'], $page, 'advaipbl_recaptcha_section');
add_settings_field('advaipbl_recaptcha_secret_key', __('Secret Key', 'advanced-ip-blocker'), [$this, 'recaptcha_secret_key_callback'], $page, 'advaipbl_recaptcha_section');
add_settings_field('advaipbl_recaptcha_score_threshold', __('v3 Score Threshold', 'advanced-ip-blocker'), [$this, 'recaptcha_score_callback'], $page, 'advaipbl_recaptcha_section');
// SECCIÓN DE 2FA
add_settings_section(
'advaipbl_2fa_settings_section',
null, // El título ya está en el HTML de la pestaña
null,
$page
);
add_settings_field(
'advaipbl_enable_2fa',
__( 'Enable Two-Factor Authentication', 'advanced-ip-blocker' ),
[$this, 'switch_field_callback'],
$page,
'advaipbl_2fa_settings_section',
[
'name' => 'enable_2fa',
'label' => __( 'Enable the 2FA feature for all users on this site.', 'advanced-ip-blocker' ),
'description' => sprintf(/* translators: $s: User profile URL */__('When enabled, users will see the 2FA setup section in their Profile.', 'advanced-ip-blocker'), admin_url('profile.php'))
]
);
add_settings_field(
'advaipbl_tfa_force_roles',
__( 'Force 2FA for Roles', 'advanced-ip-blocker' ),
[$this, 'tfa_force_roles_callback'],
$page,
'advaipbl_2fa_settings_section'
);
// --- HTACCESS FIREWALL SECTION (INTEGRATED) ---
// Creamos una nueva sección que se mostrará en el Settings Page principal
add_settings_section('advaipbl_htaccess_settings_section', null, null, $page);
add_settings_field(
'advaipbl_enable_htaccess_write',
__('Enable Htaccess Writer', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_htaccess_settings_section',
[
'name' => 'enable_htaccess_write',
'label' => __('Allow the plugin to modify the .htaccess file.', 'advanced-ip-blocker'),
'description' => __('This is required for all server-level blocking features. The plugin creates a backup before every write operation.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/high-performance-server-level-firewall-htaccess/'
]
);
add_settings_field(
'advaipbl_enable_htaccess_ip_blocking',
__('Sync Blocked IPs', 'advanced-ip-blocker'),
[$this, 'checkbox_field_callback'],
$page,
'advaipbl_htaccess_settings_section',
[
'name' => 'enable_htaccess_ip_blocking',
'label' => __('Automatically write "Manually Blocked" and "Permanent" IPs to the .htaccess file.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_enable_htaccess_all_ips',
__('Include Temporary Blocks', 'advanced-ip-blocker'),
[$this, 'checkbox_field_callback'],
$page,
'advaipbl_htaccess_settings_section',
[
'name' => 'enable_htaccess_all_ips',
'label' => __('Write ALL blocked IPs (including temporary ones like 404/Login) to .htaccess.', 'advanced-ip-blocker'),
'description' => __('Advanced Performance: Offloads temporary blocks to the server. The file updates automatically when IPs expire. Requires "Sync Blocked IPs" to be enabled.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_htaccess_protect_system_files',
__('Block System Files', 'advanced-ip-blocker'),
[$this, 'checkbox_field_callback'],
$page,
'advaipbl_htaccess_settings_section',
[
'name' => 'htaccess_protect_system_files',
'label' => __('Block access to sensitive files (.git, .svn, .log, .sql, backups, etc.)', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_htaccess_protect_wp_config',
__('Block wp-config.php', 'advanced-ip-blocker'),
[$this, 'checkbox_field_callback'],
$page,
'advaipbl_htaccess_settings_section',
[
'name' => 'htaccess_protect_wp_config',
'label' => __('Block direct access to wp-config.php and wp-config-sample.php', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_htaccess_protect_readme',
__('Block Readme Files', 'advanced-ip-blocker'),
[$this, 'checkbox_field_callback'],
$page,
'advaipbl_htaccess_settings_section',
[
'name' => 'htaccess_protect_readme',
'label' => __('Block access to readme.html and license.txt (prevents version enumeration)', 'advanced-ip-blocker')
]
);
add_settings_section('advaipbl_cloudflare_section', null, null, $page);
add_settings_field(
'advaipbl_enable_cloudflare',
__('Enable Cloudflare Integration', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_cloudflare_section',
[
'name' => 'enable_cloudflare',
'label' => __('Activate synchronization with Cloudflare Firewall.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/cloud-edge-defense-setup/'
]
);
add_settings_field(
'advaipbl_cf_api_token',
__('Cloudflare API Token', 'advanced-ip-blocker'),
[$this, 'text_field_callback'],
$page,
'advaipbl_cloudflare_section',
[
'name' => 'cf_api_token',
'class' => 'regular-text',
'description' => __('Create a token with Zone > Firewall > Edit permissions. Get Token', 'advanced-ip-blocker'),
// Añadimos un atributo data para el JS de validación
'data_provider' => 'cloudflare'
]
);
add_settings_field(
'advaipbl_cf_zone_id',
__('Zone ID', 'advanced-ip-blocker'),
[$this, 'text_field_callback'],
$page,
'advaipbl_cloudflare_section',
[
'name' => 'cf_zone_id',
'class' => 'regular-text',
'description' => __('Found on the "Overview" page of your domain in Cloudflare (bottom right).', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_cf_sync_manual',
__('Sync Manual Blocks', 'advanced-ip-blocker'),
[$this, 'checkbox_field_callback'],
$page,
'advaipbl_cloudflare_section',
[
'name' => 'cf_sync_manual',
'label' => __('Push "Manually Blocked" IPs to Cloudflare.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_cf_sync_temporary',
__('Sync Temporary Blocks', 'advanced-ip-blocker'),
[$this, 'checkbox_field_callback'],
$page,
'advaipbl_cloudflare_section',
[
'name' => 'cf_sync_temporary',
'label' => __('Push temporary blocks (WAF, Login attempts, etc.) to Cloudflare.', 'advanced-ip-blocker'),
'description' => __('Recommended for High Security. Offload all bad traffic to the cloud.', 'advanced-ip-blocker')
]
);
add_settings_section('advaipbl_uninstall_section', null, null, $page);
add_settings_field('advaipbl_delete_data_on_uninstall', __('Delete Data on Uninstall', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_uninstall_section', ['name' => 'delete_data_on_uninstall', 'label' => __('Check to delete all data from this plugin when it is deleted.', 'advanced-ip-blocker')]);
add_settings_section('advaipbl_threat_scoring_section', null, null, $page);
add_settings_field(
'advaipbl_enable_threat_scoring',
__('Enable Threat Scoring System', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_threat_scoring_section',
[
'name' => 'enable_threat_scoring',
'label' => __('Activate the dynamic IP threat scoring system.', 'advanced-ip-blocker'),
'description' => __('When enabled, the plugin will assign threat points to IPs for malicious actions instead of using simple thresholds. An IP will be blocked only when its total score reaches the configured threshold.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/threat-scoring-system-guide/'
]
);
add_settings_field('advaipbl_threat_score_threshold', __('Blocking Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_threat_scoring_section', [
'name' => 'threat_score_threshold',
'default' => 100,
'description' => __('An IP will be blocked when its threat score reaches or exceeds this value.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_duration_threat_score', __('Block Duration (minutes)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_threat_scoring_section', [
'name' => 'duration_threat_score',
'default' => 360,
'description' => __('How long an IP will be blocked after reaching the threshold. Set to 0 for a permanent block.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_threat_scores', __('Threat Event Points', 'advanced-ip-blocker'), [$this, 'threat_scores_callback'], $page, 'advaipbl_threat_scoring_section');
add_settings_field('advaipbl_score_decay_points', __('Score Decay Rate', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_threat_scoring_section', [
'name' => 'score_decay_points',
'default' => 1,
'description' => __('Number of points to subtract from an inactive IP\'s score during each decay cycle.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_score_decay_frequency', __('Score Decay Frequency (Hours)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_threat_scoring_section', [
'name' => 'score_decay_frequency',
'default' => 1,
'description' => __('How often (in hours) to run the decay process. The score of an IP will only decay if it has been inactive for at least this period.', 'advanced-ip-blocker')
]);
add_settings_section('advaipbl_signature_engine_section', null, null, $page);
add_settings_field(
'advaipbl_enable_signature_engine',
__('Enable Signature Logging', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_signature_engine_section',
[
'name' => 'enable_signature_engine',
'label' => __('Activate the experimental request fingerprinting engine.', 'advanced-ip-blocker'),
'description' => __('Warning: This is an advanced feature for data collection. Activating it will log details of incoming requests to a new database table. Use only if you are aware of the potential performance impact on high-traffic sites.', 'advanced-ip-blocker'),
'help_url' => 'https://advaipbl.com/beyond-the-blocklist-introducing-the-intelligent-ip-trust-attack-signature-engines/'
]
);
add_settings_field('advaipbl_enable_signature_analysis', __('Enable Signature Analysis', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'enable_signature_analysis',
'label' => __('Activate automatic analysis of request signatures.', 'advanced-ip-blocker'),
'description' => __('When enabled, a background process will analyze the collected logs to find patterns of a distributed attack.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_enable_signature_blocking', __('Enable Signature Blocking', 'advanced-ip-blocker'), [$this, 'switch_field_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'enable_signature_blocking',
'label' => __('Activate blocking based on malicious signatures.', 'advanced-ip-blocker'),
'description' => __('Enable this to activate protection. When a request matches a known malicious signature, the plugin will present a JavaScript challenge to filter out bots.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_signature_challenge_mode', __('Challenge Mode', 'advanced-ip-blocker'), [$this, 'challenge_mode_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'signature_challenge_mode',
'description' => __('Choose the type of JS challenge to serve when defending against distributed attacks.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_signature_ip_threshold', __('Signature IP Threshold', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'signature_ip_threshold',
'default' => 5,
'description' => __('The minimum number of different IPs that must use the same attack signature to be flagged as malicious.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_signature_analysis_window', __('Analysis Window (Hours)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'signature_analysis_window',
'default' => 1,
'description' => __('How far back (in hours) the analysis process should look for patterns.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_signature_rule_ttl', __('Signature Rule Lifetime (Hours)', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'signature_rule_ttl',
'default' => 24,
'description' => __('How long a malicious signature will remain active before it expires.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_signature_notification_frequency', __('Notification Frequency', 'advanced-ip-blocker'), [$this, 'signature_notification_frequency_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'signature_notification_frequency',
'label' => __('How often to send alerts for detected signatures.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_signature_notification_recipient', __('Notification Recipient', 'advanced-ip-blocker'), [$this, 'signature_notification_recipient_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'signature_notification_recipient',
'label' => __('Who should receive these specific alerts.', 'advanced-ip-blocker')
]);
add_settings_field('advaipbl_signature_notification_custom_email', __('Custom Recipient Email', 'advanced-ip-blocker'), [$this, 'text_field_callback'], $page, 'advaipbl_signature_engine_section', [
'name' => 'signature_notification_custom_email',
'class' => 'regular-text',
'description' => __('Required if "Custom Email" is selected above.', 'advanced-ip-blocker')
]);
add_settings_section('advaipbl_trusted_signatures_section', __('Trusted Signatures (Whitelist)', 'advanced-ip-blocker'), [$this, 'trusted_signatures_section_callback'], $page);
add_settings_field('advaipbl_trusted_signature_hashes', __('Trusted Signature Hashes', 'advanced-ip-blocker'), [$this, 'textarea_field_callback'], $page, 'advaipbl_trusted_signatures_section', [
'name' => 'trusted_signature_hashes',
'label' => __('Add known legitimate signature hashes here (one per line). Requests matching these exact fingerprints will always be allowed and never logged by the Signature Engine. Use this for services like Googlebot, Facebook Crawler, etc., to prevent false positives. Find hashes in the "Blocked Signatures" page by clicking "View Details".', 'advanced-ip-blocker')
]);
// --- INTERNAL SECURITY & FORENSICS (v8.7.1) ---
add_settings_section('advaipbl_internal_security_section', __('Internal Security & Forensics', 'advanced-ip-blocker'), null, $page);
add_settings_field(
'advaipbl_enable_audit_log',
__('Enable Activity Audit Log', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_internal_security_section',
[
'name' => 'enable_audit_log',
'label' => __('Record critical administrative actions.', 'advanced-ip-blocker'),
'description' => __('Logs plugin rule changes, setting updates, and other critical admin events to a separate audit table.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_enable_fim',
__('Enable File Integrity Monitor', 'advanced-ip-blocker'),
[$this, 'switch_field_callback'],
$page,
'advaipbl_internal_security_section',
[
'name' => 'enable_fim',
'label' => __('Monitor critical WordPress files for unauthorized changes.', 'advanced-ip-blocker'),
'description' => __('Automatically scans core files (wp-config.php, .htaccess, index.php) daily for modifications.', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_fim_alert_email',
__('FIM Alert Email', 'advanced-ip-blocker'),
[$this, 'email_field_callback'],
$page,
'advaipbl_internal_security_section',
[
'name' => 'fim_alert_email',
'label' => __('Where to send critical file change alerts (leave blank for admin email).', 'advanced-ip-blocker')
]
);
add_settings_field(
'advaipbl_fim_manual_scan_button',
__('Manual Scan', 'advanced-ip-blocker'),
[$this, 'fim_manual_scan_button_callback'], // Use a new callback
$page,
'advaipbl_internal_security_section'
);
}
public function sanitize_settings($input) {
// Empezamos con las opciones antiguas como base.
$new_input = get_option(ADVAIPBL_Main::OPTION_SETTINGS, []);
$defaults = $this->plugin->get_default_settings();
// Base starting point is the EXISTING settings. This prevents wiping tabs that weren't submitted.
$existing_options = get_option( ADVAIPBL_Main::OPTION_SETTINGS, [] );
if ( ! is_array( $existing_options ) ) {
$existing_options = [];
}
$new_input = $existing_options;
$numeric_fields = [
'threshold_404', 'duration_404', 'transient_expiration_404',
'threshold_403', 'duration_403', 'transient_expiration_403',
'threshold_login', 'duration_login', 'transient_expiration_login',
'duration_geoblock', 'duration_honeypot', 'duration_user_agent', 'duration_waf', 'duration_rate_limit',
'rate_limiting_limit', 'rate_limiting_window', 'duration_asn', 'duration_xmlrpc_block',
'rows_per_page', 'log_retention_days',
'threat_score_threshold', 'duration_threat_score', 'score_404', 'score_403', 'score_login',
'score_user_agent', 'score_waf', 'score_honeypot', 'score_asn', 'score_impersonation',
'score_decay_points', 'score_decay_frequency',
'signature_ip_threshold', 'signature_analysis_window', 'signature_rule_ttl',
'xmlrpc_lockdown_threshold', 'xmlrpc_lockdown_window', 'xmlrpc_lockdown_duration',
'login_lockdown_event_threshold', 'login_lockdown_ip_threshold', 'login_lockdown_window', 'login_lockdown_duration',
'lockdown_404_event_threshold', 'lockdown_404_ip_threshold', 'lockdown_404_window', 'lockdown_404_duration',
'lockdown_403_event_threshold', 'lockdown_403_ip_threshold', 'lockdown_403_window', 'lockdown_403_duration',
'global_challenge_cookie_duration', 'geo_challenge_cookie_duration', 'abuseipdb_threshold', 'duration_abuseipdb', 'duration_aib_network',
'under_attack_threshold', 'under_attack_window', 'under_attack_duration'
];
foreach ($numeric_fields as $field) {
if (isset($input[$field])) {
$new_input[$field] = absint($input[$field]);
}
}
$checkbox_fields = [
'prevent_author_scanning', 'disable_user_enumeration', 'restrict_login_page',
'enable_logging', 'delete_data_on_uninstall', 'enable_email_notifications',
'enable_waf', 'enable_geoblocking', 'enable_honeypot_blocking',
'enable_user_agent_blocking', 'rate_limiting_enable', 'show_admin_bar_menu',
'enable_spamhaus_asn', 'enable_manual_asn',
'enable_push_notifications', 'push_critical_only', 'auto_whitelist_admin',
'allow_telemetry',
'enable_threat_scoring',
'enable_signature_engine',
'enable_signature_blocking',
'enable_signature_analysis',
'enable_2fa',
'recaptcha_enable',
'prevent_login_hinting',
'enable_xmlrpc_lockdown',
'enable_login_lockdown',
'enable_404_lockdown',
'enable_403_lockdown',
'enable_geo_challenge',
'enable_bot_verification', 'enable_ai_bot_verification', 'enable_monitoring_bot_verification',
'enable_community_blocking',
'enable_abuseipdb',
'enable_community_network',
'enable_htaccess_write',
'enable_cloudflare', 'cf_sync_manual', 'cf_sync_temporary',
'enable_htaccess_ip_blocking',
'enable_htaccess_all_ips',
'htaccess_protect_system_files',
'htaccess_protect_wp_config',
'htaccess_protect_readme',
'htaccess_protect_readme',
'enable_scheduled_scans',
'enable_audit_log',
'enable_fim',
'scan_check_ssl', 'scan_check_updates', 'scan_check_php', 'scan_check_wp', 'scan_check_debug',
];
foreach ($checkbox_fields as $field) {
// Dado que hemos inyectado un input oculto, SIEMPRE recibiremos '0' o '1' si la pestaña fue enviada.
// Si el campo fue enviado en $input (0 o 1), actualizamos $new_input.
// Si no fue enviado en $input en absoluto (es decir, pertenece a OTRA pestaña no enviada), conservamos el valor previo en $new_input.
if (isset($input[$field])) {
$new_input[$field] = ( $input[$field] === '1' ) ? '1' : '0';
}
}
// Campos de array y texto, que siempre deberían estar presentes en el formulario.
if (isset($input['tfa_force_roles'])) {
$new_input['tfa_force_roles'] = is_array($input['tfa_force_roles']) ? array_map('sanitize_key', $input['tfa_force_roles']) : [];
} else {
$new_input['tfa_force_roles'] = []; // Si no se envía nada, es un array vacío.
}
$text_fields = [
'notification_frequency', 'custom_block_message', 'excluded_error_urls', 'waf_excluded_urls',
'push_webhook_urls', 'push_mentions', 'trusted_signature_hashes', 'notification_email',
'signature_notification_frequency', 'signature_notification_recipient', 'signature_notification_custom_email',
'api_key_ipapicom', 'api_key_ipstackcom', 'api_key_ipinfocom', 'api_key_ip_apicom', 'maxmind_license_key',
'geolocation_provider', 'log_timezone', 'recaptcha_version', 'recaptcha_site_key', 'recaptcha_secret_key',
'xmlrpc_protection_mode', 'geolocation_method', 'trusted_proxies', 'abuseipdb_api_key', 'abuseipdb_action',
'cf_api_token', 'cf_zone_id', 'community_blocking_action', 'scan_frequency', 'scan_notification_email',
'fim_alert_email', 'api_token_v3',
'geo_challenge_mode', 'lockdown_404_challenge_mode', 'lockdown_403_challenge_mode',
'xmlrpc_lockdown_challenge_mode', 'login_lockdown_challenge_mode', 'signature_challenge_mode',
'under_attack_mode', 'under_attack_challenge_mode', 'under_attack_notification_email', 'under_attack_excluded_urls', 'under_attack_alerts'
];
foreach ($text_fields as $field) {
if (isset($input[$field])) {
if ($field === 'custom_block_message') {
// Permitimos h1 y br para el mensaje de bloqueo personalizado
$allowed_html = [
'h1' => [],
'br' => [],
];
$new_input[$field] = wp_kses($input[$field], $allowed_html);
} elseif (strpos($field, 'email') !== false) {
$new_input[$field] = sanitize_email($input[$field]);
} elseif (strpos($field, 'urls') !== false || strpos($field, 'proxies') !== false || strpos($field, 'hashes') !== false || strpos($field, 'mentions') !== false) { // Quitamos 'message' de aquí
$new_input[$field] = sanitize_textarea_field($input[$field]);
} else {
$new_input[$field] = sanitize_text_field($input[$field]);
}
}
}
// V3 API Token Validation (only if changed manually)
if (isset($new_input['api_token_v3']) && $new_input['api_token_v3'] !== ($this->plugin->options['api_token_v3'] ?? '')) {
if (!empty($new_input['api_token_v3'])) {
$response = wp_remote_get('https://advaipbl.com/wp-json/aib-api/v3/verify-token', [
'headers' => [
'Authorization' => 'Bearer ' . $new_input['api_token_v3'],
'Accept' => 'application/json'
],
'timeout' => 15
]);
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
add_settings_error('advaipbl_settings_messages', 'invalid_v3_token', __('Invalid AIB Cloud Network Token. Connection failed.', 'advanced-ip-blocker'), 'error');
$new_input['api_token_v3'] = $this->plugin->options['api_token_v3'] ?? ''; // Revert to previous or empty
}
}
}
// Trigger immediate MaxMind download if key is manually changed/added
if (isset($new_input['maxmind_license_key']) && $new_input['maxmind_license_key'] !== ($this->plugin->options['maxmind_license_key'] ?? '')) {
if (!empty($new_input['maxmind_license_key'])) {
wp_clear_scheduled_hook('advaipbl_update_geoip_db_event');
wp_schedule_event(time() + 60, 'advaipbl_3_days', 'advaipbl_update_geoip_db_event');
}
}
if (isset($input['geoblock_countries'])) {
$countries = (array) $input['geoblock_countries'];
$all_country_codes = array_keys($this->plugin->get_country_list());
$new_input['geoblock_countries'] = array_values(array_intersect($countries, $all_country_codes));
} else {
$new_input['geoblock_countries'] = [];
}
if (isset($input['geo_challenge_countries'])) {
$countries = (array) $input['geo_challenge_countries'];
$all_country_codes = array_keys($this->plugin->get_country_list());
$new_input['geo_challenge_countries'] = array_values(array_intersect($countries, $all_country_codes));
} else {
$new_input['geo_challenge_countries'] = [];
}
if (isset($input['login_restrict_countries'])) {
$countries = (array) $input['login_restrict_countries'];
$all_country_codes = array_keys($this->plugin->get_country_list());
$new_input['login_restrict_countries'] = array_values(array_intersect($countries, $all_country_codes));
} else {
$new_input['login_restrict_countries'] = [];
}
if (isset($input['recaptcha_score_threshold'])) {
$new_input['recaptcha_score_threshold'] = $this->plugin->sanitize_score_threshold($input['recaptcha_score_threshold']);
}
// Purge page caches when security settings are updated
$this->plugin->purge_all_page_caches();
return $new_input;
}
public function text_field_callback($args){
$value = $this->plugin->options[$args['name']] ?? $args['default'] ?? '';
$class = $args['class'] ?? '';
$data_attr = ! empty( $args['data_provider'] ) ? 'data-provider="' . esc_attr( $args['data_provider'] ) . '"' : '';
if ( (isset($args['name']) && substr($args['name'], -8) === '_api_key') || !empty($args['data_provider']) ) {
printf(
'
',
esc_attr( $args['name'] ),
esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ),
esc_attr( $value ),
esc_attr( $class ),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$data_attr,
esc_attr( $args['data_provider'] ),
esc_html__( 'Verify', 'advanced-ip-blocker' )
);
} else {
$is_numeric = false;
if (isset($args['name']) && is_string($args['name'])) {
$numeric_keywords = ['duration', 'threshold', 'retention', 'score', 'points', 'frequency', 'limit', 'window', 'expiration', 'ttl'];
foreach ($numeric_keywords as $keyword) {
if (strpos($args['name'], $keyword) !== false) {
$is_numeric = true;
break;
}
}
}
$type = $is_numeric ? 'number' : 'text';
$min_attr = ( 'number' === $type ) ? 'min="0"' : '';
printf(
'',
esc_attr($type),
esc_attr($args['name']),
esc_attr('advaipbl_settings[' . $args['name'] . ']'),
esc_attr($value),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$min_attr,
esc_attr($class)
);
}
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->get_help_link_html($args);
if ( isset($args['description']) ) {
echo '
' . wp_kses_post($args['description']) . '
'; } } public function checkbox_field_callback($args){ $checked = checked( '1', $this->plugin->options[$args['name']] ?? '0', false ); $id_attr = isset($args['id']) ? 'id="' . esc_attr($args['id']) . '"' : ''; // Generamos el HTML del checkbox y su label $html = sprintf( '', esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ), $checked, $id_attr, esc_html( $args['label'] ) ); // Añadimos el icono de ayuda al final del label $html .= $this->get_help_link_html($args); // Imprimimos una sola vez // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $html; // Imprimimos la descripción si existe if ( ! empty( $args['description'] ) ) { echo '' . wp_kses_post( $args['description'] ) . '
'; } } /** * Muestra un campo de tipo interruptor (toggle/switch) para los ajustes. * Utiliza la estructura HTML necesaria para ser estilizado con CSS. */ public function switch_field_callback($args){ $default = $args['default'] ?? '0'; $value = $this->plugin->options[$args['name']] ?? $default; $id_attr = isset($args['id']) ? 'id="' . esc_attr($args['id']) . '"' : 'advaipbl_switch_' . esc_attr($args['name']); $html = sprintf( ' ', esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ), esc_attr( $id_attr ), esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ), esc_attr( $id_attr ), checked( '1', $value, false ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $html; if ( ! empty( $args['description'] ) ) { echo '' . wp_kses_post( $args['description'] ) . '
'; } elseif ( ! empty( $args['label'] ) ) { echo ''; } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); } public function textarea_field_callback($args){ $value = $this->plugin->options[$args['name']] ?? ''; $rows = $args['rows'] ?? 5; $class = $args['class'] ?? 'large-text'; // 1. Imprimir Textarea printf( '', esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ), esc_attr( $rows ), esc_textarea( $value ), esc_attr( $class ) ); // 2. Imprimir Icono de Ayuda (si hay URL) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); // 3. Imprimir Descripción (o Label si no hay descripción explícita en este contexto) if ( isset($args['description']) ) { echo '' . wp_kses_post($args['description']) . '
'; } elseif (isset($args['label'])) { echo '' . esc_html($args['label']) . '
'; } } public function email_field_callback($args){ $value = $this->plugin->options[$args['name']] ?? ''; printf( '', esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ), esc_attr( $value ), esc_attr( get_option('admin_email') ) ); if ( isset($args['label']) ) { printf( '%s
', esc_html($args['label']) ); } } public function select_field_callback($args){ $name = $args['name']; $options_list = $args['options'] ?? []; $default_val = $args['default'] ?? ''; $value = $this->plugin->options[$name] ?? $default_val; echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); if ( isset($args['label']) ) { printf( '%s
', wp_kses_post($args['label']) ); } } public function timezone_select_callback() { $name_attr = 'advaipbl_settings[log_timezone]'; $current_timezone = $this->plugin->options['log_timezone'] ?? wp_timezone_string(); echo ''; echo '' . esc_html__('Select the timezone to display in the logs.', 'advanced-ip-blocker') . '
'; } public function notification_frequency_callback() { $value = $this->plugin->options['notification_frequency'] ?? 'disabled'; $frequencies = [ 'disabled' => __('Disabled', 'advanced-ip-blocker'), 'instant' => __('Instant', 'advanced-ip-blocker'), 'daily' => __('Daily Summary', 'advanced-ip-blocker'), 'weekly' => __('Weekly Summary', 'advanced-ip-blocker') ]; echo ''; echo '' . esc_html__('Choose how often you want to receive alert emails.', 'advanced-ip-blocker') . '
'; } public function signature_notification_frequency_callback() { $value = $this->plugin->options['signature_notification_frequency'] ?? 'instant'; $frequencies = [ 'instant' => __('Instant (Batch per hour)', 'advanced-ip-blocker'), 'daily' => __('Daily Digest', 'advanced-ip-blocker'), 'weekly' => __('Weekly Digest', 'advanced-ip-blocker'), 'disabled' => __('Disabled', 'advanced-ip-blocker') ]; echo ''; echo '' . esc_html__('Instant mode sends one email per detection cycle (hourly). Digests accumulate signatures.', 'advanced-ip-blocker') . '
'; } public function signature_notification_recipient_callback() { $value = $this->plugin->options['signature_notification_recipient'] ?? 'default'; $recipients = [ 'default' => __('Default (Use Plugin Recipient)', 'advanced-ip-blocker'), 'admin' => __('Administrator Email', 'advanced-ip-blocker'), 'custom' => __('Custom Email', 'advanced-ip-blocker') ]; echo ''; } public function scan_frequency_callback() { $value = $this->plugin->options['scan_frequency'] ?? 'weekly'; $frequencies = [ 'daily' => __('Daily', 'advanced-ip-blocker'), 'weekly' => __('Weekly', 'advanced-ip-blocker') ]; echo ''; echo '' . esc_html__('How often to run the automated security audit.', 'advanced-ip-blocker') . '
'; } public function send_test_scan_button_callback() { $nonce_url = wp_nonce_url( admin_url('admin-post.php?action=advaipbl_run_manual_scan'), 'advaipbl_run_manual_scan_nonce' ); ?>aquí, pero es más limpio en el HTML. } /** * Muestra la tabla de campos numéricos para configurar los puntos de cada evento de amenaza. */ public function threat_scores_callback() { $events = [ 'score_404' => ['label' => __('404 Error', 'advanced-ip-blocker'), 'default' => 5], 'score_403' => ['label' => __('403 Error', 'advanced-ip-blocker'), 'default' => 10], 'score_login' => ['label' => __('Failed Login', 'advanced-ip-blocker'), 'default' => 15], 'score_user_agent' => ['label' => __('Blocked User-Agent', 'advanced-ip-blocker'), 'default' => 60], 'score_waf' => ['label' => __('WAF Rule Triggered', 'advanced-ip-blocker'), 'default' => 60], 'score_impersonation' => ['label' => __('Bot Impersonation', 'advanced-ip-blocker'), 'default' => 75], 'score_honeypot' => ['label' => __('Honeypot Accessed', 'advanced-ip-blocker'), 'default' => 100], 'score_asn' => ['label' => __('Blocked ASN (Spamhaus)', 'advanced-ip-blocker'), 'default' => 100], ]; ?>
' . esc_html__( 'WARNING: This is a highly restrictive feature. Only enable it if you have a static IP address and public user registration is disabled on your site.', 'advanced-ip-blocker' ) . '
'; // Si la IP del admin no está en la whitelist, mostramos un aviso y un botón para añadirla if ( ! $is_whitelisted ) { echo ''; /* translators: %s: The admin's current IP address. */ echo '' . sprintf( esc_html__( 'Your current IP address (%s) is NOT whitelisted.', 'advanced-ip-blocker' ), esc_html( $client_ip ) ) . ' ' . esc_html__( 'You MUST add it to the whitelist before enabling this feature, or you will be locked out.', 'advanced-ip-blocker' ); echo ''; echo '
' . esc_html__('Get a Free API Key below to connect your site to the AIB Cloud Network.', 'advanced-ip-blocker') . '
'; } else { echo ''; echo ''; echo ''; echo '
'; echo '' . wp_kses_post($args['description']) . '
'; } else if (!empty($value)) { echo '' . esc_html__('Your API key is hidden for security.', 'advanced-ip-blocker') . '
'; } // Script para manejar la edición y la validación ?> para el modo de protección XML-RPC. */ public function xmlrpc_protection_mode_callback() { $current_mode = $this->plugin->options['xmlrpc_protection_mode'] ?? 'smart'; // 'smart' es el nuevo valor por defecto $modes = [ 'enabled' => __('Enabled (Not Recommended)', 'advanced-ip-blocker'), 'smart' => __('Smart Protection (Recommended)', 'advanced-ip-blocker'), 'disabled' => __('Completely Disabled', 'advanced-ip-blocker'), ]; ?>
-
-
' . esc_html__( 'Warning:', 'advanced-ip-blocker' ) . ' ' . esc_html__( 'Blocking countries can prevent legitimate users and services (like payment gateways) from accessing your site. Use with caution.', 'advanced-ip-blocker' ) . '
'; } /** * Muestra el campo de selección múltiple para los países, reutilizable para Geoblocking y Geo-Challenge. * @param array $args Argumentos pasados desde add_settings_field. */ public function geoblock_countries_callback($args) { $type = $args['type'] ?? 'geoblock'; // Por defecto es geoblock para retrocompatibilidad if ($type === 'geo_challenge') { $option_name = 'geo_challenge_countries'; $placeholder_text = __('Search for a country to challenge...', 'advanced-ip-blocker'); } elseif ($type === 'login_restrict') { $option_name = 'login_restrict_countries'; $placeholder_text = __('Search for an allowed country...', 'advanced-ip-blocker'); } else { $option_name = 'geoblock_countries'; $placeholder_text = __('Search for a country to block...', 'advanced-ip-blocker'); } $select_id = 'advaipbl_' . $option_name; $selected_countries = $this->plugin->options[$option_name] ?? []; $all_countries = $this->plugin->get_country_list(); ?>
plugin->options['enable_fim'])) { echo '
' . esc_html__('Enable the File Integrity Monitor to run scans.', 'advanced-ip-blocker') . '
'; return; } $nonce = wp_create_nonce('advaipbl_run_fim_scan_nonce'); ?>plugin->options['geolocation_method'] ?? 'api'; ?> plugin->geoip_manager instanceof ADVAIPBL_GeoIP_Manager ) { echo '
' . esc_html__('This status is only available when the "Local Database" method is selected and active.', 'advanced-ip-blocker') . '
'; return; } $status = $this->plugin->geoip_manager->get_database_status(); ?>: ()
: ()
: ()
get_help_link_html($args); ?>
plugin->options['recaptcha_version'] ?? 'v3'; ?> plugin->options['recaptcha_site_key'] ?? ''; ?> plugin->options['recaptcha_secret_key'] ?? ''; ?> plugin->options['recaptcha_score_threshold'] ?? '0.5'; ?>' . wp_kses_post( $args['description'] ) . '
'; } // Icono de ayuda // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->get_help_link_html($args); } /** * Muestra el campo de selección para la acción de AbuseIPDB. */ public function abuseipdb_action_callback() { $options = $this->plugin->options; $current_action = $options['abuseipdb_action'] ?? 'block'; ?> plugin->options[$name] ?? 'managed'; printf(''; if ( ! empty( $args['description'] ) ) { echo '' . wp_kses_post( $args['description'] ) . '
'; } } /** * Helper para generar el icono de ayuda si existe una URL. * * @param array $args Argumentos del campo. * @return string HTML del enlace de ayuda o cadena vacía. */ private function get_help_link_html($args) { if ( empty( $args['help_url'] ) ) { return ''; } return sprintf( ' ', esc_url( $args['help_url'] ), esc_attr__( 'Read Documentation', 'advanced-ip-blocker' ) ); } /** * Callback for visual separator. */ public function separator_callback() { echo '