ARGUS WordPress Defence 1.0.0 — first production release
Automatic WordPress security: local firewall, malware and file-integrity scanning, vulnerability protection, quarantine, scheduled backups, an optional page cache, and automatic global threat intelligence. See README.md for installation, update, and uninstall instructions.
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'anis';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$protection_display = array(
|
||||
'active' => array( 'label' => __( 'ACTIVE', 'argus-wordpress-defence' ), 'chip' => 'chip-emerald' ),
|
||||
'limited' => array( 'label' => __( 'TEMPORARILY LIMITED', 'argus-wordpress-defence' ), 'chip' => 'chip-amber' ),
|
||||
'not_connected' => array( 'label' => __( 'CONNECTING...', 'argus-wordpress-defence' ), 'chip' => 'chip-off' ),
|
||||
);
|
||||
$state = $protection_display[ $anis_status['protection'] ];
|
||||
|
||||
$date_format = 'd M Y, H:i';
|
||||
$last_sync_display = $anis_status['last_sync'] ? wp_date( $date_format, strtotime( $anis_status['last_sync'] . ' UTC' ) ) : '';
|
||||
$next_sync_display = $anis_status['next_sync'] ? wp_date( $date_format, strtotime( $anis_status['next_sync'] . ' UTC' ) ) : '';
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Global Threat Intelligence', 'argus-wordpress-defence' ); ?></h1>
|
||||
|
||||
<div class="argus-wpd-status-row">
|
||||
<div class="argus-wpd-status-chip <?php echo esc_attr( $state['chip'] ); ?>">
|
||||
<span class="dot"></span>
|
||||
<span class="state"><?php echo esc_html( $state['label'] ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<p style="font-size:14px;color:var(--text);margin:0 0 20px;">
|
||||
<?php
|
||||
if ( 'active' === $anis_status['protection'] ) {
|
||||
esc_html_e( 'ARGUS Defence is automatically protected by continuously updated global threat intelligence.', 'argus-wordpress-defence' );
|
||||
} elseif ( 'limited' === $anis_status['protection'] ) {
|
||||
esc_html_e( 'ARGUS Defence is continuing to protect your website while global threat intelligence connectivity is being restored automatically.', 'argus-wordpress-defence' );
|
||||
} else {
|
||||
esc_html_e( 'ARGUS Defence is automatically connecting to the global threat intelligence network. Your local protection is already fully active.', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
|
||||
<table class="widefat" style="border:none;background:transparent;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="border:none;padding:10px 0;color:var(--faint);font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;width:45%;"><?php esc_html_e( 'Protection Status', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:10px 0;font-size:14px;color:var(--text);font-weight:600;"><?php echo 'active' === $anis_status['protection'] ? esc_html__( 'Active', 'argus-wordpress-defence' ) : esc_html__( 'Local Protection Active', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:none;padding:10px 0;color:var(--faint);font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;"><?php esc_html_e( 'Intelligence Updates', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:10px 0;font-size:14px;color:var(--text);font-weight:600;"><?php esc_html_e( 'Automatic', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:none;padding:10px 0;color:var(--faint);font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;"><?php esc_html_e( 'Update Frequency', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:10px 0;font-size:14px;color:var(--text);font-weight:600;"><?php esc_html_e( 'Every 60 minutes', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:none;padding:10px 0;color:var(--faint);font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;"><?php esc_html_e( 'Last Intelligence Sync', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:10px 0;font-size:14px;color:var(--text);font-weight:600;"><?php echo $last_sync_display ? esc_html( $last_sync_display ) : esc_html__( 'Pending', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:none;padding:10px 0;color:var(--faint);font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;"><?php esc_html_e( 'Next Intelligence Sync', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:10px 0;font-size:14px;color:var(--text);font-weight:600;"><?php echo $next_sync_display ? esc_html( $next_sync_display ) : esc_html__( 'Pending', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<p style="font-size:13px;color:var(--faint);margin:0;line-height:1.7;"><?php esc_html_e( 'Threat intelligence is privacy-focused. ARGUS Defence only shares anonymous security signals from activity already identified as malicious -- never usernames, passwords, page content, or anything that identifies your site or visitors.', 'argus-wordpress-defence' ); ?></p>
|
||||
</div>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'audit-log';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$severity_colors = array(
|
||||
'critical' => 'var(--rose)',
|
||||
'high' => 'var(--orange)',
|
||||
'medium' => 'var(--amber)',
|
||||
'low' => 'var(--cyan)',
|
||||
'info' => 'var(--faint)',
|
||||
);
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Audit Log', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 24px;"><?php esc_html_e( 'Every event ARGUS has recorded -- system-detected and administrator-initiated.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<form method="get" class="argus-wpd-inline-form" style="margin-bottom:16px;">
|
||||
<input type="hidden" name="page" value="argus-wpd-audit-log" />
|
||||
<input type="text" name="s" value="<?php echo esc_attr( $search ); ?>" placeholder="<?php esc_attr_e( 'Search events…', 'argus-wordpress-defence' ); ?>" />
|
||||
<select name="severity">
|
||||
<option value=""><?php esc_html_e( 'All Severities', 'argus-wordpress-defence' ); ?></option>
|
||||
<?php foreach ( array( 'critical', 'high', 'medium', 'low', 'info' ) as $sev ) : ?>
|
||||
<option value="<?php echo esc_attr( $sev ); ?>" <?php selected( $severity, $sev ); ?>><?php echo esc_html( ucfirst( $sev ) ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<select name="type">
|
||||
<option value=""><?php esc_html_e( 'All Types', 'argus-wordpress-defence' ); ?></option>
|
||||
<?php foreach ( $event_types as $t ) : ?>
|
||||
<option value="<?php echo esc_attr( $t ); ?>" <?php selected( $type, $t ); ?>><?php echo esc_html( ucwords( str_replace( '_', ' ', $t ) ) ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<select name="range">
|
||||
<option value=""><?php esc_html_e( 'All Time', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="24h" <?php selected( $range, '24h' ); ?>><?php esc_html_e( 'Last 24 Hours', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="7d" <?php selected( $range, '7d' ); ?>><?php esc_html_e( 'Last 7 Days', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="30d" <?php selected( $range, '30d' ); ?>><?php esc_html_e( 'Last 30 Days', 'argus-wordpress-defence' ); ?></option>
|
||||
</select>
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Filter', 'argus-wordpress-defence' ); ?></button>
|
||||
<?php if ( $search || $severity || $type || $range ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-audit-log' ) ); ?>" class="button"><?php esc_html_e( 'Clear', 'argus-wordpress-defence' ); ?></a>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<?php if ( empty( $events ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No events recorded yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Time', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Actor', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Event', 'argus-wordpress-defence' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $events as $event ) : ?>
|
||||
<?php $actor = $event->payload['actor'] ?? __( 'ARGUS', 'argus-wordpress-defence' ); ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( human_time_diff( strtotime( $event->created_at . ' UTC' ) ) ); ?> <?php esc_html_e( 'ago', 'argus-wordpress-defence' ); ?></td>
|
||||
<td><code><?php echo esc_html( $actor ); ?></code></td>
|
||||
<td>
|
||||
<span style="color:<?php echo esc_attr( $severity_colors[ $event->severity ] ?? 'var(--muted)' ); ?>">●</span>
|
||||
<?php echo esc_html( $event->summary ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$base_url = remove_query_arg( 'paged' );
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/footer.php';
|
||||
?>
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'backups';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$date_format = 'd M Y, H:i';
|
||||
$last_backup_display = $backup_status['last_backup'] ? wp_date( $date_format, strtotime( $backup_status['last_backup'] . ' UTC' ) ) : __( 'None yet', 'argus-wordpress-defence' );
|
||||
$next_backup_display = $backup_status['next_backup'] ? wp_date( $date_format, strtotime( $backup_status['next_backup'] . ' UTC' ) ) : __( 'Not scheduled', 'argus-wordpress-defence' );
|
||||
|
||||
$schedule_mode = Argus_Settings::get( 'backup_schedule_mode', 'automatic' );
|
||||
$interval_hours = (int) Argus_Settings::get( 'backup_interval_hours', 24 );
|
||||
$lockdown = Argus_Backup::lockdown_status();
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Backups', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 20px;"><?php esc_html_e( 'ARGUS can create scheduled recovery points for your WordPress website.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<?php if ( ! empty( $notice ) ) : ?>
|
||||
<div class="notice notice-<?php echo esc_attr( $notice_type ); ?>" style="padding:14px 18px;margin:0 0 20px;"><p style="margin:0"><?php echo esc_html( $notice ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( 'active' !== $lockdown ) : ?>
|
||||
<div class="notice notice-warning" style="padding:14px 18px;margin:0 0 20px;">
|
||||
<p style="margin:0"><?php esc_html_e( 'ARGUS could not secure the backup storage location on this host (a permissions issue in wp-content/uploads). Backups are not available until this is resolved.', 'argus-wordpress-defence' ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-metric-grid">
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Last Backup', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value" style="font-size:18px;"><?php echo esc_html( $last_backup_display ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Next Backup', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value" style="font-size:18px;"><?php echo esc_html( $next_backup_display ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Backup Status', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value" style="color:<?php echo 'active' === $lockdown ? 'var(--emerald)' : 'var(--rose)'; ?>;font-size:18px;"><?php echo 'active' === $lockdown ? esc_html__( 'Protected', 'argus-wordpress-defence' ) : esc_html__( 'Unavailable', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Available Recovery Points', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $backup_status['available'] ) ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Create a backup now', 'argus-wordpress-defence' ); ?></h2>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_backup_create', 'argus_wpd_backup_create_nonce' ); ?>
|
||||
<button type="submit" class="button button-primary" <?php disabled( 'active' !== $lockdown ); ?>><?php esc_html_e( 'Create Backup Now', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Backup Schedule', 'argus-wordpress-defence' ); ?></h2>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_backup_schedule', 'argus_wpd_backup_schedule_nonce' ); ?>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Schedule', 'argus-wordpress-defence' ); ?></th>
|
||||
<td>
|
||||
<label><input type="radio" name="backup_schedule_mode" value="automatic" <?php checked( $schedule_mode, 'automatic' ); ?> /> <?php esc_html_e( 'Automatic -- recommended, based on your active protection profile', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="radio" name="backup_schedule_mode" value="custom" <?php checked( $schedule_mode, 'custom' ); ?> /> <?php esc_html_e( 'Custom', 'argus-wordpress-defence' ); ?>
|
||||
<select name="backup_interval_hours">
|
||||
<option value="1" <?php selected( $interval_hours, 1 ); ?>><?php esc_html_e( 'Every 1 hour', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="6" <?php selected( $interval_hours, 6 ); ?>><?php esc_html_e( 'Every 6 hours', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="12" <?php selected( $interval_hours, 12 ); ?>><?php esc_html_e( 'Every 12 hours', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="24" <?php selected( $interval_hours, 24 ); ?>><?php esc_html_e( 'Every 24 hours', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="168" <?php selected( $interval_hours, 168 ); ?>><?php esc_html_e( 'Every 7 days', 'argus-wordpress-defence' ); ?></option>
|
||||
</select>
|
||||
</label><br>
|
||||
<label><input type="radio" name="backup_schedule_mode" value="manual" <?php checked( $schedule_mode, 'manual' ); ?> /> <?php esc_html_e( 'Manual -- only when I click Create Backup Now', 'argus-wordpress-defence' ); ?></label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Save Schedule', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Available Recovery Points', 'argus-wordpress-defence' ); ?></h2>
|
||||
<?php if ( empty( $backups ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No backups yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Date', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Type', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Size', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Status', 'argus-wordpress-defence' ); ?></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $backups as $backup ) : ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( wp_date( $date_format, strtotime( $backup->created_at . ' UTC' ) ) ); ?></td>
|
||||
<td><?php echo esc_html( Argus_Backup::TYPE_MANUAL === $backup->type ? __( 'Manual', 'argus-wordpress-defence' ) : __( 'Scheduled', 'argus-wordpress-defence' ) ); ?></td>
|
||||
<td><?php echo esc_html( Argus_Backup::STATUS_COMPLETE === $backup->status ? size_format( (int) $backup->size_bytes ) : '—' ); ?></td>
|
||||
<td>
|
||||
<?php if ( Argus_Backup::STATUS_COMPLETE === $backup->status ) : ?>
|
||||
<span style="color:var(--emerald);font-weight:600;"><?php esc_html_e( 'Complete', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span style="color:var(--rose);font-weight:600;" title="<?php echo esc_attr( $backup->error_message ); ?>"><?php esc_html_e( 'Failed', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ( Argus_Backup::STATUS_COMPLETE === $backup->status ) : ?>
|
||||
<a class="button" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=argus_wpd_download_backup&id=' . $backup->id ), 'argus_wpd_backup_download_' . $backup->id ) ); ?>"><?php esc_html_e( 'Download', 'argus-wordpress-defence' ); ?></a>
|
||||
<?php endif; ?>
|
||||
<form method="post" style="display:inline">
|
||||
<?php wp_nonce_field( 'argus_wpd_backup_delete_' . $backup->id, 'argus_wpd_backup_delete_nonce' ); ?>
|
||||
<input type="hidden" name="backup_id" value="<?php echo esc_attr( $backup->id ); ?>" />
|
||||
<button type="submit" class="button" style="color:var(--rose)" onclick="return confirm('<?php echo esc_js( __( 'Delete this backup permanently? This cannot be undone.', 'argus-wordpress-defence' ) ); ?>')"><?php esc_html_e( 'Delete', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$base_url = remove_query_arg( 'paged' );
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,596 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'cache';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$tabs = array(
|
||||
'overview' => __( 'Overview', 'argus-wordpress-defence' ),
|
||||
'page-cache' => __( 'Page Cache', 'argus-wordpress-defence' ),
|
||||
'discovery' => __( 'Page Discovery', 'argus-wordpress-defence' ),
|
||||
'rules' => __( 'Cache Rules', 'argus-wordpress-defence' ),
|
||||
'compression' => __( 'Compression', 'argus-wordpress-defence' ),
|
||||
'warming' => __( 'Preload', 'argus-wordpress-defence' ),
|
||||
'purge' => __( 'Purge & Cache', 'argus-wordpress-defence' ),
|
||||
'analytics' => __( 'Analytics', 'argus-wordpress-defence' ),
|
||||
'advanced' => __( 'Advanced', 'argus-wordpress-defence' ),
|
||||
);
|
||||
|
||||
$hit_30d = $log_summary_30d[ Argus_Static_Cache::STATUS_HIT ]['count'] ?? 0;
|
||||
$stale_30d = $log_summary_30d[ Argus_Static_Cache::STATUS_STALE ]['count'] ?? 0;
|
||||
$miss_30d = $log_summary_30d[ Argus_Static_Cache::STATUS_MISS ]['count'] ?? 0;
|
||||
$revalidated_30d = $log_summary_30d[ Argus_Static_Cache::STATUS_REVALIDATED ]['count'] ?? 0;
|
||||
$bypass_30d = $log_summary_30d[ Argus_Static_Cache::STATUS_BYPASS ]['count'] ?? 0;
|
||||
$excluded_30d = $log_summary_30d[ Argus_Static_Cache::STATUS_EXCLUDED ]['count'] ?? 0;
|
||||
$accelerated_30d = $hit_30d + $stale_30d;
|
||||
$origin_reached_30d = $miss_30d + $revalidated_30d;
|
||||
$total_eligible_30d = $accelerated_30d + $origin_reached_30d;
|
||||
$dynamic_protected_30d = $bypass_30d + $excluded_30d;
|
||||
|
||||
$requests_reduced_pct = $total_eligible_30d > 0 ? round( ( $accelerated_30d / $total_eligible_30d ) * 100 ) : null;
|
||||
$cache_efficiency_pct = $total_eligible_30d > 0 ? round( ( $accelerated_30d / max( 1, $total_eligible_30d + $dynamic_protected_30d ) ) * 100, 1 ) : null;
|
||||
|
||||
$performance_status = ! $settings['static_cache_enabled']
|
||||
? array( 'label' => __( 'Not Enabled', 'argus-wordpress-defence' ), 'chip' => 'chip-off' )
|
||||
: ( $total_eligible_30d < 20
|
||||
? array( 'label' => __( 'Learning', 'argus-wordpress-defence' ), 'chip' => 'chip-amber' )
|
||||
: array( 'label' => __( 'Optimised', 'argus-wordpress-defence' ), 'chip' => 'chip-emerald' ) );
|
||||
|
||||
$cumulative = 0;
|
||||
$cumulative_series = array();
|
||||
foreach ( $daily_series as $day ) {
|
||||
$cumulative += (int) $day['hit'];
|
||||
$cumulative_series[] = array( 'label' => $day['date'], 'value' => $cumulative );
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Cache & Performance', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 20px;"><?php esc_html_e( 'Your website is accelerated safely. Public pages are cached automatically when safe, while login areas, personalised content, shopping carts, and other dynamic pages are always excluded.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<?php if ( ! empty( $notice ) ) : ?>
|
||||
<div class="notice notice-<?php echo esc_attr( $notice_type ); ?>" style="padding:14px 18px;margin:0 0 20px;"><p style="margin:0"><?php echo esc_html( $notice ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-range-tabs" style="margin-bottom:20px;flex-wrap:wrap;">
|
||||
<?php foreach ( $tabs as $key => $label ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-cache&tab=' . $key ) ); ?>" class="<?php echo $key === $tab ? 'active' : ''; ?>"><?php echo esc_html( $label ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( 'overview' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-status-row">
|
||||
<div class="argus-wpd-status-chip <?php echo esc_attr( $performance_status['chip'] ); ?>">
|
||||
<span class="dot"></span>
|
||||
<span class="label"><?php esc_html_e( 'PERFORMANCE', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="state"><?php echo esc_html( strtoupper( $performance_status['label'] ) ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-status-chip chip-cyan">
|
||||
<span class="dot"></span>
|
||||
<span class="label"><?php esc_html_e( 'AUTOMATIC UPDATES', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="state"><?php echo esc_html( strtoupper( $auto_update['label'] ) ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-grid">
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Pages Accelerated', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $accelerated_30d ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Delivered instantly, last 30 days', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Website Requests Reduced', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo null === $requests_reduced_pct ? '—' : esc_html( $requests_reduced_pct . '%' ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( "Didn't need to be processed by WordPress", 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Cache Efficiency', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo null === $cache_efficiency_pct ? '—' : esc_html( $cache_efficiency_pct . '%' ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Of all safe, cacheable visits', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Dynamic Pages Protected', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $dynamic_protected_30d ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Kept safe from shared caching, last 30 days', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-area-card">
|
||||
<div class="argus-wpd-area-head">
|
||||
<h2 style="margin:0"><?php esc_html_e( 'Pages Accelerated', 'argus-wordpress-defence' ); ?> · <?php esc_html_e( 'Last 14 days, cumulative', 'argus-wordpress-defence' ); ?></h2>
|
||||
</div>
|
||||
<?php if ( $cumulative <= 0 ) : ?>
|
||||
<p class="argus-wpd-area-empty"><?php esc_html_e( 'No pages accelerated yet -- once Page Cache is turned on, this fills in automatically.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<?php echo Argus_Charts::area_chart( $cumulative_series ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( ! $settings['static_cache_enabled'] ) : ?>
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Turn on website acceleration', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 14px;"><?php esc_html_e( 'Safe Automatic mode is recommended -- ARGUS decides what is safe to accelerate for you.', 'argus-wordpress-defence' ); ?></p>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-cache&tab=page-cache' ) ); ?>" class="button button-primary"><?php esc_html_e( 'Go to Page Cache settings', 'argus-wordpress-defence' ); ?></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php elseif ( 'page-cache' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Safe Automatic — Recommended', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 16px;"><?php esc_html_e( 'ARGUS automatically caches only safe, public, anonymous pages. Login areas, personalised content, and shopping carts are always excluded -- there is nothing you need to configure for this to work safely.', 'argus-wordpress-defence' ); ?></p>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_cache_settings', 'argus_wpd_cache_settings_nonce' ); ?>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Website Acceleration', 'argus-wordpress-defence' ); ?></th>
|
||||
<td><label><input type="checkbox" name="static_cache_enabled" <?php checked( $settings['static_cache_enabled'] ); ?> /> <?php esc_html_e( 'Enabled (Safe Automatic)', 'argus-wordpress-defence' ); ?></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'How long pages stay cached', 'argus-wordpress-defence' ); ?></th>
|
||||
<td>
|
||||
<input type="number" name="static_cache_ttl_secs" value="<?php echo esc_attr( $settings['static_cache_ttl_secs'] ); ?>" min="60" step="60" style="width:100px" /> <?php esc_html_e( 'seconds', 'argus-wordpress-defence' ); ?>
|
||||
<p class="description"><?php esc_html_e( 'Default: 3600 (1 hour). Pages update automatically after this, or immediately when you publish/edit content.', 'argus-wordpress-defence' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Grace period', 'argus-wordpress-defence' ); ?></th>
|
||||
<td>
|
||||
<input type="number" name="cache_stale_grace_secs" value="<?php echo esc_attr( $settings['cache_stale_grace_secs'] ); ?>" min="0" step="60" style="width:100px" /> <?php esc_html_e( 'seconds', 'argus-wordpress-defence' ); ?>
|
||||
<p class="description"><?php esc_html_e( 'Keeps serving a page instantly for a short extra window while ARGUS refreshes it in the background, so visitors never wait during an update.', 'argus-wordpress-defence' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Additional pages to exclude', 'argus-wordpress-defence' ); ?></th>
|
||||
<td>
|
||||
<textarea name="cache_custom_exclude_paths" rows="4" style="width:100%;max-width:480px;" placeholder="/special-landing-page /members-area/*"><?php echo esc_textarea( implode( "\n", (array) $settings['cache_custom_exclude_paths'] ) ); ?></textarea>
|
||||
<p class="description"><?php esc_html_e( 'One path per line. Use * as a wildcard. Optional -- ARGUS already protects login, checkout, and account pages automatically.', 'argus-wordpress-defence' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php submit_button( __( 'Save', 'argus-wordpress-defence' ) ); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Automatically Protected', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 14px;"><?php esc_html_e( 'These are never cached, with no configuration needed:', 'argus-wordpress-defence' ); ?></p>
|
||||
<ul style="font-size:13px;color:var(--text);margin:0;padding-left:20px;line-height:1.9;">
|
||||
<li><?php esc_html_e( 'Your login and admin area', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Logged-in visitors', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Shopping cart, checkout, and account pages (WooCommerce)', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Search results and preview pages', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Comment forms and personalised content', 'argus-wordpress-defence' ); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'discovery' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-grid">
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Pages Found', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $discovery_summary['total'] ?? 0 ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Eligible for Acceleration', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $discovery_summary['eligible'] ?? 0 ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Excluded for Safety', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $discovery_summary['excluded'] ?? 0 ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Needs Review', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $discovery_summary['needs_review'] ?? 0 ) ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<p style="font-size:13px;color:var(--text);margin:0 0 12px;">
|
||||
<?php if ( ! empty( $discovery_summary['last_run'] ) ) : ?>
|
||||
<?php
|
||||
printf(
|
||||
|
||||
esc_html__( 'Last checked %s ago.', 'argus-wordpress-defence' ),
|
||||
esc_html( human_time_diff( strtotime( $discovery_summary['last_run'] . ' UTC' ) ) )
|
||||
);
|
||||
?>
|
||||
<?php else : ?>
|
||||
<?php esc_html_e( "ARGUS hasn't looked for your pages yet.", 'argus-wordpress-defence' ); ?>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<?php if ( ! empty( $discovery_summary['last_error'] ) ) : ?>
|
||||
<p style="font-size:12.5px;color:var(--amber);margin:0 0 12px;"><?php echo esc_html( $discovery_summary['last_error'] ); ?></p>
|
||||
<?php endif; ?>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_cache_run_discovery', 'argus_wpd_cache_run_discovery_nonce' ); ?>
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e( 'Find Pages Now', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $discovered_urls['rows'] ) ) : ?>
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Discovered Pages', 'argus-wordpress-defence' ); ?></h2>
|
||||
<table class="widefat striped">
|
||||
<thead><tr><th><?php esc_html_e( 'Page', 'argus-wordpress-defence' ); ?></th><th><?php esc_html_e( 'Status', 'argus-wordpress-defence' ); ?></th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ( $discovered_urls['rows'] as $row ) : ?>
|
||||
<tr>
|
||||
<td style="word-break:break-all;"><?php echo esc_html( $row->url ); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$eligible_labels = array(
|
||||
Argus_Cache_Eligibility::SAFE_TO_CACHE => __( 'Eligible', 'argus-wordpress-defence' ),
|
||||
Argus_Cache_Eligibility::BYPASS => __( 'Excluded', 'argus-wordpress-defence' ),
|
||||
Argus_Cache_Eligibility::FORCE_EXCLUDED => __( 'Excluded', 'argus-wordpress-defence' ),
|
||||
Argus_Cache_Eligibility::NEEDS_REVIEW => __( 'Needs Review', 'argus-wordpress-defence' ),
|
||||
);
|
||||
echo esc_html( $eligible_labels[ $row->eligibility ] ?? $row->eligibility );
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$page = $discovered_urls['page'];
|
||||
$total_pages = $discovered_urls['total_pages'];
|
||||
$base_url = remove_query_arg( 'paged' );
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php elseif ( 'rules' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'How ARGUS decides what to accelerate', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 16px;"><?php esc_html_e( 'Checked in this order for every page view. Safety always comes first.', 'argus-wordpress-defence' ); ?></p>
|
||||
<ol style="font-size:13px;color:var(--text);margin:0;padding-left:20px;line-height:2;">
|
||||
<li><?php esc_html_e( 'Security and privacy checks', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Is the visitor logged in?', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Shopping cart, checkout, or account activity (WooCommerce)', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Login, admin, and other protected areas', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Your own additional exclusions', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Personalised or changing content', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'What the page itself says about being cacheable', 'argus-wordpress-defence' ); ?></li>
|
||||
<li><?php esc_html_e( 'Safe to accelerate', 'argus-wordpress-defence' ); ?></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Recently excluded pages', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 14px;"><?php esc_html_e( 'For troubleshooting -- shows why a specific page was not accelerated.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php $rule_examples = array_slice( Argus_Cache_Log::recent( 15, Argus_Static_Cache::STATUS_BYPASS ), 0, 15 ); ?>
|
||||
<?php if ( empty( $rule_examples ) ) : ?>
|
||||
<p class="argus-wpd-empty" style="padding:10px 0;"><?php esc_html_e( 'Nothing to show yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead><tr><th><?php esc_html_e( 'Page', 'argus-wordpress-defence' ); ?></th><th><?php esc_html_e( 'Reason', 'argus-wordpress-defence' ); ?></th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ( $rule_examples as $row ) : ?>
|
||||
<tr>
|
||||
<td style="word-break:break-all;"><?php echo esc_html( wp_parse_url( $row['u'] ?? '', PHP_URL_PATH ) ?: ( $row['u'] ?? '' ) ); ?></td>
|
||||
<td><?php echo esc_html( $row['r'] ?? '' ); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'compression' === $tab ) : ?>
|
||||
|
||||
<?php if ( $compression_stats['gzip']['files'] > 0 || $compression_stats['brotli']['files'] > 0 ) : ?>
|
||||
<div class="argus-wpd-grid">
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Data Saved', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( size_format( $compression_stats['total_bytes_saved'] ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Across all accelerated pages', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Gzip', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo $compression_stats['gzip']['files'] > 0 ? esc_html( $compression_stats['gzip']['avg_savings_pct'] . '%' ) : '—'; ?></div>
|
||||
<div class="argus-wpd-metric-sub">
|
||||
<?php
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
|
||||
__( 'Average savings, %1$d page(s), %2$s saved', 'argus-wordpress-defence' ),
|
||||
$compression_stats['gzip']['files'],
|
||||
size_format( $compression_stats['gzip']['bytes_saved'] )
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Brotli', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo $compression_stats['brotli']['files'] > 0 ? esc_html( $compression_stats['brotli']['avg_savings_pct'] . '%' ) : '—'; ?></div>
|
||||
<div class="argus-wpd-metric-sub">
|
||||
<?php
|
||||
echo esc_html(
|
||||
$compression_stats['brotli']['files'] > 0
|
||||
? sprintf(
|
||||
|
||||
__( 'Average savings, %1$d page(s), %2$s saved', 'argus-wordpress-defence' ),
|
||||
$compression_stats['brotli']['files'],
|
||||
size_format( $compression_stats['brotli']['bytes_saved'] )
|
||||
)
|
||||
: __( 'Not currently in use', 'argus-wordpress-defence' )
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Compression', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 16px;"><?php esc_html_e( 'Accelerated pages are compressed automatically before being sent to visitors -- smaller downloads, faster page loads. Each visitor\'s browser receives only the format it supports.', 'argus-wordpress-defence' ); ?></p>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_cache_compression', 'argus_wpd_cache_compression_nonce' ); ?>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Gzip Compression', 'argus-wordpress-defence' ); ?></th>
|
||||
<td>
|
||||
<label><input type="checkbox" name="cache_gzip_enabled" <?php checked( $settings['cache_gzip_enabled'] ); ?> <?php disabled( ! $gzip_available ); ?> /> <?php esc_html_e( 'Enabled', 'argus-wordpress-defence' ); ?></label>
|
||||
<?php if ( ! $gzip_available ) : ?><p class="description"><?php esc_html_e( 'Not available on this server.', 'argus-wordpress-defence' ); ?></p><?php endif; ?>
|
||||
<p class="description"><?php esc_html_e( 'Compression level (1 = fastest, 9 = smallest)', 'argus-wordpress-defence' ); ?></p>
|
||||
<input type="number" name="cache_gzip_level" value="<?php echo esc_attr( $settings['cache_gzip_level'] ); ?>" min="1" max="9" style="width:80px" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Brotli Compression', 'argus-wordpress-defence' ); ?></th>
|
||||
<td>
|
||||
<label><input type="checkbox" name="cache_brotli_enabled" <?php checked( $settings['cache_brotli_enabled'] ); ?> <?php disabled( ! $brotli_available ); ?> /> <?php esc_html_e( 'Enabled', 'argus-wordpress-defence' ); ?></label>
|
||||
<?php if ( ! $brotli_available ) : ?><p class="description"><?php esc_html_e( 'Not available on this server -- your hosting provider would need to enable this. Gzip is used automatically instead.', 'argus-wordpress-defence' ); ?></p><?php endif; ?>
|
||||
<p class="description"><?php esc_html_e( 'Compression level (0 = fastest, 11 = smallest)', 'argus-wordpress-defence' ); ?></p>
|
||||
<input type="number" name="cache_brotli_level" value="<?php echo esc_attr( $settings['cache_brotli_level'] ); ?>" min="0" max="11" style="width:80px" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Minimum page size to compress', 'argus-wordpress-defence' ); ?></th>
|
||||
<td><input type="number" name="cache_min_compress_bytes" value="<?php echo esc_attr( $settings['cache_min_compress_bytes'] ); ?>" min="0" style="width:100px" /> <?php esc_html_e( 'bytes', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php submit_button( __( 'Save', 'argus-wordpress-defence' ) ); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'warming' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-grid">
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Pages Prepared', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $warmer_status['done'] ?? 0 ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Waiting', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( ( $warmer_status['queued'] ?? 0 ) + ( $warmer_status['processing'] ?? 0 ) ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Needs Attention', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $warmer_status['failed'] ?? 0 ) ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $warmer_status['paused_until'] ) ) : ?>
|
||||
<div class="notice notice-warning" style="padding:14px 18px;margin:0 0 20px;"><p style="margin:0"><?php esc_html_e( 'Preparation is briefly paused to avoid adding load to your website. It will resume automatically.', 'argus-wordpress-defence' ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Preload / Cache Warming', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 16px;"><?php esc_html_e( 'ARGUS can visit your public pages ahead of time so the very first real visitor still gets an instant page load. This is always paced gently and pauses automatically if your website is under load.', 'argus-wordpress-defence' ); ?></p>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_cache_warming', 'argus_wpd_cache_warming_nonce' ); ?>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Page Discovery', 'argus-wordpress-defence' ); ?></th>
|
||||
<td><label><input type="checkbox" name="cache_discovery_enabled" <?php checked( $settings['cache_discovery_enabled'] ); ?> /> <?php esc_html_e( 'Automatically find pages daily', 'argus-wordpress-defence' ); ?></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Preloading', 'argus-wordpress-defence' ); ?></th>
|
||||
<td><label><input type="checkbox" name="cache_warming_enabled" <?php checked( $settings['cache_warming_enabled'] ); ?> /> <?php esc_html_e( 'Enabled', 'argus-wordpress-defence' ); ?></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'How many pages to prepare at once', 'argus-wordpress-defence' ); ?></th>
|
||||
<td><input type="number" name="cache_warm_concurrency" value="<?php echo esc_attr( $settings['cache_warm_concurrency'] ); ?>" min="1" max="10" style="width:80px" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Pages per hour', 'argus-wordpress-defence' ); ?></th>
|
||||
<td><input type="number" name="cache_warm_batch_size" value="<?php echo esc_attr( $settings['cache_warm_batch_size'] ); ?>" min="1" max="200" style="width:80px" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Pause between groups', 'argus-wordpress-defence' ); ?></th>
|
||||
<td><input type="number" name="cache_warm_min_interval_secs" value="<?php echo esc_attr( $settings['cache_warm_min_interval_secs'] ); ?>" min="0" max="30" style="width:80px" /> <?php esc_html_e( 'seconds', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php submit_button( __( 'Save', 'argus-wordpress-defence' ) ); ?>
|
||||
</form>
|
||||
<form method="post" style="margin-top:10px;">
|
||||
<?php wp_nonce_field( 'argus_wpd_cache_run_warming', 'argus_wpd_cache_run_warming_nonce' ); ?>
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Prepare Pages Now', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'purge' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Refresh Cache', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 14px;">
|
||||
<?php
|
||||
printf(
|
||||
|
||||
esc_html__( '%1$s pages currently accelerated (%2$s).', 'argus-wordpress-defence' ),
|
||||
esc_html( number_format_i18n( $cache_stats['file_count'] ) ),
|
||||
esc_html( size_format( $cache_stats['total_bytes'] ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<form method="post" onsubmit="return confirm('<?php echo esc_js( __( 'Refresh the entire cache? All visitors will get a freshly-generated page until it rebuilds.', 'argus-wordpress-defence' ) ); ?>')">
|
||||
<?php wp_nonce_field( 'argus_wpd_cache_purge_all', 'argus_wpd_cache_purge_all_nonce' ); ?>
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Refresh Everything', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Refresh a Specific Page', 'argus-wordpress-defence' ); ?></h2>
|
||||
<form method="post" class="argus-wpd-inline-form">
|
||||
<?php wp_nonce_field( 'argus_wpd_cache_purge_url', 'argus_wpd_cache_purge_url_nonce' ); ?>
|
||||
<input type="text" name="purge_url" placeholder="<?php echo esc_attr( home_url( '/example-page/' ) ); ?>" style="min-width:320px" required />
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Refresh', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
<form method="post" class="argus-wpd-inline-form" style="margin-top:10px;">
|
||||
<?php wp_nonce_field( 'argus_wpd_cache_purge_pattern', 'argus_wpd_cache_purge_pattern_nonce' ); ?>
|
||||
<input type="text" name="purge_pattern" placeholder="<?php echo esc_attr( home_url( '/blog/*' ) ); ?>" style="min-width:320px" required />
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Refresh Matching Pages', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Recently Accelerated Pages', 'argus-wordpress-defence' ); ?></h2>
|
||||
<?php if ( empty( $cached_urls ) ) : ?>
|
||||
<p class="argus-wpd-empty" style="padding:10px 0;"><?php esc_html_e( 'Nothing accelerated yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead><tr><th><?php esc_html_e( 'Page', 'argus-wordpress-defence' ); ?></th><th><?php esc_html_e( 'Size', 'argus-wordpress-defence' ); ?></th><th><?php esc_html_e( 'Age', 'argus-wordpress-defence' ); ?></th><th><?php esc_html_e( 'Compression', 'argus-wordpress-defence' ); ?></th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ( $cached_urls as $row ) : ?>
|
||||
<tr>
|
||||
<td style="word-break:break-all;"><?php echo esc_html( $row['url'] ); ?></td>
|
||||
<td><?php echo esc_html( size_format( $row['bytes'] ) ); ?></td>
|
||||
<td><?php echo null === $row['age_secs'] ? '—' : esc_html( human_time_diff( time() - $row['age_secs'] ) . ' ' . __( 'ago', 'argus-wordpress-defence' ) ); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$badges = array();
|
||||
if ( $row['has_brotli'] ) { $badges[] = 'Brotli'; }
|
||||
if ( $row['has_gzip'] ) { $badges[] = 'Gzip'; }
|
||||
echo esc_html( $badges ? implode( ', ', $badges ) : __( 'None', 'argus-wordpress-defence' ) );
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'analytics' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-area-card">
|
||||
<div class="argus-wpd-area-head"><h2 style="margin:0"><?php esc_html_e( 'Pages Accelerated', 'argus-wordpress-defence' ); ?> · <?php esc_html_e( 'Last 14 days, cumulative', 'argus-wordpress-defence' ); ?></h2></div>
|
||||
<?php if ( $cumulative <= 0 ) : ?>
|
||||
<p class="argus-wpd-area-empty"><?php esc_html_e( 'No activity recorded yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<?php echo Argus_Charts::area_chart( $cumulative_series ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel" style="display:flex;gap:32px;align-items:center;flex-wrap:wrap;">
|
||||
<?php
|
||||
$distribution = array(
|
||||
__( 'Served from Cache', 'argus-wordpress-defence' ) => $hit_30d + $stale_30d,
|
||||
__( 'Loaded from WordPress', 'argus-wordpress-defence' ) => $miss_30d + $revalidated_30d,
|
||||
__( 'Excluded for Safety', 'argus-wordpress-defence' ) => $dynamic_protected_30d,
|
||||
);
|
||||
?>
|
||||
<?php echo Argus_Charts::donut( $distribution ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
<div style="flex:1;min-width:220px;"><?php echo Argus_Charts::legend( $distribution ); // phpcs:ignore WordPress.Security.EscapeOutput ?></div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Recent Activity', 'argus-wordpress-defence' ); ?></h2>
|
||||
<div class="argus-wpd-range-tabs" style="margin-bottom:14px;">
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-cache&tab=analytics' ) ); ?>" class="<?php echo empty( $_GET['status'] ) ? 'active' : ''; ?>"><?php esc_html_e( 'All', 'argus-wordpress-defence' ); ?></a>
|
||||
<?php foreach ( array( 'HIT' => __( 'Served from Cache', 'argus-wordpress-defence' ), 'MISS' => __( 'Loaded from WordPress', 'argus-wordpress-defence' ), 'BYPASS' => __( 'Excluded', 'argus-wordpress-defence' ), 'WARMED' => __( 'Preloaded', 'argus-wordpress-defence' ), 'PURGED' => __( 'Refreshed', 'argus-wordpress-defence' ) ) as $status_key => $status_label ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-cache&tab=analytics&status=' . strtolower( $status_key ) ) ); ?>" class="<?php echo ( isset( $_GET['status'] ) && strtoupper( sanitize_key( wp_unslash( $_GET['status'] ) ) ) === $status_key ) ? 'active' : ''; ?>"><?php echo esc_html( $status_label ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ( empty( $recent_log ) ) : ?>
|
||||
<p class="argus-wpd-empty" style="padding:10px 0;"><?php esc_html_e( 'No activity recorded yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead><tr><th><?php esc_html_e( 'When', 'argus-wordpress-defence' ); ?></th><th><?php esc_html_e( 'Page', 'argus-wordpress-defence' ); ?></th><th><?php esc_html_e( 'Result', 'argus-wordpress-defence' ); ?></th></tr></thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$friendly_status = array(
|
||||
'HIT' => __( 'Served from Cache', 'argus-wordpress-defence' ),
|
||||
'STALE' => __( 'Served from Cache', 'argus-wordpress-defence' ),
|
||||
'MISS' => __( 'Loaded from WordPress', 'argus-wordpress-defence' ),
|
||||
'REVALIDATED' => __( 'Refreshed', 'argus-wordpress-defence' ),
|
||||
'BYPASS' => __( 'Excluded', 'argus-wordpress-defence' ),
|
||||
'EXCLUDED' => __( 'Excluded', 'argus-wordpress-defence' ),
|
||||
'WARMED' => __( 'Preloaded', 'argus-wordpress-defence' ),
|
||||
'PURGED' => __( 'Refreshed', 'argus-wordpress-defence' ),
|
||||
'EXPIRED' => __( 'Renewed', 'argus-wordpress-defence' ),
|
||||
);
|
||||
?>
|
||||
<?php foreach ( $recent_log as $row ) : ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( human_time_diff( (int) ( $row['t'] ?? time() ) ) . ' ' . __( 'ago', 'argus-wordpress-defence' ) ); ?></td>
|
||||
<td style="word-break:break-all;"><?php echo esc_html( wp_parse_url( $row['u'] ?? '', PHP_URL_PATH ) ?: ( $row['u'] ?? '' ) ); ?></td>
|
||||
<td><?php echo esc_html( $friendly_status[ $row['s'] ?? '' ] ?? ( $row['s'] ?? '' ) ); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$page = $log_page;
|
||||
$total_pages = $log_total_pages;
|
||||
$base_url = remove_query_arg( 'paged' );
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'advanced' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Additional Performance Opportunity', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--text);font-size:13px;margin:0 0 14px;line-height:1.6;"><?php esc_html_e( 'Your website could benefit from server-level compression for static files. ARGUS is already optimizing the content it can safely accelerate -- to compress images, fonts, and other static files further, your hosting provider may need to enable server-level compression.', 'argus-wordpress-defence' ); ?></p>
|
||||
<table class="widefat" style="border:none;background:transparent;margin-bottom:14px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="border:none;padding:6px 0;color:var(--faint);font-size:12px;width:160px;"><?php esc_html_e( 'What this improves', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:6px 0;color:var(--text);font-size:13px;"><?php esc_html_e( 'Faster delivery of static website files.', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:none;padding:6px 0;color:var(--faint);font-size:12px;"><?php esc_html_e( 'Recommended next step', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:6px 0;color:var(--text);font-size:13px;"><?php esc_html_e( 'Contact your hosting provider.', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$provider_message = __( "Hello,\n\nI would like to confirm whether server-level compression is enabled for static assets on my WordPress website.\n\nCould you please confirm whether Gzip and/or Brotli compression is available for static files such as CSS, JavaScript, fonts and supported text-based assets?\n\nThank you.", 'argus-wordpress-defence' );
|
||||
?>
|
||||
<details>
|
||||
<summary style="cursor:pointer;font-weight:600;font-size:12.5px;color:var(--cyan);"><?php esc_html_e( 'Copy message for your hosting provider', 'argus-wordpress-defence' ); ?></summary>
|
||||
<textarea readonly rows="7" style="width:100%;max-width:520px;margin-top:10px;background:var(--panel-2);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:10px;font-size:12.5px;font-family:inherit;" onclick="this.select();"><?php echo esc_textarea( $provider_message ); ?></textarea>
|
||||
<p style="color:var(--faint);font-size:11.5px;margin:6px 0 0;"><?php esc_html_e( 'Click the text above to select it, then copy.', 'argus-wordpress-defence' ); ?></p>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<details>
|
||||
<summary style="cursor:pointer;font-weight:600;font-size:13px;"><?php esc_html_e( 'Advanced Diagnostics', 'argus-wordpress-defence' ); ?></summary>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:12px 0 16px;"><?php esc_html_e( 'For troubleshooting with support -- not needed for normal use.', 'argus-wordpress-defence' ); ?></p>
|
||||
<table class="widefat striped">
|
||||
<tbody>
|
||||
<tr><td><?php esc_html_e( 'Cached pages on disk', 'argus-wordpress-defence' ); ?></td><td><?php echo esc_html( number_format_i18n( $cache_stats['file_count'] ) ); ?></td></tr>
|
||||
<tr><td><?php esc_html_e( 'Storage used', 'argus-wordpress-defence' ); ?></td><td><?php echo esc_html( size_format( $cache_stats['total_bytes'] ) ); ?></td></tr>
|
||||
<tr><td><?php esc_html_e( 'Gzip available on this server', 'argus-wordpress-defence' ); ?></td><td><?php echo $gzip_available ? esc_html__( 'Yes', 'argus-wordpress-defence' ) : esc_html__( 'No', 'argus-wordpress-defence' ); ?></td></tr>
|
||||
<tr><td><?php esc_html_e( 'Brotli available on this server', 'argus-wordpress-defence' ); ?></td><td><?php echo $brotli_available ? esc_html__( 'Yes', 'argus-wordpress-defence' ) : esc_html__( 'No', 'argus-wordpress-defence' ); ?></td></tr>
|
||||
<tr><td><?php esc_html_e( 'Page discovery last run', 'argus-wordpress-defence' ); ?></td><td><?php echo esc_html( $discovery_summary['last_run'] ?: '—' ); ?></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'findings';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$view_labels = array(
|
||||
'active' => __( 'Active', 'argus-wordpress-defence' ),
|
||||
'needs_attention' => __( 'Needs Attention', 'argus-wordpress-defence' ),
|
||||
'resolved' => __( 'Resolved', 'argus-wordpress-defence' ),
|
||||
'accepted' => __( 'Accepted', 'argus-wordpress-defence' ),
|
||||
);
|
||||
|
||||
$donut_data = array();
|
||||
foreach ( $view_labels as $key => $label ) {
|
||||
if ( ( $view_counts[ $key ] ?? 0 ) > 0 ) {
|
||||
$donut_data[ $label ] = $view_counts[ $key ];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Findings', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 20px;"><?php esc_html_e( 'Everything ARGUS has found, organized by what still needs your attention.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<?php if ( ! empty( $action_result ) ) : ?>
|
||||
<div class="notice <?php echo $action_result['success'] ? 'notice-success' : 'notice-error'; ?>" style="padding:14px 18px;margin:0 0 20px;">
|
||||
<p style="margin:0"><?php echo esc_html( $action_result['message'] ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $findings_notice ) ) : ?>
|
||||
<div class="notice notice-success" style="padding:14px 18px;margin:0 0 20px;">
|
||||
<p style="margin:0"><?php echo esc_html( $findings_notice ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $donut_data ) ) : ?>
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Finding Status', 'argus-wordpress-defence' ); ?></h2>
|
||||
<div class="argus-wpd-donut-row">
|
||||
<?php echo Argus_Charts::donut( $donut_data ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
<?php echo Argus_Charts::legend( $donut_data ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-range-tabs" style="margin-bottom:20px;flex-wrap:wrap;">
|
||||
<?php foreach ( $view_labels as $key => $label ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-findings&view=' . $key ) ); ?>" class="<?php echo $key === $view ? 'active' : ''; ?>"><?php echo esc_html( $label ); ?> (<?php echo esc_html( number_format_i18n( $view_counts[ $key ] ?? 0 ) ); ?>)</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;margin-bottom:16px;">
|
||||
<h2 style="margin:0"><?php echo esc_html( $view_labels[ $view ] ); ?></h2>
|
||||
<?php if ( in_array( $view, array( 'active', 'needs_attention' ), true ) && ! empty( $findings ) ) : ?>
|
||||
<form method="post" onsubmit="return confirm('<?php echo esc_js( __( 'Mark every currently open finding as resolved? This does not undo anything ARGUS already did -- it only clears them from your review queue.', 'argus-wordpress-defence' ) ); ?>')">
|
||||
<?php wp_nonce_field( 'argus_wpd_resolve_all_open', 'argus_wpd_resolve_all_nonce' ); ?>
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Resolve All Open', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ( empty( $findings ) ) : ?>
|
||||
<p class="argus-wpd-empty">
|
||||
<?php
|
||||
switch ( $view ) {
|
||||
case 'needs_attention':
|
||||
esc_html_e( 'Nothing needs your attention right now.', 'argus-wordpress-defence' );
|
||||
break;
|
||||
case 'resolved':
|
||||
esc_html_e( 'No resolved findings yet.', 'argus-wordpress-defence' );
|
||||
break;
|
||||
case 'accepted':
|
||||
esc_html_e( 'No accepted-risk findings yet.', 'argus-wordpress-defence' );
|
||||
break;
|
||||
default:
|
||||
esc_html_e( 'No active findings -- your site is clear.', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
<?php else : ?>
|
||||
<div class="argus-wpd-finding-list">
|
||||
<?php foreach ( $findings as $finding ) : ?>
|
||||
<?php $argus_compact = false; include ARGUS_WPD_DIR . 'admin/views/partials/finding-card.php'; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$base_url = remove_query_arg( array( 'finding', 'paged' ) );
|
||||
$argus_page_param = 'paged';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/footer.php';
|
||||
?>
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'firewall';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$action_labels = array(
|
||||
'block' => __( 'Block', 'argus-wordpress-defence' ),
|
||||
'challenge' => __( 'Challenge', 'argus-wordpress-defence' ),
|
||||
'rate_limit' => __( 'Rate Limit', 'argus-wordpress-defence' ),
|
||||
'allow' => __( 'Allow', 'argus-wordpress-defence' ),
|
||||
);
|
||||
|
||||
$tabs = array(
|
||||
'overview' => __( 'Overview', 'argus-wordpress-defence' ),
|
||||
'rule-activity' => __( 'Rule Activity', 'argus-wordpress-defence' ),
|
||||
'manual-block' => __( 'Manual IP Block', 'argus-wordpress-defence' ),
|
||||
'blocked-ips' => __( 'Blocked IPs', 'argus-wordpress-defence' ),
|
||||
);
|
||||
|
||||
$blocked_24h = $security_actions[ __( 'Blocked', 'argus-wordpress-defence' ) ] ?? 0;
|
||||
$challenged_24h = $security_actions[ __( 'Challenged', 'argus-wordpress-defence' ) ] ?? 0;
|
||||
$top_categories = array_slice( $attack_categories, 0, 3, true );
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Firewall', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 20px;"><?php esc_html_e( 'ARGUS actively monitors and blocks malicious requests before they can reach sensitive areas of your website.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<?php if ( ! empty( $notice ) ) : ?>
|
||||
<div class="notice notice-success" style="padding:14px 18px;margin:0 0 20px;"><p style="margin:0"><?php echo esc_html( $notice ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-range-tabs" style="margin-bottom:20px;flex-wrap:wrap;">
|
||||
<?php foreach ( $tabs as $key => $label ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-firewall&tab=' . $key ) ); ?>" class="<?php echo $key === $tab ? 'active' : ''; ?>"><?php echo esc_html( $label ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( 'overview' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-tile-row">
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Requests Blocked Today', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value"><?php echo esc_html( number_format_i18n( $requests_blocked_24h ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Rules Active', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value"><?php echo esc_html( number_format_i18n( $rules_active ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Malicious IPs', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value"><?php echo esc_html( number_format_i18n( $malicious_ips ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Mode', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value" style="font-size:16px;text-transform:capitalize;"><?php echo esc_html( Argus_Settings::mode() ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-columns-equal">
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Attack Categories', 'argus-wordpress-defence' ); ?> <span class="argus-wpd-subtle-label"><?php esc_html_e( 'Last 24h', 'argus-wordpress-defence' ); ?></span></h2>
|
||||
<?php if ( empty( $attack_categories ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No attack activity in the last 24 hours.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<div class="argus-wpd-donut-row">
|
||||
<?php echo Argus_Charts::donut( $attack_categories ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
<?php echo Argus_Charts::legend( $attack_categories ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Security Actions', 'argus-wordpress-defence' ); ?> <span class="argus-wpd-subtle-label"><?php esc_html_e( 'Last 24h', 'argus-wordpress-defence' ); ?></span></h2>
|
||||
<?php if ( empty( $security_actions ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No enforcement activity in the last 24 hours.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<div class="argus-wpd-donut-row">
|
||||
<?php echo Argus_Charts::donut( $security_actions ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
<?php echo Argus_Charts::legend( $security_actions ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<?php if ( $blocked_24h > 0 || $challenged_24h > 0 ) : ?>
|
||||
<p style="font-size:14px;color:var(--text);margin:0 0 14px;">
|
||||
<?php
|
||||
echo esc_html(
|
||||
$challenged_24h > 0
|
||||
? sprintf(
|
||||
|
||||
__( 'ARGUS blocked %1$s malicious requests and challenged %2$s suspicious requests during the last 24 hours.', 'argus-wordpress-defence' ),
|
||||
number_format_i18n( $blocked_24h ),
|
||||
number_format_i18n( $challenged_24h )
|
||||
)
|
||||
: sprintf(
|
||||
|
||||
__( 'ARGUS blocked %s malicious requests during the last 24 hours.', 'argus-wordpress-defence' ),
|
||||
number_format_i18n( $blocked_24h )
|
||||
)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php if ( ! empty( $top_categories ) ) : ?>
|
||||
<p style="font-size:12.5px;color:var(--muted);margin:0 0 6px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;"><?php esc_html_e( 'Top activity', 'argus-wordpress-defence' ); ?></p>
|
||||
<ul style="margin:0;padding:0;list-style:none;">
|
||||
<?php foreach ( $top_categories as $label => $count ) : ?>
|
||||
<li style="font-size:13px;color:var(--text);padding:4px 0;">— <?php echo esc_html( $label ); ?>: <strong><?php echo esc_html( number_format_i18n( $count ) ); ?> <?php esc_html_e( 'blocked', 'argus-wordpress-defence' ); ?></strong></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No malicious activity detected in the last 24 hours.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'rule-activity' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Rule Activity', 'argus-wordpress-defence' ); ?> · <?php esc_html_e( 'Last 24h', 'argus-wordpress-defence' ); ?></h2>
|
||||
<?php if ( empty( $rule_hits ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No rule hits in the last 24 hours.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Rule', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Category', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Action', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Hits (24h)', 'argus-wordpress-defence' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $rule_hits as $hit ) : ?>
|
||||
<tr>
|
||||
<td><code><?php echo esc_html( $hit['label'] ); ?></code></td>
|
||||
<td><?php echo esc_html( $hit['category'] ); ?></td>
|
||||
<td><?php echo esc_html( $action_labels[ $hit['action'] ] ?? ucfirst( $hit['action'] ) ); ?></td>
|
||||
<td><?php echo esc_html( number_format_i18n( $hit['hits'] ) ); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'manual-block' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Block an IP manually', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--muted);font-size:12.5px;margin:0 0 16px;"><?php esc_html_e( 'The address is blocked immediately and appears in Blocked IPs.', 'argus-wordpress-defence' ); ?></p>
|
||||
<form method="post" class="argus-wpd-inline-form">
|
||||
<?php wp_nonce_field( 'argus_wpd_block_ip', 'argus_wpd_block_nonce' ); ?>
|
||||
<input type="text" name="block_ip" placeholder="203.0.113.10" required pattern="^[0-9a-fA-F:.]+$" />
|
||||
<input type="text" name="block_reason" placeholder="<?php esc_attr_e( 'Reason (optional)', 'argus-wordpress-defence' ); ?>" />
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e( 'Block', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php elseif ( 'blocked-ips' === $tab ) : ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Blocked IPs', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--muted);font-size:12.5px;margin:0 0 16px;"><?php esc_html_e( 'Currently active blocks only. Lifted or expired blocks no longer appear here -- the full history is in the Audit Log.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php if ( empty( $bans ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No IPs are currently blocked.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'IP', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Source', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Reason', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Level', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Blocked', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Expires', 'argus-wordpress-defence' ); ?></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $bans as $ban ) : ?>
|
||||
<tr>
|
||||
<td><span class="argus-wpd-flag" title="<?php echo esc_attr( Argus_GeoIP::label( $ban->ip ) ); ?>"><?php echo esc_html( Argus_GeoIP::icon( $ban->ip ) ); ?></span> <code><?php echo esc_html( $ban->ip ); ?></code></td>
|
||||
<td><?php echo esc_html( $ban->source ); ?></td>
|
||||
<td><?php echo esc_html( $ban->reason ); ?></td>
|
||||
<td><?php echo esc_html( $ban->ban_level ); ?></td>
|
||||
<td><?php echo esc_html( human_time_diff( strtotime( $ban->created_at . ' UTC' ) ) ); ?> <?php esc_html_e( 'ago', 'argus-wordpress-defence' ); ?></td>
|
||||
<td><?php echo esc_html( $ban->expires_at ?: __( 'Permanent', 'argus-wordpress-defence' ) ); ?></td>
|
||||
<td>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_unban_' . $ban->id, 'argus_wpd_unban_nonce' ); ?>
|
||||
<input type="hidden" name="ban_id" value="<?php echo esc_attr( $ban->id ); ?>" />
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Unban', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$base_url = remove_query_arg( 'paged' );
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'intelligence';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Intelligence', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 24px;"><?php esc_html_e( 'Threat intelligence sources feeding ARGUS Defence.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<div class="argus-wpd-not-connected">
|
||||
<span class="icon"><?php echo 'active' === $anis_status['protection'] ? '🛡' : '🔌'; ?></span>
|
||||
<div>
|
||||
<h3>
|
||||
<?php
|
||||
if ( 'active' === $anis_status['protection'] ) {
|
||||
esc_html_e( 'GLOBAL THREAT INTELLIGENCE: ACTIVE', 'argus-wordpress-defence' );
|
||||
} elseif ( 'limited' === $anis_status['protection'] ) {
|
||||
esc_html_e( 'GLOBAL THREAT INTELLIGENCE: TEMPORARILY LIMITED', 'argus-wordpress-defence' );
|
||||
} else {
|
||||
esc_html_e( 'GLOBAL THREAT INTELLIGENCE: CONNECTING', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</h3>
|
||||
<p>
|
||||
<?php if ( 'active' === $anis_status['protection'] ) : ?>
|
||||
<?php esc_html_e( 'ARGUS Defence is automatically connected to the ARGUS threat intelligence network. Continuously updated intelligence helps identify and block malicious sources detected across the ARGUS security network. Everything below is this site\'s own local intelligence.', 'argus-wordpress-defence' ); ?>
|
||||
<?php elseif ( 'limited' === $anis_status['protection'] ) : ?>
|
||||
<?php esc_html_e( 'ARGUS Defence is continuing to protect your website while intelligence connectivity is being restored automatically.', 'argus-wordpress-defence' ); ?>
|
||||
<?php else : ?>
|
||||
<?php esc_html_e( 'ARGUS Defence is connecting to the global threat intelligence network -- this happens automatically, no action needed. Everything below is this site\'s own local intelligence, already fully active.', 'argus-wordpress-defence' ); ?>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<p style="margin-top:10px;"><a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-anis' ) ); ?>" class="button"><?php esc_html_e( 'View Threat Intelligence Status', 'argus-wordpress-defence' ); ?></a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-tile-row">
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'WAF Rule Corpus', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value"><?php echo esc_html( number_format_i18n( $waf_rule_count ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Vulnerability Intelligence', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value" style="font-size:16px;">
|
||||
<?php if ( $vuln_row_count > 0 ) : ?>
|
||||
<span style="color:var(--emerald)"><?php esc_html_e( 'Active', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span style="color:var(--faint)"><?php esc_html_e( 'Standby', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'GeoIP Database', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value" style="font-size:16px;">
|
||||
<?php if ( $geoip_status && ! empty( $geoip_status['range_count'] ) ) : ?>
|
||||
<span style="color:var(--emerald)"><?php esc_html_e( 'Loaded', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span style="color:var(--faint)"><?php esc_html_e( 'Building', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Local Intelligence Sources', 'argus-wordpress-defence' ); ?></h2>
|
||||
<div class="argus-wpd-ioc-row">
|
||||
<span class="argus-wpd-ioc-type">WAF</span>
|
||||
<span class="argus-wpd-ioc-desc"><?php echo esc_html( sprintf( __( 'Application-layer signature corpus (SQLi/XSS/RCE/path traversal/protocol anomaly) -- %d rules, updated with this plugin.', 'argus-wordpress-defence' ), $waf_rule_count ) ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-ioc-row">
|
||||
<span class="argus-wpd-ioc-type">VULN</span>
|
||||
<span class="argus-wpd-ioc-desc">
|
||||
<?php
|
||||
echo esc_html(
|
||||
$vuln_row_count > 0
|
||||
? __( 'Vulnerability intelligence -- actively matching installed plugins and themes against known security issues.', 'argus-wordpress-defence' )
|
||||
: __( 'Vulnerability intelligence -- WordPress core is checked live against WordPress.org. Plugin and theme results activate automatically as intelligence becomes available.', 'argus-wordpress-defence' )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="argus-wpd-ioc-row">
|
||||
<span class="argus-wpd-ioc-type">GEOIP</span>
|
||||
<span class="argus-wpd-ioc-desc">
|
||||
<?php
|
||||
if ( $geoip_status && ! empty( $geoip_status['range_count'] ) ) {
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
__( 'Self-hosted RIR delegation database -- %s IPv4 ranges, last refreshed %s.', 'argus-wordpress-defence' ),
|
||||
number_format_i18n( $geoip_status['range_count'] ),
|
||||
$geoip_status['last_refresh'] ? human_time_diff( strtotime( $geoip_status['last_refresh'] . ' UTC' ) ) . ' ' . __( 'ago', 'argus-wordpress-defence' ) : __( 'never', 'argus-wordpress-defence' )
|
||||
)
|
||||
);
|
||||
} else {
|
||||
esc_html_e( 'Self-hosted RIR delegation database has not built its first snapshot yet -- refreshes automatically once daily, no action needed.', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="argus-wpd-ioc-row">
|
||||
<span class="argus-wpd-ioc-type">ANIS</span>
|
||||
<span class="argus-wpd-ioc-desc">
|
||||
<?php
|
||||
if ( 'not_connected' === $anis_status['protection'] ) {
|
||||
esc_html_e( 'Global threat intelligence -- connecting automatically.', 'argus-wordpress-defence' );
|
||||
} else {
|
||||
esc_html_e( 'Global threat intelligence -- automatically updated to help identify malicious sources.', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'overview';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$range_labels = array( '24h' => '24H', '7d' => '7D', '30d' => '30D' );
|
||||
|
||||
$score = max( 0, 100 - ( $counts['critical'] * 15 ) - ( $counts['high'] * 8 ) - ( $counts['medium'] * 3 ) - ( $counts['low'] * 1 ) );
|
||||
$score_r = 54;
|
||||
$score_circ = 2 * M_PI * $score_r;
|
||||
$score_offset = $score_circ * ( 1 - $score / 100 );
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'ARGUS Defence', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 24px;"><?php esc_html_e( 'Security Operations Center for your WordPress site.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<?php if ( 'installed' !== $mu_status ) : ?>
|
||||
<div class="notice notice-warning" style="padding:14px 18px;margin:0 0 20px;">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
|
||||
esc_html__( 'Maximum protection is not fully active on this host (status: %s). ARGUS is still protecting your site via its standard fallback hook, but consider checking file permissions on wp-content/mu-plugins.', 'argus-wordpress-defence' ),
|
||||
esc_html( $mu_status )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php elseif ( 'stale' === $mu_exec_status ) : ?>
|
||||
<div class="notice notice-error" style="padding:14px 18px;margin:0 0 20px;">
|
||||
<p><?php esc_html_e( 'Maximum protection was installed but ARGUS has not seen it actually run recently -- it may have been removed from wp-content/mu-plugins outside of WordPress. ARGUS is still protecting your site via its standard fallback hook, but check that wp-content/mu-plugins/argus-mu-core.php still exists.', 'argus-wordpress-defence' ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-grid">
|
||||
<div class="argus-wpd-card argus-wpd-score">
|
||||
<svg viewBox="0 0 128 128">
|
||||
<circle class="argus-wpd-score-track" cx="64" cy="64" r="<?php echo esc_attr( $score_r ); ?>"></circle>
|
||||
<circle class="argus-wpd-score-arc" cx="64" cy="64" r="<?php echo esc_attr( $score_r ); ?>"
|
||||
stroke-dasharray="<?php echo esc_attr( $score_circ ); ?>"
|
||||
stroke-dashoffset="<?php echo esc_attr( $score_offset ); ?>"
|
||||
transform="rotate(-90 64 64)"></circle>
|
||||
<text x="64" y="70" text-anchor="middle" class="argus-wpd-score-num"><?php echo esc_html( $score ); ?></text>
|
||||
</svg>
|
||||
<div class="argus-wpd-score-label"><?php esc_html_e( 'Security Score', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Threats Blocked Today', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $blocked_today ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Local WAF + policy engine, since 00:00 UTC', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Malicious IPs', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $malicious_ips ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Currently banned by local WAF + policy engine', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Blocked Requests', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $blocked_30d ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Last 30 days', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Security Events', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $security_events ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Medium severity or higher, last 30 days', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-area-card">
|
||||
<div class="argus-wpd-area-head">
|
||||
<h2 style="margin:0"><?php esc_html_e( 'Blocked Requests', 'argus-wordpress-defence' ); ?> · <?php echo esc_html( $range_labels[ $range ] ?? $range ); ?></h2>
|
||||
<div class="argus-wpd-range-tabs">
|
||||
<?php foreach ( $range_labels as $key => $label ) : ?>
|
||||
<a href="<?php echo esc_url( add_query_arg( 'range', $key ) ); ?>" class="<?php echo $key === $range ? 'active' : ''; ?>"><?php echo esc_html( $label ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ( array_sum( wp_list_pluck( $series, 'value' ) ) <= 0 ) : ?>
|
||||
<p class="argus-wpd-area-empty"><?php esc_html_e( 'No blocked requests recorded in this window yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<?php echo Argus_Charts::area_chart( $series ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-status-row">
|
||||
<div class="argus-wpd-status-chip <?php echo Argus_Settings::get( 'waf_enabled', true ) ? ( Argus_Settings::is_monitor_only() ? 'chip-amber' : 'chip-cyan' ) : 'chip-off'; ?>">
|
||||
<span class="dot"></span>
|
||||
<span class="label">FIREWALL</span>
|
||||
<span class="state"><?php echo Argus_Settings::get( 'waf_enabled', true ) ? ( Argus_Settings::is_monitor_only() ? esc_html__( 'MONITORING', 'argus-wordpress-defence' ) : esc_html__( 'BLOCKING', 'argus-wordpress-defence' ) ) : esc_html__( 'DISABLED', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-status-chip <?php echo ( $malware_open > 0 || $integrity_open > 0 ) ? 'chip-rose' : 'chip-emerald'; ?>">
|
||||
<span class="dot"></span>
|
||||
<span class="label">SCANNER</span>
|
||||
<span class="state"><?php echo ( $malware_open > 0 || $integrity_open > 0 ) ? esc_html__( 'ISSUES FOUND', 'argus-wordpress-defence' ) : esc_html__( 'CLEAN', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
<?php
|
||||
$anis_chip_map = array(
|
||||
'active' => array( 'chip-cyan', __( 'CONNECTED', 'argus-wordpress-defence' ) ),
|
||||
'limited' => array( 'chip-amber', __( 'LIMITED', 'argus-wordpress-defence' ) ),
|
||||
'not_connected' => array( 'chip-off', __( 'CONNECTING…', 'argus-wordpress-defence' ) ),
|
||||
);
|
||||
list( $anis_chip_class, $anis_chip_state ) = $anis_chip_map[ $anis_status['protection'] ] ?? $anis_chip_map['not_connected'];
|
||||
?>
|
||||
<div class="argus-wpd-status-chip <?php echo esc_attr( $anis_chip_class ); ?>">
|
||||
<span class="dot"></span>
|
||||
<span class="label">ANIS</span>
|
||||
<span class="state"><?php echo esc_html( $anis_chip_state ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_compact = $argus_compact ?? false;
|
||||
$action = $finding->evidence['action'] ?? null;
|
||||
$finding_ip = $finding->evidence['ip'] ?? null;
|
||||
?>
|
||||
<div class="argus-wpd-finding-card argus-wpd-sev-<?php echo esc_attr( $finding->severity ); ?>">
|
||||
<div class="argus-wpd-finding-summary">
|
||||
<span class="argus-wpd-sev-badge"><?php echo esc_html( strtoupper( $finding->severity ) ); ?></span>
|
||||
<span class="argus-wpd-finding-title">
|
||||
<?php if ( $finding_ip ) : ?>
|
||||
<span class="argus-wpd-flag" title="<?php echo esc_attr( Argus_GeoIP::label( $finding_ip ) ); ?>"><?php echo esc_html( Argus_GeoIP::icon( $finding_ip ) ); ?></span>
|
||||
<?php endif; ?>
|
||||
<?php echo esc_html( $finding->title ); ?>
|
||||
</span>
|
||||
<span class="argus-wpd-status-pill argus-wpd-status-<?php echo esc_attr( $finding->status ); ?>"><?php echo esc_html( ucfirst( str_replace( '_', ' ', $finding->status ) ) ); ?></span>
|
||||
<span class="argus-wpd-finding-time"><?php echo esc_html( human_time_diff( strtotime( $finding->last_seen_at . ' UTC' ) ) ); ?> <?php esc_html_e( 'ago', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-finding-actions">
|
||||
<?php if ( $action && ! empty( $action['type'] ) ) : ?>
|
||||
<form method="post" action="<?php echo esc_url( add_query_arg( 'finding', $finding->id ) ); ?>" style="display:inline">
|
||||
<?php wp_nonce_field( 'argus_wpd_run_action_' . $finding->id, 'argus_wpd_action_nonce' ); ?>
|
||||
<button type="submit" class="button button-primary" onclick="return confirm('<?php echo esc_js( sprintf( __( 'Run "%s" now? This will make a real change to your site.', 'argus-wordpress-defence' ), $action['label'] ) ); ?>')">
|
||||
<?php echo esc_html( $action['label'] ); ?>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php if ( Argus_Findings::STATUS_OPEN === $finding->status ) : ?>
|
||||
<form method="post" action="<?php echo esc_url( add_query_arg( 'finding', $finding->id ) ); ?>" style="display:inline">
|
||||
<?php wp_nonce_field( 'argus_wpd_set_status_' . $finding->id, 'argus_wpd_status_nonce' ); ?>
|
||||
<button type="submit" name="new_status" value="acknowledged" class="button"><?php esc_html_e( 'Acknowledge', 'argus-wordpress-defence' ); ?></button>
|
||||
<button type="submit" name="new_status" value="resolved" class="button"><?php esc_html_e( 'Resolve', 'argus-wordpress-defence' ); ?></button>
|
||||
<button type="submit" name="new_status" value="risk_accepted" class="button"><?php esc_html_e( 'Accept Risk', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<form method="post" action="<?php echo esc_url( add_query_arg( 'finding', $finding->id ) ); ?>" style="display:inline">
|
||||
<?php wp_nonce_field( 'argus_wpd_delete_finding_' . $finding->id, 'argus_wpd_delete_finding_nonce' ); ?>
|
||||
<button type="submit" class="button" style="color:var(--rose)" onclick="return confirm('<?php echo esc_js( __( 'Delete this finding permanently? This cannot be undone.', 'argus-wordpress-defence' ) ); ?>')"><?php esc_html_e( 'Delete', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if ( ! $argus_compact && ! empty( $finding->explain ) ) : ?>
|
||||
<details class="argus-wpd-finding-details">
|
||||
<summary><?php esc_html_e( 'Show full explanation', 'argus-wordpress-defence' ); ?></summary>
|
||||
<?php echo Argus_Explain::render( $finding->explain ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
</details>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = $argus_active_page ?? 'overview';
|
||||
$argus_mode = Argus_Settings::mode();
|
||||
$argus_mode_labels = array( 'monitor' => 'Monitor', 'block' => 'Block', 'strict' => 'Strict' );
|
||||
|
||||
$argus_domain = wp_parse_url( home_url(), PHP_URL_HOST ) ?: get_bloginfo( 'name' );
|
||||
|
||||
$argus_protection_state = Argus_Console_Stats::protection_state();
|
||||
$argus_protection_labels = array(
|
||||
'protected' => array( 'class' => 'on', 'label' => __( 'Protected', 'argus-wordpress-defence' ) ),
|
||||
'action_required' => array( 'class' => 'danger', 'label' => __( 'Action Required', 'argus-wordpress-defence' ) ),
|
||||
'checking' => array( 'class' => 'checking', 'label' => __( 'Checking Security', 'argus-wordpress-defence' ) ),
|
||||
);
|
||||
$argus_protection_display = $argus_protection_labels[ $argus_protection_state ] ?? $argus_protection_labels['protected'];
|
||||
|
||||
$argus_nav_items = array(
|
||||
'overview' => array( __( 'Overview', 'argus-wordpress-defence' ), 'argus-wpd-dashboard' ),
|
||||
'firewall' => array( __( 'Firewall', 'argus-wordpress-defence' ), 'argus-wpd-firewall' ),
|
||||
'threats' => array( __( 'Threats', 'argus-wordpress-defence' ), 'argus-wpd-threats' ),
|
||||
'findings' => array( __( 'Findings', 'argus-wordpress-defence' ), 'argus-wpd-findings' ),
|
||||
'scanner' => array( __( 'Scanner', 'argus-wordpress-defence' ), 'argus-wpd-scanner' ),
|
||||
'quarantine' => array( __( 'Quarantine', 'argus-wordpress-defence' ), 'argus-wpd-quarantine' ),
|
||||
'cache' => array( __( 'Cache & Performance', 'argus-wordpress-defence' ), 'argus-wpd-cache' ),
|
||||
'backups' => array( __( 'Backups', 'argus-wordpress-defence' ), 'argus-wpd-backups' ),
|
||||
'vulnerabilities' => array( __( 'Vulnerabilities', 'argus-wordpress-defence' ), 'argus-wpd-vulnerabilities' ),
|
||||
'intelligence' => array( __( 'Intelligence', 'argus-wordpress-defence' ), 'argus-wpd-intelligence' ),
|
||||
'anis' => array( __( 'ANIS', 'argus-wordpress-defence' ), 'argus-wpd-anis' ),
|
||||
'audit-log' => array( __( 'Audit Log', 'argus-wordpress-defence' ), 'argus-wpd-audit-log' ),
|
||||
);
|
||||
?>
|
||||
<div class="argus-wpd-shell">
|
||||
<div class="argus-wpd-inner">
|
||||
|
||||
<div class="argus-wpd-topbar">
|
||||
<div class="argus-wpd-logo">🛡</div>
|
||||
<div class="argus-wpd-brand">
|
||||
<span class="argus-wpd-eyebrow"><span class="dot"></span>ARGUS DEFENCE · SECURITY OPERATIONS CENTER</span>
|
||||
<span class="argus-wpd-title"><?php echo esc_html( $argus_domain ); ?></span>
|
||||
<span class="argus-wpd-domain-caption"><?php esc_html_e( 'ARGUS Defence is protecting this website', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-status-badge <?php echo esc_attr( $argus_protection_display['class'] ); ?>">
|
||||
<span class="dot"></span>
|
||||
<?php echo esc_html( $argus_protection_display['label'] ); ?>
|
||||
· <?php echo esc_html( $argus_mode_labels[ $argus_mode ] ?? $argus_mode ); ?>
|
||||
</div>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-settings' ) ); ?>" class="argus-wpd-gear <?php echo 'settings' === $argus_active_page ? 'active' : ''; ?>" title="<?php esc_attr_e( 'Settings', 'argus-wordpress-defence' ); ?>">⚙</a>
|
||||
</div>
|
||||
|
||||
<nav class="argus-wpd-nav">
|
||||
<?php foreach ( $argus_nav_items as $key => $item ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=' . $item[1] ) ); ?>" class="<?php echo $key === $argus_active_page ? 'active' : ''; ?>"><?php echo esc_html( $item[0] ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</nav>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_page_param = $argus_page_param ?? 'paged';
|
||||
|
||||
if ( $total_pages <= 1 ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="argus-wpd-pagination">
|
||||
<?php if ( $page > 1 ) : ?>
|
||||
<a href="<?php echo esc_url( add_query_arg( $argus_page_param, $page - 1, $base_url ) ); ?>" class="argus-wpd-page-link">← <?php esc_html_e( 'Previous', 'argus-wordpress-defence' ); ?></a>
|
||||
<?php endif; ?>
|
||||
|
||||
<span class="argus-wpd-page-info">
|
||||
<?php
|
||||
printf(
|
||||
|
||||
esc_html__( 'Page %1$d of %2$d', 'argus-wordpress-defence' ),
|
||||
(int) $page,
|
||||
(int) $total_pages
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
|
||||
<?php if ( $page < $total_pages ) : ?>
|
||||
<a href="<?php echo esc_url( add_query_arg( $argus_page_param, $page + 1, $base_url ) ); ?>" class="argus-wpd-page-link"><?php esc_html_e( 'Next', 'argus-wordpress-defence' ); ?> →</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'quarantine';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$status_labels = array(
|
||||
Argus_Quarantine::STATUS_QUARANTINED => __( 'Quarantined', 'argus-wordpress-defence' ),
|
||||
Argus_Quarantine::STATUS_RESTORED => __( 'Restored', 'argus-wordpress-defence' ),
|
||||
Argus_Quarantine::STATUS_DELETED => __( 'Deleted', 'argus-wordpress-defence' ),
|
||||
);
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Quarantine', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 24px;">
|
||||
<?php
|
||||
echo $review_count > 0
|
||||
? esc_html( sprintf( _n( '%d item requires review.', '%d items require review.', $review_count, 'argus-wordpress-defence' ), $review_count ) )
|
||||
: esc_html__( 'No items currently require review.', 'argus-wordpress-defence' );
|
||||
?>
|
||||
</p>
|
||||
|
||||
<?php if ( ! empty( $notice ) ) : ?>
|
||||
<div class="notice notice-<?php echo esc_attr( $notice_type ); ?>" style="padding:14px 18px;margin:0 0 20px;"><p style="margin:0"><?php echo esc_html( $notice ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-grid">
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Currently Quarantined', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $status_counts[ Argus_Quarantine::STATUS_QUARANTINED ] ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Restored', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $status_counts[ Argus_Quarantine::STATUS_RESTORED ] ) ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Deleted', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $status_counts[ Argus_Quarantine::STATUS_DELETED ] ) ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( $legacy_count > 0 ) : ?>
|
||||
<div class="notice notice-warning" style="padding:14px 18px;margin:0 0 20px;">
|
||||
<p style="margin:0">
|
||||
<?php
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
|
||||
_n(
|
||||
'%d file quarantined by an earlier version of ARGUS exists outside this page\'s tracked store (left in place, not migrated). It is not executable but is not listed below.',
|
||||
'%d files quarantined by an earlier version of ARGUS exist outside this page\'s tracked store (left in place, not migrated). They are not executable but are not listed below.',
|
||||
$legacy_count,
|
||||
'argus-wordpress-defence'
|
||||
),
|
||||
$legacy_count
|
||||
)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;margin-bottom:20px;">
|
||||
<div class="argus-wpd-range-tabs">
|
||||
<?php foreach ( $status_labels as $key => $label ) : ?>
|
||||
<a href="<?php echo esc_url( add_query_arg( array( 'status' => $key, 'paged' => false ) ) ); ?>" class="<?php echo $key === $status_filter ? 'active' : ''; ?>"><?php echo esc_html( $label ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="argus-wpd-range-tabs">
|
||||
<?php foreach ( array( 10, 25, 50 ) as $size ) : ?>
|
||||
<a href="<?php echo esc_url( add_query_arg( array( 'per_page' => $size, 'paged' => false ) ) ); ?>" class="<?php echo $size === $per_page ? 'active' : ''; ?>"><?php echo esc_html( $size ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( empty( $items ) ) : ?>
|
||||
<div class="argus-wpd-panel"><p class="argus-wpd-empty"><?php esc_html_e( 'Nothing here.', 'argus-wordpress-defence' ); ?></p></div>
|
||||
<?php else : ?>
|
||||
<div class="argus-wpd-finding-list">
|
||||
<?php foreach ( $items as $item ) : ?>
|
||||
<div class="argus-wpd-finding-card argus-wpd-sev-<?php echo esc_attr( $item->severity ); ?>">
|
||||
<div class="argus-wpd-finding-summary">
|
||||
<span class="argus-wpd-sev-badge"><?php echo esc_html( strtoupper( $item->severity ) ); ?></span>
|
||||
<span class="argus-wpd-finding-title"><?php echo esc_html( $item->original_path ); ?></span>
|
||||
<span class="argus-wpd-status-pill argus-wpd-status-<?php echo esc_attr( $item->status ); ?>"><?php echo esc_html( $status_labels[ $item->status ] ?? ucfirst( $item->status ) ); ?></span>
|
||||
<span class="argus-wpd-finding-time"><?php echo esc_html( human_time_diff( strtotime( $item->quarantined_at . ' UTC' ) ) ); ?> <?php esc_html_e( 'ago', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
|
||||
<?php if ( Argus_Quarantine::STATUS_QUARANTINED === $item->status ) : ?>
|
||||
<div class="argus-wpd-finding-actions">
|
||||
<form method="post" style="display:inline">
|
||||
<?php wp_nonce_field( 'argus_wpd_quarantine_analyse_' . $item->id, 'argus_wpd_quarantine_analyse_nonce' ); ?>
|
||||
<input type="hidden" name="quarantine_id" value="<?php echo esc_attr( $item->id ); ?>" />
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Analyse', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
<form method="post" style="display:inline">
|
||||
<?php wp_nonce_field( 'argus_wpd_quarantine_restore_' . $item->id, 'argus_wpd_quarantine_restore_nonce' ); ?>
|
||||
<input type="hidden" name="quarantine_id" value="<?php echo esc_attr( $item->id ); ?>" />
|
||||
<button type="submit" class="button" onclick="return confirm('<?php echo esc_js( __( 'Restore this file? ARGUS will re-verify its content first and refuse if it still looks malicious.', 'argus-wordpress-defence' ) ); ?>')"><?php esc_html_e( 'Restore', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
<form method="post" style="display:inline">
|
||||
<?php wp_nonce_field( 'argus_wpd_quarantine_delete_' . $item->id, 'argus_wpd_quarantine_delete_nonce' ); ?>
|
||||
<input type="hidden" name="quarantine_id" value="<?php echo esc_attr( $item->id ); ?>" />
|
||||
<button type="submit" class="button" style="color:var(--rose);border-color:rgba(230,103,103,.4);" onclick="return confirm('<?php echo esc_js( __( 'Delete permanently? This file will be permanently removed and cannot be recovered from ARGUS Quarantine.', 'argus-wordpress-defence' ) ); ?>')"><?php esc_html_e( 'Delete Permanently', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<details class="argus-wpd-finding-details">
|
||||
<summary><?php esc_html_e( 'Inspect', 'argus-wordpress-defence' ); ?></summary>
|
||||
<dl class="argus-explain">
|
||||
<dt><?php esc_html_e( 'Detection Engine', 'argus-wordpress-defence' ); ?></dt>
|
||||
<dd><?php echo esc_html( $item->detection_engine ); ?></dd>
|
||||
<dt><?php esc_html_e( 'Detection Type', 'argus-wordpress-defence' ); ?></dt>
|
||||
<dd><?php echo esc_html( ucfirst( $item->detection_type ) ); ?></dd>
|
||||
<dt><?php esc_html_e( 'Detection Rule', 'argus-wordpress-defence' ); ?></dt>
|
||||
<dd><?php echo esc_html( $item->detection_rule ?: '—' ); ?></dd>
|
||||
<dt><?php esc_html_e( 'File Size', 'argus-wordpress-defence' ); ?></dt>
|
||||
<dd><?php echo esc_html( size_format( (int) $item->file_size ) ); ?></dd>
|
||||
<dt><?php esc_html_e( 'SHA-256 (at time of quarantine)', 'argus-wordpress-defence' ); ?></dt>
|
||||
<dd><code><?php echo esc_html( $item->file_hash ); ?></code></dd>
|
||||
<dt><?php esc_html_e( 'Original Modified', 'argus-wordpress-defence' ); ?></dt>
|
||||
<dd><?php echo esc_html( $item->original_mtime ?: '—' ); ?></dd>
|
||||
<?php if ( $item->analysed_at ) : ?>
|
||||
<dt><?php esc_html_e( 'Last Analysis', 'argus-wordpress-defence' ); ?></dt>
|
||||
<dd>
|
||||
<?php
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
|
||||
__( 'Score %1$d, analysed %2$s ago', 'argus-wordpress-defence' ),
|
||||
(int) $item->confidence_score,
|
||||
human_time_diff( strtotime( $item->analysed_at . ' UTC' ) )
|
||||
)
|
||||
);
|
||||
if ( ! empty( $item->matched_rules ) ) {
|
||||
echo ' -- ' . esc_html__( 'matched:', 'argus-wordpress-defence' ) . ' ' . esc_html( implode( ', ', $item->matched_rules ) );
|
||||
}
|
||||
?>
|
||||
</dd>
|
||||
<?php endif; ?>
|
||||
</dl>
|
||||
</details>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
$base_url = remove_query_arg( 'paged' );
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/footer.php';
|
||||
?>
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'scanner';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$scan_type_labels = array(
|
||||
Argus_Scan_History::TYPE_QUICK => __( 'Quick Scan', 'argus-wordpress-defence' ),
|
||||
Argus_Scan_History::TYPE_FULL => __( 'Full Scan', 'argus-wordpress-defence' ),
|
||||
Argus_Scan_History::TYPE_SCHEDULED_INCREMENTAL => __( 'Scheduled (Quick)', 'argus-wordpress-defence' ),
|
||||
Argus_Scan_History::TYPE_SCHEDULED_FULL => __( 'Scheduled (Full)', 'argus-wordpress-defence' ),
|
||||
);
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Scanner', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 20px;"><?php esc_html_e( 'ARGUS regularly checks your WordPress installation for suspicious files, integrity changes, and known security risks.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<?php if ( ! empty( $scan_notice ) ) : ?>
|
||||
<div class="notice notice-success" style="padding:14px 18px;margin:0 0 20px;"><p style="margin:0"><?php echo esc_html( $scan_notice ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-metric-grid">
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Last Scan Status', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value" style="color:<?php echo ( $malware_open > 0 || $integrity_open > 0 ) ? 'var(--rose)' : 'var(--emerald)'; ?>"><?php echo ( $malware_open > 0 || $integrity_open > 0 ) ? esc_html__( 'Issues', 'argus-wordpress-defence' ) : esc_html__( 'Clean', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php echo $scan_status['last_full_scan'] ? esc_html( human_time_diff( $scan_status['last_full_scan'] ) . ' ' . __( 'ago', 'argus-wordpress-defence' ) ) : esc_html__( 'No scan yet', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Files Checked', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $scan_status['files_scanned'] ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Last full scan', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Findings', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value"><?php echo esc_html( number_format_i18n( $malware_open + $integrity_open ) ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Currently open', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php esc_html_e( 'Next Scan', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-value" style="font-size:22px;"><?php echo $scan_status['next_scan'] ? esc_html( human_time_diff( $scan_status['next_scan'] ) ) : esc_html__( 'Not scheduled', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-metric-sub"><?php esc_html_e( 'Automatic, daily', 'argus-wordpress-defence' ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Run a scan now', 'argus-wordpress-defence' ); ?></h2>
|
||||
<form method="post" class="argus-wpd-inline-form">
|
||||
<?php wp_nonce_field( 'argus_wpd_run_scan', 'argus_wpd_scan_nonce' ); ?>
|
||||
<button type="submit" name="scan_type" value="quick" class="button"><?php esc_html_e( 'Quick Scan', 'argus-wordpress-defence' ); ?></button>
|
||||
<button type="submit" name="scan_type" value="full" class="button button-primary"><?php esc_html_e( 'Full Scan', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Scan History', 'argus-wordpress-defence' ); ?></h2>
|
||||
<?php if ( empty( $scan_history ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No scans recorded yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Date', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Scan Type', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Duration', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Result', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Findings', 'argus-wordpress-defence' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $scan_history as $run ) : ?>
|
||||
<?php
|
||||
$duration_secs = max( 0, strtotime( $run->finished_at . ' UTC' ) - strtotime( $run->started_at . ' UTC' ) );
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( wp_date( 'd M Y, H:i', strtotime( $run->started_at . ' UTC' ) ) ); ?></td>
|
||||
<td><?php echo esc_html( $scan_type_labels[ $run->scan_type ] ?? ucfirst( $run->scan_type ) ); ?></td>
|
||||
<td><?php echo esc_html( $duration_secs < 1 ? '<1s' : $duration_secs . 's' ); ?></td>
|
||||
<td><span style="color:<?php echo 'clean' === $run->result ? 'var(--emerald)' : 'var(--rose)'; ?>;font-weight:600;"><?php echo 'clean' === $run->result ? esc_html__( 'Clean', 'argus-wordpress-defence' ) : esc_html__( 'Issues Found', 'argus-wordpress-defence' ); ?></span></td>
|
||||
<td><?php echo esc_html( number_format_i18n( $run->findings_count ) ); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$page = $history_page;
|
||||
$total_pages = $history_total_pages;
|
||||
$base_url = remove_query_arg( 'scan_paged' );
|
||||
$argus_page_param = 'scan_paged';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
unset( $argus_page_param );
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-scan-grid">
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'File Integrity', 'argus-wordpress-defence' ); ?></h2>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Status', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="v" style="color:<?php echo $integrity_open > 0 ? 'var(--rose)' : 'var(--emerald)'; ?>"><?php echo $integrity_open > 0 ? esc_html__( 'ISSUES FOUND', 'argus-wordpress-defence' ) : esc_html__( 'VERIFIED', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Open findings', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="v"><?php echo esc_html( number_format_i18n( $integrity_open ) ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Last full scan', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="v"><?php echo $scan_status['last_full_scan'] ? esc_html( human_time_diff( $scan_status['last_full_scan'] ) . ' ' . __( 'ago', 'argus-wordpress-defence' ) ) : esc_html__( 'Never', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Files scanned', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="v"><?php echo esc_html( number_format_i18n( $scan_status['files_scanned'] ) ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Next scheduled scan', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="v"><?php echo $scan_status['next_scan'] ? esc_html( human_time_diff( $scan_status['next_scan'] ) ) : esc_html__( 'Not scheduled', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Malware', 'argus-wordpress-defence' ); ?></h2>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Status', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="v" style="color:<?php echo $malware_open > 0 ? 'var(--rose)' : 'var(--emerald)'; ?>"><?php echo $malware_open > 0 ? esc_html__( 'THREATS FOUND', 'argus-wordpress-defence' ) : esc_html__( 'CLEAN', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Open findings', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="v"><?php echo esc_html( number_format_i18n( $malware_open ) ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Uploads PHP-execution lock', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php if ( 'active' === $lockdown_status ) : ?>
|
||||
<span class="v" style="color:var(--emerald)"><?php esc_html_e( 'ACTIVE', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php elseif ( 'not_writable' === $lockdown_status || 'failed_write' === $lockdown_status ) : ?>
|
||||
<span class="v" style="color:var(--rose)"><?php esc_html_e( 'NOT ACTIVE', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span class="v" style="color:var(--faint)"><?php esc_html_e( 'UNKNOWN', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ( 'active' !== $lockdown_status ) : ?>
|
||||
<p style="color:var(--amber);font-size:11.5px;margin:10px 0 0;line-height:1.5;">
|
||||
<?php
|
||||
if ( 'not_writable' === $lockdown_status || 'failed_write' === $lockdown_status ) {
|
||||
esc_html_e( 'ARGUS could not write the protective .htaccess rule -- wp-content/uploads is not writable by PHP on this host. This is a real, unmitigated gap: fix directory permissions so ARGUS can lock uploads against PHP execution.', 'argus-wordpress-defence' );
|
||||
} else {
|
||||
esc_html_e( 'Status not yet determined -- a scan has not run since this check was added.', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<div class="argus-wpd-scan-fact-row">
|
||||
<span class="k"><?php esc_html_e( 'Quarantined items', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="v"><?php echo esc_html( number_format_i18n( $quarantine_review_count ) ); ?></span>
|
||||
</div>
|
||||
<p style="color:var(--faint);font-size:12px;margin:14px 0 0;line-height:1.6;">
|
||||
<?php esc_html_e( 'A PHP file found in wp-content/uploads is moved into a protected quarantine store on sight, and the uploads directory is locked against PHP execution entirely -- the same technique used by other established WordPress security plugins.', 'argus-wordpress-defence' ); ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-quarantine' ) ); ?>" style="color:var(--cyan);font-weight:600;text-decoration:none"><?php esc_html_e( 'Manage quarantine', 'argus-wordpress-defence' ); ?> →</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( $malware_open > 0 || $integrity_open > 0 ) : ?>
|
||||
<div class="argus-wpd-panel">
|
||||
<p style="margin:0;font-size:13px;color:var(--muted);">
|
||||
<?php esc_html_e( 'Scanner findings appear on the', 'argus-wordpress-defence' ); ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-findings' ) ); ?>" style="color:var(--cyan);font-weight:600;text-decoration:none"><?php esc_html_e( 'Findings page', 'argus-wordpress-defence' ); ?></a>,
|
||||
<?php esc_html_e( 'with full explanations and one-click remediation where available.', 'argus-wordpress-defence' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'settings';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Settings', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 24px;"><?php esc_html_e( 'Start in Monitor mode, review findings, then switch to Block once you trust legitimate traffic is not being flagged.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<?php if ( ! empty( $saved ) ) : ?>
|
||||
<div class="notice notice-success" style="padding:14px 18px;margin:0 0 20px;"><p style="margin:0"><?php esc_html_e( 'Settings saved.', 'argus-wordpress-defence' ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $template_applied ) ) : ?>
|
||||
<div class="notice notice-success" style="padding:14px 18px;margin:0 0 20px;"><p style="margin:0">
|
||||
<?php
|
||||
printf(
|
||||
|
||||
esc_html__( '"%s" protection template applied. You can still fine-tune anything below.', 'argus-wordpress-defence' ),
|
||||
esc_html( $template_applied )
|
||||
);
|
||||
?>
|
||||
</p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $templates ) ) : ?>
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Site Type', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 16px;"><?php esc_html_e( 'A starting point, not a lock-in -- applying a template sets sensible defaults below, which you can still hand-tune afterward.', 'argus-wordpress-defence' ); ?></p>
|
||||
<div class="argus-wpd-template-grid">
|
||||
<?php foreach ( $templates as $key => $template ) : ?>
|
||||
<div class="argus-wpd-template-card<?php echo $active_template === $key ? ' active' : ''; ?>">
|
||||
<div class="argus-wpd-template-title">
|
||||
<?php echo esc_html( $template['label'] ); ?>
|
||||
<?php if ( $recommended_template === $key ) : ?><span class="argus-wpd-template-badge"><?php esc_html_e( 'Recommended -- store plugin detected', 'argus-wordpress-defence' ); ?></span><?php endif; ?>
|
||||
<?php if ( $active_template === $key ) : ?><span class="argus-wpd-template-badge active"><?php esc_html_e( 'Currently applied', 'argus-wordpress-defence' ); ?></span><?php endif; ?>
|
||||
</div>
|
||||
<p class="argus-wpd-template-desc"><?php echo esc_html( $template['description'] ); ?></p>
|
||||
<form method="post" onsubmit="return confirm('<?php echo esc_js( sprintf( __( 'Apply the "%s" template? This will overwrite your current Protection Mode and Engine settings below.', 'argus-wordpress-defence' ), $template['label'] ) ); ?>')">
|
||||
<?php wp_nonce_field( 'argus_wpd_apply_template', 'argus_wpd_apply_template_nonce' ); ?>
|
||||
<input type="hidden" name="template" value="<?php echo esc_attr( $key ); ?>" />
|
||||
<button type="submit" class="button<?php echo $active_template === $key ? '' : ' button-primary'; ?>"><?php echo $active_template === $key ? esc_html__( 'Re-apply', 'argus-wordpress-defence' ) : esc_html__( 'Apply', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_save_settings', 'argus_wpd_settings_nonce' ); ?>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Protection Mode', 'argus-wordpress-defence' ); ?></th>
|
||||
<td>
|
||||
<select name="mode">
|
||||
<option value="monitor" <?php selected( $settings['mode'], 'monitor' ); ?>><?php esc_html_e( 'Monitor -- detect and log, never block', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="block" <?php selected( $settings['mode'], 'block' ); ?>><?php esc_html_e( 'Block -- normal production protection', 'argus-wordpress-defence' ); ?></option>
|
||||
<option value="strict" <?php selected( $settings['mode'], 'strict' ); ?>><?php esc_html_e( 'Strict -- aggressive protection', 'argus-wordpress-defence' ); ?></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Engines', 'argus-wordpress-defence' ); ?></th>
|
||||
<td>
|
||||
<label><input type="checkbox" name="waf_enabled" <?php checked( $settings['waf_enabled'] ); ?> /> <?php esc_html_e( 'Local WAF', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="checkbox" name="login_protection_enabled" <?php checked( $settings['login_protection_enabled'] ); ?> /> <?php esc_html_e( 'Login / brute-force protection', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="checkbox" name="xmlrpc_block_pingback" <?php checked( $settings['xmlrpc_block_pingback'] ); ?> /> <?php esc_html_e( 'Block XML-RPC pingback (recommended)', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="checkbox" name="rest_api_protection_enabled" <?php checked( $settings['rest_api_protection_enabled'] ); ?> /> <?php esc_html_e( 'REST API abuse protection', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="checkbox" name="integrity_scan_enabled" <?php checked( $settings['integrity_scan_enabled'] ); ?> /> <?php esc_html_e( 'File integrity scanning', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="checkbox" name="malware_scan_enabled" <?php checked( $settings['malware_scan_enabled'] ); ?> /> <?php esc_html_e( 'Malware scanning', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="checkbox" name="upload_scan_enabled" <?php checked( $settings['upload_scan_enabled'] ); ?> /> <?php esc_html_e( 'Scan file uploads before they reach your website', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="checkbox" name="vuln_intel_enabled" <?php checked( $settings['vuln_intel_enabled'] ); ?> /> <?php esc_html_e( 'Vulnerability intelligence', 'argus-wordpress-defence' ); ?></label><br>
|
||||
<label><input type="checkbox" name="geoip_rir_enabled" <?php checked( $settings['geoip_rir_enabled'] ); ?> /> <?php esc_html_e( 'Self-hosted GeoIP (country flags/statistics)', 'argus-wordpress-defence' ); ?></label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if ( null !== $geoip_status ) : ?>
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'GeoIP Database', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 16px;"><?php esc_html_e( 'Self-hosted, same public RIR delegation-file data source argus-appliance itself uses -- no MaxMind account, no manual step. Refreshes automatically once a day; nothing to click.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php if ( $geoip_status['range_count'] > 0 ) : ?>
|
||||
<p style="font-size:13px;color:var(--text);margin:0 0 6px;">
|
||||
<?php
|
||||
printf(
|
||||
|
||||
esc_html__( '%1$s IPv4 ranges loaded -- last refreshed %2$s ago.', 'argus-wordpress-defence' ),
|
||||
esc_html( number_format_i18n( $geoip_status['range_count'] ) ),
|
||||
esc_html( human_time_diff( strtotime( $geoip_status['last_refresh'] . ' UTC' ) ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php elseif ( $geoip_status['cursor'] > 0 ) : ?>
|
||||
<p style="font-size:13px;color:var(--muted);margin:0 0 6px;">
|
||||
<?php
|
||||
printf(
|
||||
|
||||
esc_html__( 'First build in progress -- %1$d of %2$d sources loaded so far, continuing automatically.', 'argus-wordpress-defence' ),
|
||||
(int) $geoip_status['cursor'],
|
||||
5
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php else : ?>
|
||||
<p style="font-size:13px;color:var(--muted);margin:0 0 6px;"><?php esc_html_e( 'Not built yet -- the first daily refresh will populate this automatically, no action needed.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $geoip_status['last_error'] ) ) : ?>
|
||||
<p style="font-size:12.5px;color:var(--amber);margin:6px 0 0;"><?php echo esc_html( $geoip_status['last_error'] ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Automatic Security Updates', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="font-size:13px;color:var(--emerald);margin:0 0 6px;display:flex;align-items:center;gap:8px;"><span class="argus-wpd-status-chip chip-emerald" style="padding:2px 10px;"><span class="dot"></span><span class="state"><?php echo esc_html( strtoupper( Argus_Auto_Update::status()['label'] ) ); ?></span></span></p>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:8px 0 0 0 0 16px;"><?php echo esc_html( Argus_Auto_Update::status()['detail'] ); ?></p>
|
||||
<?php $update_status = Argus_Update_Client::status(); ?>
|
||||
<table class="widefat" style="border:none;background:transparent;margin-top:14px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="border:none;padding:6px 0;color:var(--faint);font-size:12px;width:160px;"><?php esc_html_e( 'Current Version', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:6px 0;color:var(--text);font-size:13px;font-weight:600;"><?php echo esc_html( $update_status['current_version'] ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:none;padding:6px 0;color:var(--faint);font-size:12px;"><?php esc_html_e( 'Update Status', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:6px 0;color:var(--text);font-size:13px;">
|
||||
<?php if ( ! empty( $update_status['pending']['version'] ) ) : ?>
|
||||
<?php echo esc_html( sprintf( __( 'Update to %s available', 'argus-wordpress-defence' ), $update_status['pending']['version'] ) ); ?>
|
||||
<?php elseif ( empty( $update_status['configured'] ) ) : ?>
|
||||
<?php esc_html_e( 'Update channel not configured', 'argus-wordpress-defence' ); ?>
|
||||
<?php else : ?>
|
||||
<?php esc_html_e( 'Up to date', 'argus-wordpress-defence' ); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:none;padding:6px 0;color:var(--faint);font-size:12px;"><?php esc_html_e( 'Last Successful Update', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:6px 0;color:var(--text);font-size:13px;">
|
||||
<?php
|
||||
if ( ! empty( $update_status['last_success']['installed_at'] ) ) {
|
||||
echo esc_html( sprintf( '%s (%s)', $update_status['last_success']['version'], wp_date( 'd M Y, H:i', strtotime( $update_status['last_success']['installed_at'] . ' UTC' ) ) ) );
|
||||
} else {
|
||||
esc_html_e( 'None yet', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ( ! empty( $update_status['last_failure']['message'] ) ) : ?>
|
||||
<tr>
|
||||
<td style="border:none;padding:6px 0;color:var(--faint);font-size:12px;"><?php esc_html_e( 'Last Failed Update', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:6px 0;color:var(--rose);font-size:13px;"><?php echo esc_html( $update_status['last_failure']['message'] ); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php if ( ! empty( $update_check_result ) ) : ?>
|
||||
<p style="font-size:12.5px;margin:12px 0 0;color:<?php echo ! empty( $update_check_result['success'] ) ? 'var(--emerald)' : 'var(--rose)'; ?>;"><?php echo esc_html( $update_check_result['message'] ); ?></p>
|
||||
<?php endif; ?>
|
||||
<form method="post" style="margin-top:14px;">
|
||||
<?php wp_nonce_field( 'argus_wpd_check_updates', 'argus_wpd_check_updates_nonce' ); ?>
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Check for Updates Now', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Website Acceleration', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 12px;"><?php esc_html_e( 'Cache & Performance now has its own dedicated page -- speed up your website, reduce load, and see what\'s being accelerated.', 'argus-wordpress-defence' ); ?></p>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-cache' ) ); ?>" class="button button-primary"><?php esc_html_e( 'Open Cache & Performance', 'argus-wordpress-defence' ); ?></a>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'IP Whitelist', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 16px;"><?php esc_html_e( 'Whitelisted IPs always pass -- WAF, login protection, and bans never apply to them. Use for your own office/VPN IP, monitoring services, etc.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<?php $exceptions = Argus_Settings::get( 'exceptions', array() ); ?>
|
||||
<?php if ( empty( $exceptions ) ) : ?>
|
||||
<p class="argus-wpd-empty" style="padding:10px 0;"><?php esc_html_e( 'No exceptions yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<?php foreach ( $exceptions as $exception ) : ?>
|
||||
<?php if ( 'ip' !== ( $exception['type'] ?? '' ) ) { continue; } ?>
|
||||
<div class="argus-wpd-exception-row">
|
||||
<code><?php echo esc_html( $exception['value'] ); ?></code>
|
||||
<span class="note"><?php echo esc_html( $exception['note'] ?? '' ); ?></span>
|
||||
<span class="added"><?php echo esc_html( $exception['added_at'] ?? '' ); ?></span>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'argus_wpd_remove_exception', 'argus_wpd_remove_exception_nonce' ); ?>
|
||||
<input type="hidden" name="exception_value" value="<?php echo esc_attr( $exception['value'] ); ?>" />
|
||||
<button type="submit" class="button"><?php esc_html_e( 'Remove', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" class="argus-wpd-inline-form" style="margin-top:16px;">
|
||||
<?php wp_nonce_field( 'argus_wpd_add_exception', 'argus_wpd_add_exception_nonce' ); ?>
|
||||
<input type="text" name="exception_ip" placeholder="203.0.113.10" required pattern="^[0-9a-fA-F:.]+$" />
|
||||
<input type="text" name="exception_note" placeholder="<?php esc_attr_e( 'Note (optional)', 'argus-wordpress-defence' ); ?>" />
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e( 'Add to Whitelist', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'threats';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$category_labels = array(
|
||||
'waf' => __( 'WAF (SQLi/XSS/RCE/etc.)', 'argus-wordpress-defence' ),
|
||||
'integrity' => __( 'File Integrity', 'argus-wordpress-defence' ),
|
||||
'malware' => __( 'Malware', 'argus-wordpress-defence' ),
|
||||
'vulnerability' => __( 'Vulnerability', 'argus-wordpress-defence' ),
|
||||
'account' => __( 'Account / Login', 'argus-wordpress-defence' ),
|
||||
'correlation' => __( 'Correlated Campaign', 'argus-wordpress-defence' ),
|
||||
'rest_inventory' => __( 'REST API Inventory', 'argus-wordpress-defence' ),
|
||||
'ajax_inventory' => __( 'AJAX Inventory', 'argus-wordpress-defence' ),
|
||||
);
|
||||
|
||||
$category_display = array();
|
||||
foreach ( $category_counts as $category => $count ) {
|
||||
$category_display[ $category_labels[ $category ] ?? ucfirst( $category ) ] = $count;
|
||||
}
|
||||
|
||||
$action_labels = array(
|
||||
'block' => __( 'Blocked', 'argus-wordpress-defence' ),
|
||||
'challenge' => __( 'Challenged', 'argus-wordpress-defence' ),
|
||||
'rate_limit' => __( 'Rate Limited', 'argus-wordpress-defence' ),
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Threats', 'argus-wordpress-defence' ); ?></h1>
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 24px;">
|
||||
<?php esc_html_e( 'Recent malicious activity detected and blocked by ARGUS.', 'argus-wordpress-defence' ); ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-findings' ) ); ?>" style="color:var(--cyan);font-weight:600;text-decoration:none"><?php esc_html_e( 'View all findings', 'argus-wordpress-defence' ); ?></a>
|
||||
</p>
|
||||
|
||||
<div class="argus-wpd-panel argus-wpd-live-chart-panel">
|
||||
<h2><?php esc_html_e( 'Live Threat Activity · Blocked / Min', 'argus-wordpress-defence' ); ?></h2>
|
||||
<?php
|
||||
$blocked_total = array_sum( wp_list_pluck( $blocked_per_minute, 'value' ) );
|
||||
if ( $blocked_total <= 0 ) :
|
||||
?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No blocked activity in the last 30 minutes.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<div class="argus-wpd-chart-wrap">
|
||||
<?php echo Argus_Charts::area_chart( $blocked_per_minute, 900, 170 ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div id="argus-wpd-live-feed-rows" class="argus-wpd-live-feed-rows"
|
||||
data-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
|
||||
data-nonce="<?php echo esc_attr( $live_feed_nonce ); ?>">
|
||||
<?php if ( empty( $latest_blocked ) ) : ?>
|
||||
<p class="argus-wpd-empty" data-empty-placeholder="1"><?php esc_html_e( 'No blocked events recorded yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<?php foreach ( $latest_blocked as $row ) : ?>
|
||||
<div class="argus-wpd-live-feed-row" data-key="<?php echo esc_attr( md5( $row['ip'] . '|' . $row['created_at'] . '|' . $row['type'] ) ); ?>">
|
||||
<span class="argus-wpd-live-feed-time"><?php echo esc_html( Argus_Console_Stats::live_feed_time_label( $row['created_at'] ) ); ?></span>
|
||||
<span class="argus-wpd-live-feed-desc"><?php echo esc_html( $row['desc'] ); ?></span>
|
||||
<span class="argus-wpd-live-feed-action">BLOCKED</span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Attack Types', 'argus-wordpress-defence' ); ?></h2>
|
||||
<?php if ( empty( $category_display ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No findings recorded yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<div class="argus-wpd-donut-row">
|
||||
<?php echo Argus_Charts::donut( $category_display ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
<?php echo Argus_Charts::legend( $category_display ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Recent Activity', 'argus-wordpress-defence' ); ?></h2>
|
||||
<?php if ( empty( $recent_activity ) ) : ?>
|
||||
<p class="argus-wpd-empty"><?php esc_html_e( 'No enforcement-relevant activity recorded yet.', 'argus-wordpress-defence' ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Time', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Source IP', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Type', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Action', 'argus-wordpress-defence' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $recent_activity as $row ) : ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( human_time_diff( strtotime( $row->created_at . ' UTC' ) ) ); ?> <?php esc_html_e( 'ago', 'argus-wordpress-defence' ); ?></td>
|
||||
<td><span class="argus-wpd-flag" title="<?php echo esc_attr( Argus_GeoIP::label( $row->ip ) ); ?>"><?php echo esc_html( Argus_GeoIP::icon( $row->ip ) ); ?></span> <code><?php echo esc_html( $row->ip ); ?></code></td>
|
||||
<td><?php echo esc_html( $row->label ); ?></td>
|
||||
<td><?php echo esc_html( $action_labels[ $row->action ] ?? ucfirst( $row->action ) ); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$page = $activity_page;
|
||||
$total_pages = $activity_total_pages;
|
||||
$base_url = remove_query_arg( 'activity_paged' );
|
||||
$argus_page_param = 'activity_paged';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
unset( $argus_page_param );
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
// Vanilla JS only, no external library (matches this plugin's
|
||||
// zero-JS-dependency baseline elsewhere) -- polls the live feed and
|
||||
// re-renders only when the newest row actually changed, so a quiet
|
||||
// site never flickers/re-animates for no reason.
|
||||
var container = document.getElementById( 'argus-wpd-live-feed-rows' );
|
||||
if ( ! container ) {
|
||||
return;
|
||||
}
|
||||
var ajaxUrl = container.getAttribute( 'data-ajax-url' );
|
||||
var nonce = container.getAttribute( 'data-nonce' );
|
||||
var lastTopKey = null;
|
||||
var reduceMotion = window.matchMedia && window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches;
|
||||
|
||||
function rowHtml( row ) {
|
||||
var el = document.createElement( 'div' );
|
||||
el.className = 'argus-wpd-live-feed-row';
|
||||
el.setAttribute( 'data-key', row.key );
|
||||
if ( ! reduceMotion ) {
|
||||
el.classList.add( 'is-entering' );
|
||||
}
|
||||
el.innerHTML =
|
||||
'<span class="argus-wpd-live-feed-time">' + row.time + '</span>' +
|
||||
'<span class="argus-wpd-live-feed-desc">' + row.desc + '</span>' +
|
||||
'<span class="argus-wpd-live-feed-action">BLOCKED</span>';
|
||||
return el;
|
||||
}
|
||||
|
||||
function poll() {
|
||||
var body = 'action=argus_wpd_live_feed&nonce=' + encodeURIComponent( nonce );
|
||||
fetch( ajaxUrl, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: body,
|
||||
} )
|
||||
.then( function ( r ) { return r.json(); } )
|
||||
.then( function ( json ) {
|
||||
if ( ! json || ! json.success || ! Array.isArray( json.data ) || 0 === json.data.length ) {
|
||||
return;
|
||||
}
|
||||
var rows = json.data;
|
||||
if ( rows[0].key === lastTopKey ) {
|
||||
return; // Nothing new -- no reload, no re-animation.
|
||||
}
|
||||
lastTopKey = rows[0].key;
|
||||
|
||||
var placeholder = container.querySelector( '[data-empty-placeholder]' );
|
||||
if ( placeholder ) {
|
||||
placeholder.remove();
|
||||
}
|
||||
|
||||
var existingKeys = {};
|
||||
Array.prototype.forEach.call( container.children, function ( el ) {
|
||||
existingKeys[ el.getAttribute( 'data-key' ) ] = true;
|
||||
} );
|
||||
|
||||
rows.forEach( function ( row ) {
|
||||
if ( existingKeys[ row.key ] ) {
|
||||
return;
|
||||
}
|
||||
container.insertBefore( rowHtml( row ), container.firstChild );
|
||||
} );
|
||||
|
||||
while ( container.children.length > 10 ) {
|
||||
container.removeChild( container.lastChild );
|
||||
}
|
||||
} )
|
||||
.catch( function () {
|
||||
// Silent -- a transient polling failure must never surface
|
||||
// as a visible error to the customer; the next tick just
|
||||
// tries again.
|
||||
} );
|
||||
}
|
||||
|
||||
setInterval( poll, 5000 );
|
||||
})();
|
||||
</script>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$argus_active_page = 'vulnerabilities';
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
$type_labels = array(
|
||||
'core' => __( 'Core', 'argus-wordpress-defence' ),
|
||||
'plugin' => __( 'Plugin', 'argus-wordpress-defence' ),
|
||||
'theme' => __( 'Theme', 'argus-wordpress-defence' ),
|
||||
);
|
||||
|
||||
$status_display = array(
|
||||
Argus_Vuln_Intel::STATUS_CLEAN => array( 'icon' => '✓', 'label' => __( 'No Known Vulnerabilities', 'argus-wordpress-defence' ), 'color' => 'var(--emerald)' ),
|
||||
Argus_Vuln_Intel::STATUS_PENDING => array( 'icon' => '⚠', 'label' => __( 'Check Pending', 'argus-wordpress-defence' ), 'color' => 'var(--amber)' ),
|
||||
Argus_Vuln_Intel::STATUS_UNAVAILABLE => array( 'icon' => '⚠', 'label' => __( 'Intelligence Temporarily Unavailable', 'argus-wordpress-defence' ), 'color' => 'var(--amber)' ),
|
||||
Argus_Vuln_Intel::STATUS_VULNERABLE => array( 'icon' => '🔴', 'label' => __( 'Vulnerability Detected', 'argus-wordpress-defence' ), 'color' => 'var(--rose)' ),
|
||||
);
|
||||
|
||||
$severity_labels = array(
|
||||
'critical' => __( 'Critical', 'argus-wordpress-defence' ),
|
||||
'high' => __( 'High', 'argus-wordpress-defence' ),
|
||||
'medium' => __( 'Medium', 'argus-wordpress-defence' ),
|
||||
'low' => __( 'Low', 'argus-wordpress-defence' ),
|
||||
);
|
||||
|
||||
$date_format = 'd M Y, H:i';
|
||||
$last_check_display = $vuln_status['last_check'] ? wp_date( $date_format, strtotime( $vuln_status['last_check'] . ' UTC' ) ) : '';
|
||||
$next_check_display = $vuln_status['next_check'] ? wp_date( $date_format, strtotime( $vuln_status['next_check'] . ' UTC' ) ) : '';
|
||||
?>
|
||||
|
||||
<h1 class="argus-wpd-page-title"><?php esc_html_e( 'Vulnerability Protection', 'argus-wordpress-defence' ); ?></h1>
|
||||
|
||||
<div class="argus-wpd-status-row">
|
||||
<div class="argus-wpd-status-chip <?php echo 'active' === $vuln_status['protection'] ? 'chip-emerald' : 'chip-off'; ?>">
|
||||
<span class="dot"></span>
|
||||
<span class="state"><?php echo 'active' === $vuln_status['protection'] ? esc_html__( 'ACTIVE', 'argus-wordpress-defence' ) : esc_html__( 'STARTING...', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 20px;"><?php esc_html_e( 'ARGUS checks WordPress, installed plugins and themes for known security issues.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<div class="argus-wpd-metric-grid">
|
||||
<?php foreach ( $severity_labels as $key => $label ) : ?>
|
||||
<div class="argus-wpd-metric-card">
|
||||
<div class="argus-wpd-metric-label"><?php echo esc_html( $label ); ?></div>
|
||||
<div class="argus-wpd-metric-value" style="color:<?php echo esc_attr( array( 'critical' => 'var(--rose)', 'high' => 'var(--orange)', 'medium' => 'var(--amber)', 'low' => 'var(--cyan)' )[ $key ] ); ?>"><?php echo esc_html( number_format_i18n( $severity_counts[ $key ] ) ); ?></div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<p style="font-size:14px;color:var(--text);margin:0 0 20px;"><?php esc_html_e( 'ARGUS Defence automatically checks WordPress core, installed plugins, and themes against continuously updated vulnerability intelligence.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
<table class="widefat" style="border:none;background:transparent;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="border:none;padding:10px 0;color:var(--faint);font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;width:45%;"><?php esc_html_e( 'Last Vulnerability Check', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:10px 0;font-size:14px;color:var(--text);font-weight:600;"><?php echo $last_check_display ? esc_html( $last_check_display ) : esc_html__( 'Pending', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:none;padding:10px 0;color:var(--faint);font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;"><?php esc_html_e( 'Next Vulnerability Check', 'argus-wordpress-defence' ); ?></td>
|
||||
<td style="border:none;padding:10px 0;font-size:14px;color:var(--text);font-weight:600;"><?php echo $next_check_display ? esc_html( $next_check_display ) : esc_html__( 'Pending', 'argus-wordpress-defence' ); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Type', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Component', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Installed Version', 'argus-wordpress-defence' ); ?></th>
|
||||
<th><?php esc_html_e( 'Status', 'argus-wordpress-defence' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $vuln_status['components'] as $component ) : ?>
|
||||
<?php $display = $status_display[ $component['status'] ] ?? $status_display[ Argus_Vuln_Intel::STATUS_PENDING ]; ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( $type_labels[ $component['type'] ] ?? ucfirst( $component['type'] ) ); ?></td>
|
||||
<td><?php echo esc_html( $component['name'] ); ?></td>
|
||||
<td><code><?php echo esc_html( $component['installed_version'] ?: '—' ); ?></code></td>
|
||||
<td>
|
||||
<span style="color:<?php echo esc_attr( $display['color'] ); ?>;font-weight:600;"><?php echo $display['icon']; // phpcs:ignore WordPress.Security.EscapeOutput ?> <?php echo esc_html( $display['label'] ); ?></span>
|
||||
<?php if ( Argus_Vuln_Intel::STATUS_VULNERABLE === $component['status'] ) : ?>
|
||||
<div style="margin-top:8px;font-size:12.5px;color:var(--faint);line-height:1.8;">
|
||||
<div><?php esc_html_e( 'Severity:', 'argus-wordpress-defence' ); ?> <strong style="color:var(--text);"><?php echo esc_html( $severity_labels[ $component['severity'] ] ?? ucfirst( (string) $component['severity'] ) ); ?></strong></div>
|
||||
<?php if ( $component['fixed_in'] ) : ?>
|
||||
<div><?php esc_html_e( 'Safe Version:', 'argus-wordpress-defence' ); ?> <strong style="color:var(--text);"><?php echo esc_html( $component['fixed_in'] ); ?></strong></div>
|
||||
<div><?php esc_html_e( 'Recommended Action:', 'argus-wordpress-defence' ); ?> <strong style="color:var(--text);"><?php echo esc_html( sprintf( __( 'Update to %s', 'argus-wordpress-defence' ), $component['fixed_in'] ) ); ?></strong></div>
|
||||
<?php else : ?>
|
||||
<div><?php esc_html_e( 'Recommended Action:', 'argus-wordpress-defence' ); ?> <strong style="color:var(--text);"><?php esc_html_e( 'Deactivate the affected component until a fix is available', 'argus-wordpress-defence' ); ?></strong></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$page = $components_page;
|
||||
$total_pages = $components_total_pages;
|
||||
$base_url = remove_query_arg( 'paged' );
|
||||
include ARGUS_WPD_DIR . 'admin/views/partials/pagination.php';
|
||||
?>
|
||||
</div>
|
||||
|
||||
<p style="color:var(--muted);font-size:13px;margin:0 0 24px;"><?php esc_html_e( 'A detected vulnerability with a remediation action also appears as a finding on the', 'argus-wordpress-defence' ); ?> <a href="<?php echo esc_url( admin_url( 'admin.php?page=argus-wpd-findings' ) ); ?>" style="color:var(--cyan);font-weight:600;text-decoration:none"><?php esc_html_e( 'Findings page', 'argus-wordpress-defence' ); ?></a>.</p>
|
||||
|
||||
<?php include ARGUS_WPD_DIR . 'admin/views/partials/footer.php'; ?>
|
||||
Reference in New Issue
Block a user