plugin = $plugin_instance;
}
public function settings_page_content() {
if (!current_user_can('manage_options')) {
return;
}
// 1. DEFINIR LA ESTRUCTURA COMPLETA DEL MENÚ
$menu_structure = [
'dashboard' => [ 'title' => __('Dashboard', 'advanced-ip-blocker'), 'icon' => 'dashicons-dashboard', 'sub_tabs' => [ 'main_dashboard' => __('Security Dashboard', 'advanced-ip-blocker'), 'status' => __('System Status', 'advanced-ip-blocker') ] ],
'settings' => [ 'title' => __('Settings', 'advanced-ip-blocker'), 'icon' => 'dashicons-admin-settings', 'sub_tabs' => [ 'general_settings' => __('General', 'advanced-ip-blocker'), '2fa_management' => __('2FA Management', 'advanced-ip-blocker'), 'import_export' => __('Import / Export', 'advanced-ip-blocker') ] ],
'rules' => [ 'title' => __('Blocking Rules', 'advanced-ip-blocker'), 'icon' => 'dashicons-shield-alt', 'sub_tabs' => [ 'waf' => __('Firewall (WAF)', 'advanced-ip-blocker'), 'user_agents' => __('User Agents', 'advanced-ip-blocker'), 'honeypot' => __('Honeypot URLs', 'advanced-ip-blocker'), 'asn_blocking' => __('ASN Blocking', 'advanced-ip-blocker') ] ],
'ip_management' => [
'title' => __('IP Management', 'advanced-ip-blocker'),
'icon' => 'dashicons-location',
'sub_tabs' => [
'blocked_ips' => __('Blocked IPs', 'advanced-ip-blocker'),
'blocked_signatures' => __('Blocked Signatures', 'advanced-ip-blocker'),
'blocked_endpoints' => __('Blocked Endpoints', 'advanced-ip-blocker'),
'whitelist' => __('Whitelist', 'advanced-ip-blocker')
]
],
'logs' => [ 'title' => __('Logs & Sessions', 'advanced-ip-blocker'), 'icon' => 'dashicons-list-view', 'sub_tabs' => [ 'security_log' => __('Security Log', 'advanced-ip-blocker'), 'general_log' => __('General Log', 'advanced-ip-blocker'), 'ip_trust_log' => __('IP Trust Log', 'advanced-ip-blocker'), 'user_sessions' => __('User Sessions', 'advanced-ip-blocker'), 'cron_logs' => __('WP-Cron Log', 'advanced-ip-blocker') ] ],
'about' => [ 'title' => __('About', 'advanced-ip-blocker'), 'icon' => 'dashicons-info', 'sub_tabs' => [ 'credits' => __('Credits & Support', 'advanced-ip-blocker') ] ]
];
$current_page_slug = isset($_GET['page']) ? sanitize_key($_GET['page']) : 'advaipbl_settings_page';
// Primero, verificamos si la navegación es interna (clic en una pestaña/sub-pestaña)
if (isset($_GET['tab'])) {
$active_main_tab = sanitize_key($_GET['tab']);
$active_sub_tab = isset($_GET['sub-tab']) ? sanitize_key($_GET['sub-tab']) : null;
} else {
// Si no, es una navegación desde el menú de la izquierda.
// Mapeamos el slug de la página a la pestaña correcta.
$page_slug_to_tab_map = [
'advaipbl_settings_page' => ['dashboard', 'main_dashboard'],
'advaipbl_settings_page-settings' => ['settings', 'general_settings'],
'advaipbl_settings_page-rules' => ['rules', 'waf'],
'advaipbl_settings_page-ip-management' => ['ip_management', 'blocked_ips'],
'advaipbl_settings_page-logs' => ['logs', 'security_log'],
'advaipbl_settings_page-about' => ['about', 'credits'],
];
if (isset($page_slug_to_tab_map[$current_page_slug])) {
list($active_main_tab, $active_sub_tab) = $page_slug_to_tab_map[$current_page_slug];
} else {
// Fallback por si acaso
$active_main_tab = 'dashboard';
$active_sub_tab = 'main_dashboard';
}
}
// Validación final para asegurarse de que las pestañas existen
if (!isset($menu_structure[$active_main_tab])) {
$active_main_tab = 'dashboard';
}
if (empty($active_sub_tab) || !isset($menu_structure[$active_main_tab]['sub_tabs'][$active_sub_tab])) {
// Asigna la primera sub-pestaña de la pestaña principal activa
$active_sub_tab = key($menu_structure[$active_main_tab]['sub_tabs']);
}
$blocked_count = $this->plugin->get_blocked_count();
?>
plugin->display_admin_notice();
?>
$main_tab_data) :
$is_active = ($main_tab_key === $active_main_tab);
$first_sub_tab = key($main_tab_data['sub_tabs']);
// La URL para los enlaces de las pestañas SÍ debe construirse con add_query_arg
$url = add_query_arg(
[
'page' => 'advaipbl_settings_page',
'tab' => $main_tab_key,
'sub-tab' => $first_sub_tab
],
'admin.php'
);
?>
0) : ?>
$sub_tab_title) :
$is_active = ($sub_tab_key === $active_sub_tab);
$url = add_query_arg(
[
'page' => 'advaipbl_settings_page',
'tab' => $active_main_tab,
'sub-tab' => $sub_tab_key
],
'admin.php'
);
?>
display_dashboard_tab(); break;
case 'status': $this->display_status_tab(); break;
case 'general_settings': $this->display_general_settings_tab(); break;
case '2fa_management': $this->display_2fa_management_tab(); break;
case 'import_export': $this->render_import_export_controls_callback(); break;
case 'waf': $this->display_waf_tab(); break;
case 'user_agents': $this->display_user_agents_tab(); break;
case 'honeypot': $this->display_honeypot_tab(); break;
case 'asn_blocking': $this->display_asn_blocking_tab(); break;
case 'blocked_ips': $this->display_blocked_ips_tab(); break;
case 'blocked_signatures': $this->display_blocked_signatures_tab(); break;
case 'blocked_endpoints': $this->display_blocked_endpoints_tab(); break;
case 'whitelist': $this->display_whitelist_tab(); break;
case 'security_log': $this->display_security_log_tab(); break;
case 'general_log': $this->display_general_log_tab(); break;
case 'ip_trust_log': $this->display_ip_trust_log_tab(); break;
case 'user_sessions': $this->plugin->session_manager->display_admin_page(); break;
case 'cron_logs': $this->display_cron_logs_tab(); break;
case 'credits': $this->display_credits_tab(); break;
default: echo '
Error: Content for this tab is not available.
'; break;
}
?>
';
esc_html_e( 'This log shows which IP addresses are triggering WP-Cron tasks on your site, and which scheduled tasks (hooks) were due to run at that moment.', 'advanced-ip-blocker' );
echo '
';
$search_term = isset($_GET['s']) ? sanitize_text_field(wp_unslash($_GET['s'])) : '';
$orderby = isset($_GET['orderby']) && in_array($_GET['orderby'], ['timestamp', 'ip'], true) ? sanitize_key($_GET['orderby']) : 'timestamp';
$order = isset($_GET['order']) && in_array(strtolower($_GET['order']), ['asc', 'desc'], true) ? strtolower(sanitize_key($_GET['order'])) : 'desc';
$current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
$per_page = isset($_GET['advaipbl_per_page']) ? absint($_GET['advaipbl_per_page']) : 25;
global $wpdb;
$table_name = $wpdb->prefix . 'advaipbl_logs';
$where_clauses = [$wpdb->prepare("log_type = %s", 'wp_cron')];
if (!empty($search_term)) {
$search_like = '%' . $wpdb->esc_like($search_term) . '%';
$where_clauses[] = $wpdb->prepare("(ip LIKE %s OR details LIKE %s)", $search_like, $search_like);
}
$where_sql = implode(' AND ', $where_clauses);
$total_items = $wpdb->get_var("SELECT COUNT(log_id) FROM $table_name WHERE $where_sql");
$total_pages = ceil($total_items / $per_page);
$offset = ($current_page - 1) * $per_page;
$logs = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name WHERE $where_sql ORDER BY " . esc_sql($orderby) . " " . esc_sql($order) . " LIMIT %d OFFSET %d", $per_page, $offset), ARRAY_A);
?>
add_query_arg([
'paged' => '%#%',
's' => $search_term,
'advaipbl_per_page' => $per_page,
]),
'format' => '',
'total' => $total_pages,
'current' => $current_page
]);
if ($page_links) echo wp_kses_post($page_links);
?>
plugin->print_log_sortable_header(__('Date/Time', 'advanced-ip-blocker'), 'timestamp', $orderby, $order); ?>
plugin->print_log_sortable_header(__('IP Address', 'advanced-ip-blocker'), 'ip', $orderby, $order); ?>
';
foreach ( $details['due_hooks'] as $hook ) {
echo '' . esc_html( $hook ) . ' ';
}
echo '';
} else {
echo '–';
}
?>
plugin->options['geolocation_provider'] ?? '';
$is_compatible = in_array($provider, ['ip-api.com', 'ipinfo.io'], true);
$is_spamhaus_enabled = !empty($this->plugin->options['enable_spamhaus_asn']);
$is_manual_enabled = !empty($this->plugin->options['enable_manual_asn']);
$settings_url = admin_url('admin.php?page=advaipbl_settings_page-settings');
$spamhaus_stats = $this->plugin->dashboard_manager->get_spamhaus_stats();
?>
Warning: Your current geolocation provider (%1$s ) does not support ASN lookups. This feature is fully supported by ip-api.com and ipinfo.io . Please change your provider to use ASN blocking.', 'advanced-ip-blocker'),
['strong' => [], 'a' => ['href' => []]]
),
esc_html($provider),
esc_url($settings_url)
); ?>
prefix . 'advaipbl_malicious_signatures';
$is_enabled = !empty($this->plugin->options['enable_signature_blocking']);
$settings_url = admin_url('admin.php?page=advaipbl_settings_page-settings&sub-tab=general_settings#section-signature_engine');
?>
%s',
$is_enabled ? 'enabled' : 'disabled',
$is_enabled ? esc_html__('Active', 'advanced-ip-blocker') : esc_html__('Inactive', 'advanced-ip-blocker')
);
printf(
wp_kses(
/* translators: 1: Status (Enabled/Disabled), 2: Link to settings page. */
__('The Attack Signature Blocking system is currently %1$s. You can change this in the Settings .', 'advanced-ip-blocker'),
[ 'span' => ['class' => true], 'a' => ['href' => []] ]
),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$status_tag,
esc_url($settings_url)
);
?>
get_var("SELECT COUNT(id) FROM {$table_name}");
$total_pages = ceil($total_items / $per_page);
$offset = ($current_page - 1) * $per_page;
$items = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$table_name} ORDER BY " . esc_sql($orderby) . " " . esc_sql($order) . " LIMIT %d OFFSET %d",
$per_page, $offset
), ARRAY_A);
?>
plugin->render_per_page_selector($per_page); ?>
add_query_arg('paged', '%#%'), 'format' => '', 'total' => $total_pages, 'current' => $current_page]); if ($page_links) echo wp_kses_post($page_links); ?>
plugin->print_log_sortable_header(__('Signature Hash', 'advanced-ip-blocker'), 'signature_hash', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Reason', 'advanced-ip-blocker'), 'reason', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Last Seen', 'advanced-ip-blocker'), 'last_seen', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Expires In', 'advanced-ip-blocker'), 'expires_at', $orderby, $order); ?>
prefix . 'advaipbl_endpoint_lockdowns';
// Array para definir los endpoints que soportan lockdown
$lockdown_endpoints = [
'xmlrpc' => [
'name' => 'XML-RPC',
'option' => 'enable_xmlrpc_lockdown',
'anchor' => '#sub-section-xmlrpc-lockdown'
],
'login' => [
'name' => 'Login Page (wp-login.php)',
'option' => 'enable_login_lockdown',
'anchor' => '#sub-section-login-lockdown'
],
];
$settings_base_url = admin_url('admin.php?page=advaipbl_settings_page-settings&sub-tab=general_settings');
$status_parts = [];
foreach ($lockdown_endpoints as $key => $details) {
$is_enabled = !empty($this->plugin->options[$details['option']]);
$status_tag = sprintf(
'%s ',
$is_enabled ? 'enabled' : 'disabled',
$is_enabled ? esc_html__('Active', 'advanced-ip-blocker') : esc_html__('Inactive', 'advanced-ip-blocker')
);
$settings_link = sprintf(
'%s ',
esc_url($settings_base_url . $details['anchor']),
esc_html__('Configure', 'advanced-ip-blocker')
);
/* translators: 1: Endpoint name (e.g., XML-RPC), 2: Status tag (Active/Inactive), 3: Link to configure */
$status_parts[] = sprintf('%1$s: %2$s (%3$s)', esc_html($details['name']), $status_tag, $settings_link);
}
?>
[],
'span' => ['class' => true],
'a' => ['href' => true],
]); ?>
query($wpdb->prepare("DELETE FROM {$table_name} WHERE expires_at <= %d", time()));
$items = $wpdb->get_results("SELECT * FROM {$table_name} ORDER BY created_at DESC", ARRAY_A);
?>
'advaipbl_delete_lockdown',
'lockdown_id' => $item['id']
]),
'advaipbl_delete_lockdown_' . $item['id']
);
?>
plugin->options['enable_waf']);
$settings_url = admin_url('admin.php?page=advaipbl_settings_page-settings&sub-tab=general_settings#sub-section-waf');
?>
%s',
$is_enabled ? 'enabled' : 'disabled',
$is_enabled ? esc_html__('Active', 'advanced-ip-blocker') : esc_html__('Inactive', 'advanced-ip-blocker')
);
printf(
wp_kses(
/* translators: 1: Status tag (Active/Inactive), 2: Link to settings page. */
__('Web Application Firewall (WAF) is currently %1$s. You can change this in the Settings .', 'advanced-ip-blocker'),
[
'span' => ['class' => true],
'a' => ['href' => []]
]
),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$status_tag,
esc_url($settings_url)
);
?>
plugin->options = get_option(ADVAIPBL_Main::OPTION_SETTINGS);
// Definimos la estructura del menú lateral y las secciones.
$sections = [
'general' => __('General', 'advanced-ip-blocker'),
'notifications' => __('Notifications', 'advanced-ip-blocker'),
'ip_detection' => __('IP Detection', 'advanced-ip-blocker'),
'geolocation' => __('Geolocation', 'advanced-ip-blocker'),
'protections' => __('Core Protections', 'advanced-ip-blocker'),
'blocking_rules' => __('Threshold Blocking', 'advanced-ip-blocker'),
'login_protection' => __('Login Protection', 'advanced-ip-blocker'),
'signature_engine' => __('Signature Engine', 'advanced-ip-blocker'),
'uninstall' => __('Uninstallation', 'advanced-ip-blocker'),
];
?>
X-Forwarded-For if the request comes from one of these IPs, preventing IP spoofing.', 'advanced-ip-blocker'); ?>
plugin->options['allow_telemetry'])) :
$telemetry_setting_id = 'advaipbl_allow_telemetry';
?>
Enable anonymous usage tracking.', 'advanced-ip-blocker'), ['a' => ['href' => []]]), '#' . esc_attr($telemetry_setting_id)); ?>
plugin->options['enable_2fa']);
$settings_url = admin_url('admin.php?page=advaipbl_settings_page-settings&sub-tab=general_settings#sub-section-2FA');
$profile_url = admin_url('profile.php');
?>
%s',
$is_enabled ? 'enabled' : 'disabled',
$is_enabled ? esc_html__('Active', 'advanced-ip-blocker') : esc_html__('Inactive', 'advanced-ip-blocker')
);
printf(
wp_kses(
/* translators: %1$s: Status tag (Active/Inactive), %2$s: Link to Settings, %3$s: Link to Profile. */
__('Two-Factor Authentication (2FA) is currently %1$s. You can change this in the Settings . When enabled, users will see the 2FA setup section in their Profile .', 'advanced-ip-blocker'),
[
'span' => ['class' => true],
'a' => ['href' => true],
]
),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$status_tag,
esc_url($settings_url),
esc_url($profile_url)
);
?>
process_bulk_action();
$users_list_table->prepare_items();
?>
views(); ?>
search_box( __( 'Search Users', 'advanced-ip-blocker' ), 'user' );
$users_list_table->display();
?>
plugin->options['enable_user_agent_blocking']);
$settings_url = admin_url('admin.php?page=advaipbl_settings_page-settings&sub-tab=general_settings#sub-section-user-agent');
?>
%s',
$is_enabled ? 'enabled' : 'disabled',
$is_enabled ? esc_html__('Active', 'advanced-ip-blocker') : esc_html__('Inactive', 'advanced-ip-blocker')
);
printf(
wp_kses(
/* translators: 1: Status tag (Active/Inactive), 2: Link to settings page. */
__('User-Agent Protection is currently %1$s. You can change this in the Settings .', 'advanced-ip-blocker'),
[
'span' => ['class' => true],
'a' => ['href' => []]
]
),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$status_tag,
esc_url($settings_url)
);
?>
plugin->options['enable_honeypot_blocking']);
$settings_url = admin_url('admin.php?page=advaipbl_settings_page-settings&sub-tab=general_settings#sub-section-honeypot');
?>
%s',
$is_enabled ? 'enabled' : 'disabled',
$is_enabled ? esc_html__('Active', 'advanced-ip-blocker') : esc_html__('Inactive', 'advanced-ip-blocker')
);
printf(
wp_kses(
/* translators: 1: Status tag (Active/Inactive), 2: Link to settings page. */
__('Honeypot Protection is currently %1$s. You can change this in the Settings .', 'advanced-ip-blocker'),
[
'span' => ['class' => true],
'a' => ['href' => []]
]
),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$status_tag,
esc_url($settings_url)
);
?>
/blog/ or /contact/). Use attack-specific patterns.', 'advanced-ip-blocker') ); ?>
prefix . 'advaipbl_blocked_ips';
$filter_type = isset($_GET['filter_type']) ? sanitize_key($_GET['filter_type']) : 'all';
$orderby = isset($_GET['orderby']) && in_array($_GET['orderby'], ['ip_range', 'block_type', 'timestamp'], true) ? sanitize_key($_GET['orderby']) : 'timestamp';
$order = isset($_GET['order']) && in_array(strtolower($_GET['order']), ['asc', 'desc'], true) ? strtolower(sanitize_key($_GET['order'])) : 'desc';
$current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
$per_page = isset($_GET['advaipbl_per_page']) ? absint($_GET['advaipbl_per_page']) : 20;
$offset = ($current_page - 1) * $per_page;
$where_clauses = [];
if ('all' !== $filter_type) {
$where_clauses[] = $wpdb->prepare("block_type = %s", $filter_type);
}
$where_sql = !empty($where_clauses) ? 'WHERE ' . implode(' AND ', $where_clauses) : '';
$total_items = $wpdb->get_var("SELECT COUNT(id) FROM {$table_name} {$where_sql}");
$total_pages = ceil($total_items / $per_page);
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$items_for_page = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$table_name} {$where_sql} ORDER BY " . esc_sql($orderby) . " " . esc_sql($order) . " LIMIT %d OFFSET %d", $per_page, $offset), ARRAY_A);
$ips_and_ranges_on_page = wp_list_pluck($items_for_page, 'ip_range');
$single_ips_on_page = array_filter($ips_and_ranges_on_page, function($entry) { return filter_var($entry, FILTER_VALIDATE_IP); });
$locations = !empty($single_ips_on_page) ? $this->plugin->session_manager->get_cached_locations($single_ips_on_page) : [];
$definitions = $this->plugin->get_all_block_type_definitions();
?>
plugin->render_per_page_selector($per_page); ?>
>
$def) : if(empty($def['option_key']) && $type !== 'manual') continue; ?>
>
add_query_arg(['paged' => '%#%', 'filter_type' => $filter_type, 'advaipbl_per_page' => $per_page]), 'format' => '', 'total' => $total_pages, 'current' => $current_page]); if ($page_links) echo wp_kses_post($page_links); ?>
plugin->print_sortable_header(__('IP', 'advanced-ip-blocker'), 'ip_range', $orderby, $order); ?>
plugin->print_sortable_header(__('Block Type', 'advanced-ip-blocker'), 'block_type', $orderby, $order); ?>
plugin->print_sortable_header(__('Since', 'advanced-ip-blocker'), 'timestamp', $orderby, $order); ?>
plugin->options[$duration_key] ?? 1440);
if ($duration_minutes <= 0) {
esc_html_e('Permanent', 'advanced-ip-blocker');
} else {
printf( /* translators: %d: The number of minutes for a block duration. */
esc_html__('%d minutes', 'advanced-ip-blocker'),
absint($duration_minutes)
);
}
} else {
esc_html_e('Permanent', 'advanced-ip-blocker');
}
?>
' . esc_html__( 'View Map', 'advanced-ip-blocker' ) . ' ';
}
} else {
esc_html_e( 'Not available', 'advanced-ip-blocker' );
}
?>
'advaipbl_unblock_ip', 'ip' => $block['ip_range']]),
'advaipbl_unblock_ip'
);
?>
$data) {
if ( is_array($data) && isset($data['timestamp']) ) {
$table_data[] = [ 'ip' => $ip, 'timestamp' => $data['timestamp'], 'detail' => $data['detail'] ?? '' ];
} elseif ( is_numeric($data) ) {
$table_data[] = [ 'ip' => $ip, 'timestamp' => $data, 'detail' => __('Migrated from old format', 'advanced-ip-blocker') ];
}
}
}
$sortable_columns = ['ip', 'timestamp', 'detail'];
$orderby = isset($_GET['orderby']) && in_array($_GET['orderby'], $sortable_columns, true) ? sanitize_key($_GET['orderby']) : 'timestamp';
$order = isset($_GET['order']) && in_array(strtolower($_GET['order']), ['asc', 'desc'], true) ? strtolower(sanitize_key($_GET['order'])) : 'desc';
usort($table_data, function($a, $b) use ($orderby, $order) {
$a_val = $a[$orderby] ?? ''; $b_val = $b[$orderby] ?? '';
if ($a_val == $b_val) return 0;
return ($order === 'asc') ? strnatcasecmp((string)$a_val, (string)$b_val) : strnatcasecmp((string)$b_val, (string)$a_val);
});
$current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
$per_page = isset($_GET['advaipbl_per_page']) ? absint($_GET['advaipbl_per_page']) : 20;
$total_items = count($table_data);
$total_pages = ceil($total_items / $per_page);
$items_for_page = array_slice($table_data, ($current_page - 1) * $per_page, $per_page);
$ips_on_page = wp_list_pluck($items_for_page, 'ip');
$locations = $this->plugin->session_manager->get_cached_locations($ips_on_page);
?>
plugin->render_per_page_selector($per_page); ?>
add_query_arg('paged', '%#%'), 'format' => '', 'total' => $total_pages, 'current' => $current_page]); if ($page_links) echo wp_kses_post($page_links); ?>
plugin->print_log_sortable_header(__('IP / Location', 'advanced-ip-blocker'), 'ip', $orderby, $order); ?>
plugin->print_log_sortable_header(__('User', 'advanced-ip-blocker'), 'user', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Details', 'advanced-ip-blocker'), 'detail', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Added Since', 'advanced-ip-blocker'), 'timestamp', $orderby, $order); ?>
' . esc_html(implode(', ', $location_parts)) . ' ';
}
?>
' . esc_html($matches[1]) . '';
echo '' . esc_html($matches[2]) . ' ';
}
?>
0 ? esc_html(ADVAIPBL_Main::get_formatted_datetime($item['timestamp'])) : '...'; ?>
display_log_table_generic($security_log_types, ['critical', 'warning']);
}
/**
* Muestra la pestaña de logs generales (auditoría), restaurada a su formato original.
*/
public function display_general_log_tab() {
if (empty($this->plugin->options['enable_logging'])) {
echo '' . esc_html__('General event logging is disabled in the "Settings" tab.', 'advanced-ip-blocker') . '
';
return;
}
$search_term = isset($_GET['s']) ? sanitize_text_field(wp_unslash($_GET['s'])) : '';
$orderby = isset($_GET['orderby']) && in_array($orderby, ['timestamp', 'level', 'ip', 'message'], true) ? sanitize_key($_GET['orderby']) : 'timestamp';
$order = isset($_GET['order']) && in_array(strtolower($_GET['order']), ['asc', 'desc'], true) ? strtolower(sanitize_key($_GET['order'])) : 'desc';
$current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
$per_page = isset($_GET['advaipbl_per_page']) ? absint($_GET['advaipbl_per_page']) : 25;
global $wpdb;
$table_name = $wpdb->prefix . 'advaipbl_logs';
$where_clauses = [$wpdb->prepare("log_type = %s", 'general')];
if (!empty($search_term)) {
$search_like = '%' . $wpdb->esc_like($search_term) . '%';
$where_clauses[] = $wpdb->prepare("(ip LIKE %s OR message LIKE %s)", $search_like, $search_like);
}
$where_sql = implode(' AND ', $where_clauses);
$total_items = $wpdb->get_var("SELECT COUNT(log_id) FROM $table_name WHERE $where_sql");
$total_pages = ceil($total_items / $per_page);
$offset = ($current_page - 1) * $per_page;
$logs = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name WHERE $where_sql ORDER BY " . esc_sql($orderby) . " " . esc_sql($order) . " LIMIT %d OFFSET %d", $per_page, $offset), ARRAY_A);
?>
plugin->print_log_sortable_header(__('Date/Time', 'advanced-ip-blocker'), 'timestamp', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Level', 'advanced-ip-blocker'), 'level', $orderby, $order); ?>
plugin->print_log_sortable_header(__('IP', 'advanced-ip-blocker'), 'ip', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Message', 'advanced-ip-blocker'), 'message', $orderby, $order); ?>
prefix . 'advaipbl_ip_scores';
$is_enabled = !empty($this->plugin->options['enable_threat_scoring']);
$settings_url = admin_url('admin.php?page=advaipbl_settings_page-settings&sub-tab=general_settings#section-ip_trust');
?>
%s',
$is_enabled ? 'enabled' : 'disabled',
$is_enabled ? esc_html__('Active', 'advanced-ip-blocker') : esc_html__('Inactive', 'advanced-ip-blocker')
);
printf(
wp_kses(
/* translators: 1: Status tag (Active/Inactive), 2: Link to settings page. */
__('The Threat Scoring System is currently %1$s. You can change this in the Settings .', 'advanced-ip-blocker'),
[ 'span' => ['class' => true], 'a' => ['href' => []] ]
),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$status_tag,
esc_url($settings_url)
);
?>
0"];
if (!empty($search_term)) {
$where_clauses[] = $wpdb->prepare("ip LIKE %s", '%' . $wpdb->esc_like($search_term) . '%');
}
$where_sql = implode(' AND ', $where_clauses);
$total_items = $wpdb->get_var("SELECT COUNT(id) FROM {$table_name} WHERE {$where_sql}");
$total_pages = ceil($total_items / $per_page);
$offset = ($current_page - 1) * $per_page;
$items = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$table_name} WHERE {$where_sql} ORDER BY " . esc_sql($orderby) . " " . esc_sql($order) . " LIMIT %d OFFSET %d",
$per_page, $offset
), ARRAY_A);
$ips_on_page = wp_list_pluck($items, 'ip');
$locations = $this->plugin->session_manager->get_cached_locations($ips_on_page);
$threshold = (int) ($this->plugin->options['threat_score_threshold'] ?? 100);
?>
plugin->print_log_sortable_header(__('IP / Location', 'advanced-ip-blocker'), 'ip', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Current Score', 'advanced-ip-blocker'), 'score', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Last Activity', 'advanced-ip-blocker'), 'last_event_timestamp', $orderby, $order); ?>
' . esc_html(trim("$city, $country", ', ')) . ' ';
} ?>
0 ? min(100, ($item['score'] / $threshold) * 100) : 100;
$progress_color = $score_percentage > 80 ? '#dc3232' : ($score_percentage > 50 ? '#f59e0b' : '#0073aa');
?>
' . esc_html(ucfirst(str_replace('_', ' ', $last_event['event']))) . '';
echo ' (+ ' . esc_html($last_event['points']) . ' ' . esc_html__('points', 'advanced-ip-blocker') . ')';
}
?>
__('General System Event Log', 'advanced-ip-blocker'), 'wp_cron' => __('WP-Cron Execution Log', 'advanced-ip-blocker'), ];
$title = $titles[$log_types] ?? ucfirst($log_types) . ' Log';
$current_sub_tab = ($log_types === 'general') ? 'general_log' : $log_types . '_logs';
}
$search_term = isset($_GET['s']) ? sanitize_text_field(wp_unslash($_GET['s'])) : '';
$orderby = isset($_GET['orderby']) && in_array($orderby, ['timestamp', 'ip', 'log_type', 'message'], true) ? sanitize_key($_GET['orderby']) : 'timestamp';
$order = isset($_GET['order']) && in_array(strtolower($_GET['order']), ['asc', 'desc'], true) ? strtolower(sanitize_key($_GET['order'])) : 'desc';
$current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
$per_page = isset($_GET['advaipbl_per_page']) ? absint($_GET['advaipbl_per_page']) : 20;
global $wpdb;
$table_name = $wpdb->prefix . 'advaipbl_logs';
$where_clauses = [];
$level_placeholders = implode(', ', array_fill(0, count($levels_to_show), '%s'));
$where_clauses[] = $wpdb->prepare("level IN ({$level_placeholders})", $levels_to_show);
if ($is_unified_log) {
$types_to_query = ($current_filter !== 'all' && in_array($current_filter, $log_types)) ? [$current_filter] : $log_types;
if (!empty($types_to_query)) {
$placeholders = implode(', ', array_fill(0, count($types_to_query), '%s'));
$where_clauses[] = $wpdb->prepare("log_type IN ({$placeholders})", $types_to_query);
}
} else {
$where_clauses[] = $wpdb->prepare("log_type = %s", $log_types);
}
if (!empty($search_term)) {
$search_like = '%' . $wpdb->esc_like($search_term) . '%';
$where_clauses[] = $wpdb->prepare("(ip LIKE %s OR details LIKE %s OR message LIKE %s)", $search_like, $search_like, $search_like);
}
$where_sql = implode(' AND ', $where_clauses);
$total_items = $wpdb->get_var("SELECT COUNT(log_id) FROM $table_name WHERE $where_sql");
$total_pages = ceil($total_items / $per_page);
$offset = ($current_page - 1) * $per_page;
$logs = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name WHERE $where_sql ORDER BY " . esc_sql($orderby) . " " . esc_sql($order) . " LIMIT %d OFFSET %d", $per_page, $offset), ARRAY_A);
?>
plugin->print_log_sortable_header(__('Date/Time', 'advanced-ip-blocker'), 'timestamp', $orderby, $order); ?>
plugin->print_log_sortable_header(__('IP', 'advanced-ip-blocker'), 'ip', $orderby, $order); ?>
plugin->print_log_sortable_header(__('Type', 'advanced-ip-blocker'), 'log_type', $orderby, $order); ?>
plugin->options['duration_' . $log_type])) {
$duration_minutes = (int) $this->plugin->options['duration_' . $log_type];
}
$duration_text = '';
if ($log_type === 'manual' || $duration_minutes <= 0) {
$duration_text = __('Permanent', 'advanced-ip-blocker');
} else {
/* translators: %d: The number of minutes for a block duration. */
$duration_text = sprintf(esc_html__('%d min', 'advanced-ip-blocker'), $duration_minutes);
}
echo '' . esc_html__('Blocked:', 'advanced-ip-blocker') . ' ' . esc_html($duration_text);
}
?>
' . implode(', ', $location_parts) . ' ';
}
?>
plugin->get_all_block_type_definitions()[$log_type]['label'] ?? ucwords(str_replace('_', ' ', $log_type))); ?>
' . esc_html__('User:', 'advanced-ip-blocker') . ' ' . esc_html($details['username'] ?? 'N/A');
break;
case 'waf':
$detail_display = '' . esc_html__('Rule:', 'advanced-ip-blocker') . ' ' . esc_html($details['rule'] ?? 'N/A');
if (!empty($uri)) { $detail_display .= '' . $uri . ' '; }
break;
case 'asn':
$detail_display = esc_html($details['asn_number'] ?? 'N/A') . ' (' . esc_html($details['asn_name'] ?? '') . ')';
if (!empty($details['source'])) { $detail_display .= ' - ' . __('Source:', 'advanced-ip-blocker') . ' ' . esc_html($details['source']); }
if (!empty($uri)) { $detail_display .= '' . $uri . ' '; }
break;
case 'threat_score':
$detail_display = esc_html($entry['message']);
if (!empty($uri)) { $detail_display .= '' . $uri . ' '; }
break;
case 'geo_challenge':
$country_name = esc_html($details['country'] ?? 'N/A');
$detail_display = '' . esc_html__('Country:', 'advanced-ip-blocker') . ' ' . $country_name;
if (!empty($uri)) {
$detail_display .= '' . $uri . ' ';
}
break;
case 'signature_challenge':
$detail_display = esc_html($entry['message']);
if (!empty($uri)) { $detail_display .= '' . $uri . ' '; }
break;
case 'signature_flagged':
$hash = $details['signature_hash'] ?? 'N/A';
$short_hash = substr($hash, 0, 12) . '...';
$detail_display = '' . esc_html__('Signature:', 'advanced-ip-blocker') . ' ' . esc_html($short_hash) . '';
$detail_display .= '' . esc_html($entry['message']) . ' ';
break;
case '404':
case '403':
case 'honeypot':
default:
$detail_display = !empty($uri) ? $uri : esc_html($entry['message']);
break;
}
echo wp_kses_post($detail_display);
?>
Stripe
bc1qxfsmpqk0q7an82ckm7380pzpsea2sa294824lg
0xAF8CC1B71EAbF5dffDa2aF58AEF43b2559163284
# General Help
wp help advaipbl
# IP Management
wp advaipbl block <ip> [--reason=<reason>]
wp advaipbl unblock <ip>
wp advaipbl whitelist <add|remove|list> [<ip>]
# Threat Scoring & Signatures
wp advaipbl score <list|get|reset|decay-run> [--ip=<ip>]
wp advaipbl signature <list|delete|whitelist> [--hash=<hash>]
wp advaipbl signature-analyze
# Geolocation, ASN & WAF
wp advaipbl geoblock <add|remove|list> <country_code>
wp advaipbl asn <add|remove|list> <asn>
wp advaipbl asn-whitelist <add|remove|list> <asn>
wp advaipbl waf <add|remove|list> [<rule>] [--from-file=<file>]
# User & Session Management
wp advaipbl session <list|terminate> [--user-id=<id>]
wp advaipbl 2fa <status|reset> <user>
# System & Config
wp advaipbl log <list|clear> [--type=<type>] [--count=<number>]
wp advaipbl config <get|set> [<key>] [<value>]
wp advaipbl provider <list|set|set_key|remove_key>
wp advaipbl spamhaus-update
plugin->get_ip_intelligence();
$server_ip = $this->plugin->get_server_ip();
$client_ip = $ip_data['visitor_ip'] ?? 'N/A';
?>
plugin->get_remote_addr();
$client_ip = $this->plugin->get_client_ip();
if ( $remote_addr && $client_ip !== $remote_addr && filter_var( $remote_addr, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) ) {
echo '
';
/* translators: %1$s: Client's real IP. %2$s: Proxy/CDN IP. */
echo '' . esc_html__( 'Info:', 'advanced-ip-blocker' ) . ' ' . sprintf( esc_html__( 'It seems your site is behind a reverse proxy or CDN. Your IP is correctly detected as %1$s, while your server connects through %2$s. This is a normal and correct configuration.', 'advanced-ip-blocker' ), '' . esc_html( $client_ip ) . '', '' . esc_html( $remote_addr ) . '' );
echo '
';
$has_recommendations = true;
}
// Comprobación de la IP del servidor
if ( ! $this->plugin->get_server_ip() ) {
echo '
';
echo '' . esc_html__( 'Warning:', 'advanced-ip-blocker' ) . ' ' . esc_html__( 'The plugin could not automatically determine your server\'s public IP. The feature that adds the server IP to the whitelist on activation will not work. Please add your server IP to the whitelist manually to prevent any issues with geoblocking or other functionalities.', 'advanced-ip-blocker' );
echo '
';
$has_recommendations = true;
}
$xmlrpc_plugins = $this->plugin->get_xmlrpc_dependent_plugins();
if ( ! empty( $xmlrpc_plugins ) ) :
?>
';
echo '' . esc_html__( 'All Clear!', 'advanced-ip-blocker' ) . ' ' . esc_html__( 'No potential configuration issues were detected.', 'advanced-ip-blocker' );
echo '
';
}
?>
plugin->get_default_settings();
$numeric_fields = [
'duration_geoblock', 'duration_waf', 'duration_rate_limit', 'rate_limiting_limit', 'rate_limiting_window',
'duration_xmlrpc_block', 'duration_asn', 'log_retention_days', 'threshold_404', 'duration_404', 'transient_expiration_404',
'threshold_403', 'duration_403', 'transient_expiration_403', 'threshold_login',
'duration_login', 'transient_expiration_login', 'duration_honeypot', 'duration_user_agent',
'threat_score_threshold', 'duration_threat_score', 'score_404', 'score_403', 'score_login',
'score_user_agent', 'score_waf', 'score_honeypot', 'score_asn',
'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',
'geo_challenge_cookie_duration'
];
foreach ($numeric_fields as $field) {
// Si el campo existe en el input, lo actualizamos. Si no, el valor antiguo se mantiene.
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_geo_challenge'
];
foreach ($checkbox_fields as $field) {
// Para checkboxes, si existen en el input, es '1'. Si no, es '0'.
$new_input[$field] = (isset($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',
'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'
];
foreach ($text_fields as $field) {
if (isset($input[$field])) {
if (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 || strpos($field, 'message') !== false) {
$new_input[$field] = sanitize_textarea_field($input[$field]);
} else {
$new_input[$field] = sanitize_text_field($input[$field]);
}
}
}
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['recaptcha_score_threshold'])) {
$new_input['recaptcha_score_threshold'] = $this->plugin->sanitize_score_threshold($input['recaptcha_score_threshold']);
}
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']) && strpos($args['name'], 'api_key_') === 0 ) {
printf(
'
%7$s
',
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)
);
}
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']) . '"' : '';
$html = sprintf(
' %s ',
esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ),
$checked,
$id_attr,
esc_html( $args['label'] )
);
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
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){
$value = $this->plugin->options[$args['name']] ?? '0';
$id_attr = isset($args['id']) ? 'id="' . esc_attr($args['id']) . '"' : 'advaipbl_switch_' . esc_attr($args['name']);
// El input checkbox original se mantiene, pero se ocultará con CSS.
// La estructura de label + span es para crear el interruptor visual.
$html = sprintf(
'
',
esc_attr( $id_attr ),
esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ),
esc_attr( $id_attr ),
checked( '1', $value, false )
);
// Imprimimos el interruptor
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $html;
// Imprimimos la descripción si existe, que ahora actúa como el label visible.
if ( ! empty( $args['description'] ) ) {
echo '' . wp_kses_post( $args['description'] ) . '
';
} elseif ( ! empty( $args['label'] ) ) {
echo '' . esc_html($args['label']) . ' ';
}
}
public function textarea_field_callback($args){
$value = $this->plugin->options[$args['name']] ?? '';
$rows = $args['rows'] ?? 5;
// Hacemos la clase personalizable. Si no se especifica, usa 'large-text' por defecto.
$class = $args['class'] ?? 'large-text';
printf(
'%3$s ',
esc_attr( 'advaipbl_settings[' . $args['name'] . ']' ),
esc_attr( $rows ),
esc_textarea( $value ),
esc_attr( $class ) // Usamos la nueva variable de clase.
);
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 timezone_select_callback() { $name_attr = 'advaipbl_settings[log_timezone]'; $current_timezone = $this->plugin->options['log_timezone'] ?? wp_timezone_string(); echo ''; echo wp_timezone_choice($current_timezone, get_user_locale()); 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 '';
foreach ( $frequencies as $key => $label ) {
printf(
'%3$s ',
esc_attr( $key ),
selected( $value, $key, false ),
esc_html( $label )
);
}
echo ' ';
echo '' . esc_html__('Choose how often you want to receive alert emails.', 'advanced-ip-blocker') . '
';
}
/**
* Muestra la descripción para la sección de Threat Scoring.
*/
public function threat_scoring_section_callback() {
// La descripción ahora está en el HTML, esta función puede estar vacía.
// Opcionalmente, podemos dejar el 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' => 25],
'score_waf' => ['label' => __('WAF Rule Triggered', 'advanced-ip-blocker'), 'default' => 50],
'score_honeypot' => ['label' => __('Honeypot Accessed', 'advanced-ip-blocker'), 'default' => 100],
'score_asn' => ['label' => __('Blocked ASN (Spamhaus)', 'advanced-ip-blocker'), 'default' => 100],
];
?>
plugin->options['geolocation_provider'] ?? 'ip-api.com';
$providers = [
'ip-api.com' => __('ip-api.com (Default, no key for HTTP)', 'advanced-ip-blocker'),
'geoiplookup.net' => __('geoiplookup.net (Free, no key)', 'advanced-ip-blocker'),
'ipinfo.io' => __('ipinfo.io (API Key recommended)', 'advanced-ip-blocker'),
'ipapi.com' => __('ipapi.com (API Key required)', 'advanced-ip-blocker'),
'ipstack.com' => __('ipstack.com (API Key required)', 'advanced-ip-blocker')
];
// Añadimos un id único al select
printf( '', esc_attr( 'advaipbl_settings[geolocation_provider]' ) );
foreach ( $providers as $key => $label ) {
printf(
'%s ',
esc_attr( $key ),
selected( $value, $key, false ),
esc_html( $label )
);
}
echo ' ';
}
/**
* Renders the checkbox for the Whitelist Login Access feature, including security checks.
*/
public function restrict_login_page_callback() {
$args = [
'name' => 'restrict_login_page',
'label' => __( 'Restrict access to wp-login.php to whitelisted IPs only', 'advanced-ip-blocker' )
];
$client_ip = $this->plugin->get_client_ip();
$is_whitelisted = $this->plugin->is_whitelisted( $client_ip );
// Llama al callback del checkbox normal
$this->checkbox_field_callback($args);
// Añadimos la advertencia de seguridad
echo '' . 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 '' . esc_html__( 'Whitelist My IP Now', 'advanced-ip-blocker' ) . ' ';
echo '
';
}
}
/**
* Muestra el campo 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'),
];
?>
$label) : ?>
>
-
-
' . esc_html__( 'Block access from entire countries. This feature requires a working Geolocation Provider to be configured above.', 'advanced-ip-blocker' ) . '';
echo '' . 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
$option_name = ($type === 'geo_challenge') ? 'geo_challenge_countries' : 'geoblock_countries';
$select_id = 'advaipbl_' . $option_name;
$placeholder_text = ($type === 'geo_challenge')
? __('Search for a country to challenge...', 'advanced-ip-blocker')
: __('Search for a country to block...', 'advanced-ip-blocker');
$selected_countries = $this->plugin->options[$option_name] ?? [];
$all_countries = $this->plugin->get_country_list();
?>
$name ) : ?>
>
plugin->options['geolocation_method'] ?? 'api';
?>
>
>
plugin->geoip_manager ) return;
$status = $this->plugin->geoip_manager->get_database_status();
?>
plugin->options['tfa_force_roles'] ?? [];
$editable_roles = get_editable_roles();
?>
$role_details ) : ?>
>
plugin->options['recaptcha_enable'] ?? '0';
?>
>
plugin->options['recaptcha_version'] ?? 'v3';
?>
>
>
plugin->options['recaptcha_site_key'] ?? '';
?>
plugin->options['recaptcha_secret_key'] ?? '';
?>
plugin->options['recaptcha_score_threshold'] ?? '0.5';
?>