| 1 |
<?php |
| 2 |
/** |
| 3 |
* Process functions |
| 4 |
* |
| 5 |
* @package WPVulnerability |
| 6 |
* |
| 7 |
* @version 2.0.0 |
| 8 |
*/ |
| 9 |
|
| 10 |
defined( 'ABSPATH' ) || die( 'No script kiddies please!' ); |
| 11 |
|
| 12 |
/** |
| 13 |
* Load the settings to be available always. |
| 14 |
* |
| 15 |
* @since 2.0.0 |
| 16 |
* |
| 17 |
* @return array|false An array containing the WPVulnerability settings if they exist, or false if they don't. |
| 18 |
*/ |
| 19 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config' ); |
| 20 |
$wpvulnerability_analyze = get_option( 'wpvulnerability-analyze' ); |
| 21 |
|
| 22 |
/** |
| 23 |
* Enqueues the WPVulnerability admin CSS file on WPVulnerability admin pages. |
| 24 |
* |
| 25 |
* @since 2.0.0 |
| 26 |
* |
| 27 |
* @return void |
| 28 |
*/ |
| 29 |
function wpvulnerability_admin_enqueue_scripts() { |
| 30 |
wp_enqueue_style( |
| 31 |
'wpvulnerability-admin', |
| 32 |
WPVULNERABILITY_PLUGIN_URL . 'assets/admin.css', |
| 33 |
array(), |
| 34 |
WPVULNERABILITY_PLUGIN_VERSION |
| 35 |
); |
| 36 |
|
| 37 |
wp_enqueue_script( |
| 38 |
'wpvulnerability-admin-js', |
| 39 |
WPVULNERABILITY_PLUGIN_URL . 'assets/admin.js', |
| 40 |
array( 'jquery' ), |
| 41 |
WPVULNERABILITY_PLUGIN_VERSION, |
| 42 |
true |
| 43 |
); |
| 44 |
} |
| 45 |
add_action( 'admin_enqueue_scripts', 'wpvulnerability_admin_enqueue_scripts' ); |
| 46 |
|
| 47 |
/** |
| 48 |
* Reset the data. |
| 49 |
* |
| 50 |
* This function checks for a reset request and, if valid, calls the function to update the database data. |
| 51 |
* |
| 52 |
* @since 3.0.0 |
| 53 |
* |
| 54 |
* @return void |
| 55 |
*/ |
| 56 |
if ( isset( $_POST['wpvulnerability_reset'] ) && check_admin_referer( 'wpvulnerability_reset_action', 'wpvulnerability_reset_nonce' ) ) { |
| 57 |
|
| 58 |
if ( current_user_can( 'manage_options' ) ) { |
| 59 |
// Calls the reset function. |
| 60 |
wpvulnerability_update_database_data(); |
| 61 |
|
| 62 |
// Set a transient message for success. |
| 63 |
set_transient( 'wpvulnerability_message_manual_success', __( 'Data from source has been reloaded.', 'wpvulnerability' ), 10 ); |
| 64 |
} else { |
| 65 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to reload data.', 'wpvulnerability' ), 10 ); |
| 66 |
} |
| 67 |
} |
| 68 |
|
| 69 |
/** |
| 70 |
* Send a test email. |
| 71 |
* |
| 72 |
* This code checks for a request to send a test email and executes the notification function. |
| 73 |
* |
| 74 |
* @since 3.0.0 |
| 75 |
* |
| 76 |
* @return void |
| 77 |
*/ |
| 78 |
if ( isset( $_POST['wpvulnerability_email'] ) && check_admin_referer( 'wpvulnerability_email_action', 'wpvulnerability_email_nonce' ) ) { |
| 79 |
|
| 80 |
// Include necessary files if the notification function is not already defined. |
| 81 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-core.php'; |
| 82 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-plugins.php'; |
| 83 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-themes.php'; |
| 84 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php'; |
| 85 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-process.php'; |
| 86 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-notifications.php'; |
| 87 |
|
| 88 |
// Calls the notifications function, forced. |
| 89 |
if ( current_user_can( 'manage_options' ) ) { |
| 90 |
$wpvulnerability_wpmail = wpvulnerability_execute_notification( true ); |
| 91 |
|
| 92 |
if ( $wpvulnerability_wpmail ) { |
| 93 |
set_transient( 'wpvulnerability_message_manual_success', __( 'Test email has been sent.', 'wpvulnerability' ), 10 ); |
| 94 |
} else { |
| 95 |
set_transient( 'wpvulnerability_message_manual_error', __( 'Test email has failed. Please, check your email settings.', 'wpvulnerability' ), 10 ); |
| 96 |
} |
| 97 |
} else { |
| 98 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to send test emails.', 'wpvulnerability' ), 10 ); |
| 99 |
} |
| 100 |
} |
| 101 |
|
| 102 |
/** |
| 103 |
* Repairs scheduled cron events for the current site. |
| 104 |
* |
| 105 |
* @since 4.3.0 |
| 106 |
* |
| 107 |
* @return void |
| 108 |
*/ |
| 109 |
if ( isset( $_POST['wpvulnerability_repair_cron'] ) && check_admin_referer( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ) ) { |
| 110 |
if ( current_user_can( 'manage_options' ) ) { |
| 111 |
$wpvulnerability_cron_config = is_array( $wpvulnerability_settings ) ? $wpvulnerability_settings : array(); |
| 112 |
wpvulnerability_repair_cron_events( $wpvulnerability_cron_config ); |
| 113 |
set_transient( 'wpvulnerability_message_manual_success', __( 'WPVulnerability cron events have been repaired.', 'wpvulnerability' ), 10 ); |
| 114 |
} else { |
| 115 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to repair cron events.', 'wpvulnerability' ), 10 ); |
| 116 |
} |
| 117 |
} |
| 118 |
|
| 119 |
/** |
| 120 |
* Deletes all stored API logs when requested. |
| 121 |
* |
| 122 |
* @since 4.3.0 |
| 123 |
*/ |
| 124 |
if ( isset( $_POST['wpvulnerability_delete_logs'] ) && check_admin_referer( 'wpvulnerability_delete_logs_action', 'wpvulnerability_delete_logs_nonce' ) ) { |
| 125 |
if ( current_user_can( 'manage_options' ) ) { |
| 126 |
wpvulnerability_delete_all_logs(); |
| 127 |
set_transient( 'wpvulnerability_message_manual_success', __( 'All logs have been deleted.', 'wpvulnerability' ), 10 ); |
| 128 |
} else { |
| 129 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to delete logs.', 'wpvulnerability' ), 10 ); |
| 130 |
} |
| 131 |
} |
| 132 |
|
| 133 |
/** |
| 134 |
* Fully resets plugin data, settings, and cached API content. |
| 135 |
* |
| 136 |
* @since 4.3.0 |
| 137 |
*/ |
| 138 |
if ( isset( $_POST['wpvulnerability_full_reset'] ) && check_admin_referer( 'wpvulnerability_full_reset_action', 'wpvulnerability_full_reset_nonce' ) ) { |
| 139 |
if ( current_user_can( 'manage_options' ) ) { |
| 140 |
wpvulnerability_reset_plugin_data(); |
| 141 |
set_transient( 'wpvulnerability_message_manual_success', __( 'WPVulnerability has been reset to defaults and reloaded.', 'wpvulnerability' ), 10 ); |
| 142 |
} else { |
| 143 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to reset WPVulnerability.', 'wpvulnerability' ), 10 ); |
| 144 |
} |
| 145 |
} |
| 146 |
|
| 147 |
/** |
| 148 |
* Handles debug action: Clear all caches. |
| 149 |
* |
| 150 |
* @since 4.3.0 |
| 151 |
*/ |
| 152 |
if ( isset( $_POST['wpvulnerability_debug_clear_caches'] ) && check_admin_referer( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ) ) { |
| 153 |
if ( current_user_can( 'manage_options' ) ) { |
| 154 |
if ( ! function_exists( 'wpvulnerability_debug_clear_all_caches' ) ) { |
| 155 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php'; |
| 156 |
} |
| 157 |
wpvulnerability_debug_clear_all_caches(); |
| 158 |
set_transient( 'wpvulnerability_message_manual_success', __( 'All caches have been cleared.', 'wpvulnerability' ), 10 ); |
| 159 |
} else { |
| 160 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to clear caches.', 'wpvulnerability' ), 10 ); |
| 161 |
} |
| 162 |
} |
| 163 |
|
| 164 |
/** |
| 165 |
* Handles debug action: Reset signatures. |
| 166 |
* |
| 167 |
* @since 4.3.0 |
| 168 |
*/ |
| 169 |
if ( isset( $_POST['wpvulnerability_debug_reset_signatures'] ) && check_admin_referer( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ) ) { |
| 170 |
if ( current_user_can( 'manage_options' ) ) { |
| 171 |
if ( ! function_exists( 'wpvulnerability_debug_reset_signatures' ) ) { |
| 172 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php'; |
| 173 |
} |
| 174 |
wpvulnerability_debug_reset_signatures(); |
| 175 |
set_transient( 'wpvulnerability_message_manual_success', __( 'Plugin and theme signatures have been reset.', 'wpvulnerability' ), 10 ); |
| 176 |
} else { |
| 177 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to reset signatures.', 'wpvulnerability' ), 10 ); |
| 178 |
} |
| 179 |
} |
| 180 |
|
| 181 |
/** |
| 182 |
* Handles debug action: Export debug info. |
| 183 |
* |
| 184 |
* @since 4.3.0 |
| 185 |
*/ |
| 186 |
if ( isset( $_POST['wpvulnerability_debug_export'] ) && check_admin_referer( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ) ) { |
| 187 |
if ( current_user_can( 'manage_options' ) ) { |
| 188 |
if ( ! function_exists( 'wpvulnerability_debug_export_info' ) ) { |
| 189 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php'; |
| 190 |
} |
| 191 |
$debug_info = wpvulnerability_debug_export_info(); |
| 192 |
$filename = 'wpvulnerability-debug-' . gmdate( 'Y-m-d-His' ) . '.json'; |
| 193 |
|
| 194 |
header( 'Content-Type: application/json' ); |
| 195 |
header( 'Content-Disposition: attachment; filename="' . $filename . '"' ); |
| 196 |
header( 'Content-Length: ' . strlen( $debug_info ) ); |
| 197 |
echo $debug_info; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 198 |
exit; |
| 199 |
} else { |
| 200 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to export debug information.', 'wpvulnerability' ), 10 ); |
| 201 |
} |
| 202 |
} |
| 203 |
|
| 204 |
/** |
| 205 |
* Handles debug action: Run update database now. |
| 206 |
* |
| 207 |
* @since 4.3.0 |
| 208 |
*/ |
| 209 |
if ( isset( $_POST['wpvulnerability_run_update'] ) && check_admin_referer( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ) ) { |
| 210 |
if ( current_user_can( 'manage_options' ) ) { |
| 211 |
wpvulnerability_update_database_data(); |
| 212 |
set_transient( 'wpvulnerability_message_manual_success', __( 'Database update has been executed.', 'wpvulnerability' ), 10 ); |
| 213 |
} else { |
| 214 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to run database updates.', 'wpvulnerability' ), 10 ); |
| 215 |
} |
| 216 |
} |
| 217 |
|
| 218 |
/** |
| 219 |
* Handles debug action: Run notification now. |
| 220 |
* |
| 221 |
* @since 4.3.0 |
| 222 |
*/ |
| 223 |
if ( isset( $_POST['wpvulnerability_run_notification'] ) && check_admin_referer( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ) ) { |
| 224 |
if ( current_user_can( 'manage_options' ) ) { |
| 225 |
if ( ! function_exists( 'wpvulnerability_execute_notification' ) ) { |
| 226 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-core.php'; |
| 227 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-plugins.php'; |
| 228 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-themes.php'; |
| 229 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php'; |
| 230 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-process.php'; |
| 231 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-notifications.php'; |
| 232 |
} |
| 233 |
$result = wpvulnerability_execute_notification( true ); |
| 234 |
if ( $result ) { |
| 235 |
set_transient( 'wpvulnerability_message_manual_success', __( 'Notification has been sent.', 'wpvulnerability' ), 10 ); |
| 236 |
} else { |
| 237 |
set_transient( 'wpvulnerability_message_manual_error', __( 'Notification sending failed.', 'wpvulnerability' ), 10 ); |
| 238 |
} |
| 239 |
} else { |
| 240 |
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to send notifications.', 'wpvulnerability' ), 10 ); |
| 241 |
} |
| 242 |
} |
| 243 |
|
| 244 |
/** |
| 245 |
* Retrieves the available tabs for the WPVulnerability admin settings page. |
| 246 |
* |
| 247 |
* @since 4.1.2 |
| 248 |
* |
| 249 |
* @return array<string, array<string, string>> An associative array of tab slugs and their labels. |
| 250 |
*/ |
| 251 |
function wpvulnerability_get_admin_tabs() { |
| 252 |
$tabs = array( |
| 253 |
'notifications' => array( |
| 254 |
'label' => __( 'Notifications', 'wpvulnerability' ), |
| 255 |
), |
| 256 |
'analysis' => array( |
| 257 |
'label' => __( 'Analysis', 'wpvulnerability' ), |
| 258 |
), |
| 259 |
'logs' => array( |
| 260 |
'label' => __( 'Logs', 'wpvulnerability' ), |
| 261 |
), |
| 262 |
'security' => array( |
| 263 |
'label' => __( 'Security', 'wpvulnerability' ), |
| 264 |
), |
| 265 |
'tools' => array( |
| 266 |
'label' => __( 'Tools', 'wpvulnerability' ), |
| 267 |
), |
| 268 |
); |
| 269 |
|
| 270 |
// Add Debug tab only if WP_DEBUG is enabled. |
| 271 |
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { |
| 272 |
$tabs['debug'] = array( |
| 273 |
'label' => __( 'Debug', 'wpvulnerability' ), |
| 274 |
); |
| 275 |
} |
| 276 |
|
| 277 |
$tabs['about'] = array( |
| 278 |
'label' => __( 'About', 'wpvulnerability' ), |
| 279 |
); |
| 280 |
|
| 281 |
return $tabs; |
| 282 |
} |
| 283 |
|
| 284 |
/** |
| 285 |
* Determines the active admin tab for the settings screen. |
| 286 |
* |
| 287 |
* @since 4.1.2 |
| 288 |
* |
| 289 |
* @param array<string, array<string, string>> $tabs Registered admin tabs. |
| 290 |
* |
| 291 |
* @return string The active tab slug. |
| 292 |
*/ |
| 293 |
function wpvulnerability_get_current_admin_tab( $tabs ) { |
| 294 |
$tab_keys = array_keys( $tabs ); |
| 295 |
$default = reset( $tab_keys ); |
| 296 |
$tab_filter = filter_input( INPUT_GET, 'tab', FILTER_SANITIZE_SPECIAL_CHARS ); |
| 297 |
|
| 298 |
if ( $tab_filter ) { |
| 299 |
$tab_filter = sanitize_key( $tab_filter ); |
| 300 |
} |
| 301 |
|
| 302 |
if ( $tab_filter && isset( $tabs[ $tab_filter ] ) ) { |
| 303 |
return $tab_filter; |
| 304 |
} |
| 305 |
|
| 306 |
return $default ? $default : 'notifications'; |
| 307 |
} |
| 308 |
|
| 309 |
/** |
| 310 |
* Renders the requested admin tab content. |
| 311 |
* |
| 312 |
* @since 4.1.2 |
| 313 |
* |
| 314 |
* @param string $tab Tab slug to render. |
| 315 |
* |
| 316 |
* @return void |
| 317 |
*/ |
| 318 |
function wpvulnerability_render_admin_tab( $tab ) { |
| 319 |
switch ( $tab ) { |
| 320 |
case 'analysis': |
| 321 |
wpvulnerability_render_admin_tab_analysis(); |
| 322 |
break; |
| 323 |
case 'logs': |
| 324 |
wpvulnerability_render_admin_tab_logs(); |
| 325 |
break; |
| 326 |
case 'security': |
| 327 |
wpvulnerability_render_admin_tab_security(); |
| 328 |
break; |
| 329 |
case 'tools': |
| 330 |
wpvulnerability_render_admin_tab_tools(); |
| 331 |
break; |
| 332 |
case 'debug': |
| 333 |
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { |
| 334 |
wpvulnerability_render_admin_tab_debug(); |
| 335 |
} |
| 336 |
break; |
| 337 |
case 'about': |
| 338 |
wpvulnerability_render_admin_tab_about(); |
| 339 |
break; |
| 340 |
case 'notifications': |
| 341 |
default: |
| 342 |
wpvulnerability_render_admin_tab_notifications(); |
| 343 |
break; |
| 344 |
} |
| 345 |
} |
| 346 |
|
| 347 |
/** |
| 348 |
* Outputs the Notifications tab contents. |
| 349 |
* |
| 350 |
* @since 4.1.2 |
| 351 |
* |
| 352 |
* @return void |
| 353 |
*/ |
| 354 |
function wpvulnerability_render_admin_tab_notifications() { |
| 355 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config', array() ); |
| 356 |
$defaults = array( |
| 357 |
'cache' => 12, |
| 358 |
'period' => 'weekly', |
| 359 |
'day' => 'monday', |
| 360 |
'hour' => 0, |
| 361 |
'minute' => 0, |
| 362 |
'emails' => '', |
| 363 |
'slack_webhook' => '', |
| 364 |
'teams_webhook' => '', |
| 365 |
'discord_webhook' => '', |
| 366 |
'telegram_bot_token' => '', |
| 367 |
'telegram_chat_id' => '', |
| 368 |
'notify' => array( |
| 369 |
'email' => 'y', |
| 370 |
'slack' => 'n', |
| 371 |
'teams' => 'n', |
| 372 |
'discord' => 'n', |
| 373 |
'telegram' => 'n', |
| 374 |
), |
| 375 |
); |
| 376 |
$wpvulnerability_settings = wp_parse_args( $wpvulnerability_settings, $defaults ); |
| 377 |
|
| 378 |
// Normalize notify settings. |
| 379 |
if ( ! is_array( $wpvulnerability_settings['notify'] ) ) { |
| 380 |
$wpvulnerability_settings['notify'] = $defaults['notify']; |
| 381 |
} else { |
| 382 |
$wpvulnerability_settings['notify'] = wp_parse_args( $wpvulnerability_settings['notify'], $defaults['notify'] ); |
| 383 |
} |
| 384 |
$wpvulnerability_settings['notify'] = wpvulnerability_normalize_notify_settings( $wpvulnerability_settings['notify'] ); |
| 385 |
|
| 386 |
$email_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['email'] ); |
| 387 |
$slack_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['slack'] ); |
| 388 |
$teams_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['teams'] ); |
| 389 |
$discord_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['discord'] ); |
| 390 |
$telegram_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['telegram'] ); |
| 391 |
|
| 392 |
// Check if cache is forced. |
| 393 |
$forced_cache = null; |
| 394 |
$cache_options = array( 1, 6, 12, 24 ); |
| 395 |
if ( defined( 'WPVULNERABILITY_CACHE_HOURS' ) ) { |
| 396 |
$forced_cache = (int) WPVULNERABILITY_CACHE_HOURS; |
| 397 |
if ( ! in_array( $forced_cache, $cache_options, true ) ) { |
| 398 |
$cache_options[] = $forced_cache; |
| 399 |
sort( $cache_options, SORT_NUMERIC ); |
| 400 |
} |
| 401 |
} |
| 402 |
$current_cache = null !== $forced_cache ? $forced_cache : (int) $wpvulnerability_settings['cache']; |
| 403 |
|
| 404 |
$admin_email = get_bloginfo( 'admin_email' ); |
| 405 |
?> |
| 406 |
<section class="section wpvulnerability-notifications-panel"> |
| 407 |
|
| 408 |
<form method="post" action="options.php"> |
| 409 |
<?php settings_fields( 'admin_wpvulnerability_settings' ); ?> |
| 410 |
|
| 411 |
<div class="wpvulnerability-security-section"> |
| 412 |
<h3><?php esc_html_e( 'Notification Settings', 'wpvulnerability' ); ?></h3> |
| 413 |
|
| 414 |
<div class="wpvulnerability-intro"> |
| 415 |
<p><strong><?php esc_html_e( 'Configure how and when you want to receive vulnerability notifications.', 'wpvulnerability' ); ?></strong></p> |
| 416 |
<p><?php esc_html_e( 'Stay informed about security vulnerabilities in your WordPress installation, plugins, themes, and server software.', 'wpvulnerability' ); ?></p> |
| 417 |
</div> |
| 418 |
|
| 419 |
<!-- Cache Settings --> |
| 420 |
<div class="wpvulnerability-setting-group"> |
| 421 |
<div class="wpvulnerability-setting-label"> |
| 422 |
<span class="wpvulnerability-setting-icon">⏱️</span> |
| 423 |
<?php esc_html_e( 'Cache Expiration Time', 'wpvulnerability' ); ?> |
| 424 |
<?php if ( null !== $forced_cache ) : ?> |
| 425 |
<span class="wpvulnerability-forced-badge"><?php esc_html_e( 'FORCED', 'wpvulnerability' ); ?></span> |
| 426 |
<?php endif; ?> |
| 427 |
</div> |
| 428 |
<div class="wpvulnerability-setting-description"> |
| 429 |
<?php esc_html_e( 'How long to cache vulnerability data before refreshing from the API.', 'wpvulnerability' ); ?> |
| 430 |
</div> |
| 431 |
<select name="wpvulnerability-config[cache]" id="wpvulnerability_cache" <?php disabled( null !== $forced_cache ); ?>> |
| 432 |
<?php foreach ( $cache_options as $hours ) : ?> |
| 433 |
<option value="<?php echo esc_attr( $hours ); ?>" <?php selected( $current_cache, $hours ); ?>> |
| 434 |
<?php |
| 435 |
echo esc_html( |
| 436 |
sprintf( |
| 437 |
/* translators: %d: number of hours */ |
| 438 |
_n( '%d hour', '%d hours', $hours, 'wpvulnerability' ), |
| 439 |
$hours |
| 440 |
) |
| 441 |
); |
| 442 |
?> |
| 443 |
</option> |
| 444 |
<?php endforeach; ?> |
| 445 |
</select> |
| 446 |
<?php if ( null !== $forced_cache ) : ?> |
| 447 |
<input type="hidden" name="wpvulnerability-config[cache]" value="<?php echo esc_attr( $current_cache ); ?>" /> |
| 448 |
<?php endif; ?> |
| 449 |
<div class="wpvulnerability-info-box"> |
| 450 |
<p> |
| 451 |
<?php |
| 452 |
printf( |
| 453 |
/* translators: %s: documentation URL */ |
| 454 |
wp_kses_post( __( 'You can force the cache time via wp-config.php constant. <a href="%s" target="_blank" rel="noopener noreferrer">Learn more →</a>', 'wpvulnerability' ) ), |
| 455 |
esc_url( 'https://www.wpvulnerability.com/plugin/#cache-duration' ) |
| 456 |
); |
| 457 |
?> |
| 458 |
</p> |
| 459 |
</div> |
| 460 |
</div> |
| 461 |
|
| 462 |
<!-- Notification Frequency --> |
| 463 |
<div class="wpvulnerability-setting-group"> |
| 464 |
<div class="wpvulnerability-setting-label"> |
| 465 |
<span class="wpvulnerability-setting-icon">� |
| 466 |
</span> |
| 467 |
<?php esc_html_e( 'Notification Frequency', 'wpvulnerability' ); ?> |
| 468 |
</div> |
| 469 |
<div class="wpvulnerability-setting-description"> |
| 470 |
<?php esc_html_e( 'Choose how often you want to receive vulnerability notifications.', 'wpvulnerability' ); ?> |
| 471 |
</div> |
| 472 |
<div class="wpvulnerability-radio-group"> |
| 473 |
<label> |
| 474 |
<input type="radio" name="wpvulnerability-config[period]" value="never" <?php checked( $wpvulnerability_settings['period'], 'never' ); ?> onchange="wpvUpdateScheduleVisibility()" /> |
| 475 |
<?php esc_html_e( 'Never - Disable automatic notifications', 'wpvulnerability' ); ?> |
| 476 |
</label> |
| 477 |
<label> |
| 478 |
<input type="radio" name="wpvulnerability-config[period]" value="daily" <?php checked( $wpvulnerability_settings['period'], 'daily' ); ?> onchange="wpvUpdateScheduleVisibility()" /> |
| 479 |
<?php esc_html_e( 'Daily - Receive notifications every day', 'wpvulnerability' ); ?> |
| 480 |
</label> |
| 481 |
<label> |
| 482 |
<input type="radio" name="wpvulnerability-config[period]" value="weekly" <?php checked( $wpvulnerability_settings['period'], 'weekly' ); ?> onchange="wpvUpdateScheduleVisibility()" /> |
| 483 |
<?php esc_html_e( 'Weekly - Receive notifications once a week', 'wpvulnerability' ); ?> |
| 484 |
</label> |
| 485 |
</div> |
| 486 |
|
| 487 |
<div class="wpvulnerability-schedule-controls" id="wpvulnerability-schedule-controls"> |
| 488 |
<div class="wpvulnerability-schedule-row" id="wpvulnerability-day-selector"> |
| 489 |
<label for="wpvulnerability_day"><?php esc_html_e( 'Day:', 'wpvulnerability' ); ?></label> |
| 490 |
<select name="wpvulnerability-config[day]" id="wpvulnerability_day"> |
| 491 |
<option value="monday" <?php selected( $wpvulnerability_settings['day'], 'monday' ); ?>><?php esc_html_e( 'Monday', 'wpvulnerability' ); ?></option> |
| 492 |
<option value="tuesday" <?php selected( $wpvulnerability_settings['day'], 'tuesday' ); ?>><?php esc_html_e( 'Tuesday', 'wpvulnerability' ); ?></option> |
| 493 |
<option value="wednesday" <?php selected( $wpvulnerability_settings['day'], 'wednesday' ); ?>><?php esc_html_e( 'Wednesday', 'wpvulnerability' ); ?></option> |
| 494 |
<option value="thursday" <?php selected( $wpvulnerability_settings['day'], 'thursday' ); ?>><?php esc_html_e( 'Thursday', 'wpvulnerability' ); ?></option> |
| 495 |
<option value="friday" <?php selected( $wpvulnerability_settings['day'], 'friday' ); ?>><?php esc_html_e( 'Friday', 'wpvulnerability' ); ?></option> |
| 496 |
<option value="saturday" <?php selected( $wpvulnerability_settings['day'], 'saturday' ); ?>><?php esc_html_e( 'Saturday', 'wpvulnerability' ); ?></option> |
| 497 |
<option value="sunday" <?php selected( $wpvulnerability_settings['day'], 'sunday' ); ?>><?php esc_html_e( 'Sunday', 'wpvulnerability' ); ?></option> |
| 498 |
</select> |
| 499 |
</div> |
| 500 |
<div class="wpvulnerability-schedule-row"> |
| 501 |
<label for="wpvulnerability_hour"><?php esc_html_e( 'Time:', 'wpvulnerability' ); ?></label> |
| 502 |
<input type="number" min="0" max="23" name="wpvulnerability-config[hour]" id="wpvulnerability_hour" value="<?php echo esc_attr( (string) $wpvulnerability_settings['hour'] ); ?>" /> |
| 503 |
<span>:</span> |
| 504 |
<input type="number" min="0" max="59" name="wpvulnerability-config[minute]" id="wpvulnerability_minute" value="<?php echo esc_attr( (string) $wpvulnerability_settings['minute'] ); ?>" /> |
| 505 |
<span class="wpvulnerability-input-hint"><?php esc_html_e( '(24-hour format, server timezone)', 'wpvulnerability' ); ?></span> |
| 506 |
</div> |
| 507 |
</div> |
| 508 |
</div> |
| 509 |
|
| 510 |
<!-- Notification Channels --> |
| 511 |
<div class="wpvulnerability-setting-group"> |
| 512 |
<div class="wpvulnerability-setting-label"> |
| 513 |
<span class="wpvulnerability-setting-icon">📢</span> |
| 514 |
<?php esc_html_e( 'Notification Channels', 'wpvulnerability' ); ?> |
| 515 |
</div> |
| 516 |
<div class="wpvulnerability-setting-description"> |
| 517 |
<?php esc_html_e( 'Select where you want to receive notifications.', 'wpvulnerability' ); ?> |
| 518 |
</div> |
| 519 |
<div class="wpvulnerability-checkbox-group"> |
| 520 |
<label> |
| 521 |
<input type="checkbox" name="wpvulnerability-config[notify][email]" value="y" <?php checked( $email_enabled ); ?> onchange="wpvToggleChannelInput('email')" /> |
| 522 |
<?php esc_html_e( 'Email', 'wpvulnerability' ); ?> |
| 523 |
</label> |
| 524 |
<div class="wpvulnerability-channel-inputs" id="wpvulnerability-email-inputs"> |
| 525 |
<label for="wpvulnerability_emails"><?php esc_html_e( 'Email Addresses (separated by commas):', 'wpvulnerability' ); ?></label> |
| 526 |
<input class="wpvulnerability-input-full" type="text" name="wpvulnerability-config[emails]" id="wpvulnerability_emails" placeholder="<?php echo esc_attr( (string) $admin_email ); ?>" value="<?php echo esc_attr( (string) $wpvulnerability_settings['emails'] ); ?>" /> |
| 527 |
<span class="wpvulnerability-input-hint"><?php esc_html_e( 'Default:', 'wpvulnerability' ); ?> <?php echo esc_html( (string) $admin_email ); ?></span> |
| 528 |
</div> |
| 529 |
|
| 530 |
<label> |
| 531 |
<input type="checkbox" name="wpvulnerability-config[notify][slack]" value="y" <?php checked( $slack_enabled ); ?> onchange="wpvToggleChannelInput('slack')" /> |
| 532 |
<?php esc_html_e( 'Slack', 'wpvulnerability' ); ?> |
| 533 |
</label> |
| 534 |
<div class="wpvulnerability-channel-inputs" id="wpvulnerability-slack-inputs"> |
| 535 |
<label for="wpvulnerability_slack_webhook"><?php esc_html_e( 'Slack Webhook URL:', 'wpvulnerability' ); ?></label> |
| 536 |
<input class="wpvulnerability-input-full" type="url" name="wpvulnerability-config[slack_webhook]" id="wpvulnerability_slack_webhook" placeholder="https://hooks.slack.com/services/..." value="<?php echo esc_attr( (string) $wpvulnerability_settings['slack_webhook'] ); ?>" /> |
| 537 |
<span class="wpvulnerability-input-hint"> |
| 538 |
<?php |
| 539 |
printf( |
| 540 |
/* translators: %s: Slack documentation URL */ |
| 541 |
wp_kses_post( __( '<a href="%s" target="_blank" rel="noopener noreferrer">Learn how to create a Slack incoming webhook →</a>', 'wpvulnerability' ) ), |
| 542 |
esc_url( 'https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks/' ) |
| 543 |
); |
| 544 |
?> |
| 545 |
</span> |
| 546 |
</div> |
| 547 |
|
| 548 |
<label> |
| 549 |
<input type="checkbox" name="wpvulnerability-config[notify][teams]" value="y" <?php checked( $teams_enabled ); ?> onchange="wpvToggleChannelInput('teams')" /> |
| 550 |
<?php esc_html_e( 'Microsoft Teams', 'wpvulnerability' ); ?> |
| 551 |
</label> |
| 552 |
<div class="wpvulnerability-channel-inputs" id="wpvulnerability-teams-inputs"> |
| 553 |
<label for="wpvulnerability_teams_webhook"><?php esc_html_e( 'Teams Webhook URL:', 'wpvulnerability' ); ?></label> |
| 554 |
<input class="wpvulnerability-input-full" type="url" name="wpvulnerability-config[teams_webhook]" id="wpvulnerability_teams_webhook" placeholder="https://outlook.office.com/webhook/..." value="<?php echo esc_attr( (string) $wpvulnerability_settings['teams_webhook'] ); ?>" /> |
| 555 |
<span class="wpvulnerability-input-hint"> |
| 556 |
<?php |
| 557 |
printf( |
| 558 |
/* translators: %s: Microsoft Teams documentation URL */ |
| 559 |
wp_kses_post( __( '<a href="%s" target="_blank" rel="noopener noreferrer">Learn how to create a Teams incoming webhook →</a>', 'wpvulnerability' ) ), |
| 560 |
esc_url( 'https://learn.microsoft.com/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook' ) |
| 561 |
); |
| 562 |
?> |
| 563 |
</span> |
| 564 |
</div> |
| 565 |
|
| 566 |
<label> |
| 567 |
<input type="checkbox" name="wpvulnerability-config[notify][discord]" value="y" <?php checked( $discord_enabled ); ?> onchange="wpvToggleChannelInput('discord')" /> |
| 568 |
<?php esc_html_e( 'Discord', 'wpvulnerability' ); ?> |
| 569 |
</label> |
| 570 |
<div class="wpvulnerability-channel-inputs" id="wpvulnerability-discord-inputs"> |
| 571 |
<label for="wpvulnerability_discord_webhook"><?php esc_html_e( 'Discord Webhook URL:', 'wpvulnerability' ); ?></label> |
| 572 |
<input class="wpvulnerability-input-full" type="url" name="wpvulnerability-config[discord_webhook]" id="wpvulnerability_discord_webhook" placeholder="https://discord.com/api/webhooks/..." value="<?php echo esc_attr( (string) $wpvulnerability_settings['discord_webhook'] ); ?>" /> |
| 573 |
<span class="wpvulnerability-input-hint"> |
| 574 |
<?php |
| 575 |
printf( |
| 576 |
/* translators: %s: Discord documentation URL */ |
| 577 |
wp_kses_post( __( '<a href="%s" target="_blank" rel="noopener noreferrer">Learn how to create a Discord webhook →</a>', 'wpvulnerability' ) ), |
| 578 |
esc_url( 'https://support.discord.com/hc/articles/228383668' ) |
| 579 |
); |
| 580 |
?> |
| 581 |
</span> |
| 582 |
</div> |
| 583 |
|
| 584 |
<label> |
| 585 |
<input type="checkbox" name="wpvulnerability-config[notify][telegram]" value="y" <?php checked( $telegram_enabled ); ?> onchange="wpvToggleChannelInput('telegram')" /> |
| 586 |
<?php esc_html_e( 'Telegram', 'wpvulnerability' ); ?> |
| 587 |
</label> |
| 588 |
<div class="wpvulnerability-channel-inputs" id="wpvulnerability-telegram-inputs"> |
| 589 |
<label for="wpvulnerability_telegram_bot_token"><?php esc_html_e( 'Telegram Bot Token:', 'wpvulnerability' ); ?></label> |
| 590 |
<input class="wpvulnerability-input-full" type="text" name="wpvulnerability-config[telegram_bot_token]" id="wpvulnerability_telegram_bot_token" placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" value="<?php echo esc_attr( (string) $wpvulnerability_settings['telegram_bot_token'] ); ?>" /> |
| 591 |
<span class="wpvulnerability-input-hint"><?php esc_html_e( 'Format: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', 'wpvulnerability' ); ?></span> |
| 592 |
|
| 593 |
<label for="wpvulnerability_telegram_chat_id" style="margin-top: 12px;"><?php esc_html_e( 'Telegram Chat ID:', 'wpvulnerability' ); ?></label> |
| 594 |
<input class="wpvulnerability-input-full" type="text" name="wpvulnerability-config[telegram_chat_id]" id="wpvulnerability_telegram_chat_id" placeholder="-1001234567890" value="<?php echo esc_attr( (string) $wpvulnerability_settings['telegram_chat_id'] ); ?>" /> |
| 595 |
<span class="wpvulnerability-input-hint"> |
| 596 |
<?php |
| 597 |
printf( |
| 598 |
/* translators: %s: Telegram documentation URL */ |
| 599 |
wp_kses_post( __( '<a href="%s" target="_blank" rel="noopener noreferrer">Learn how to create a Telegram bot and get Chat ID →</a>', 'wpvulnerability' ) ), |
| 600 |
esc_url( 'https://core.telegram.org/bots' ) |
| 601 |
); |
| 602 |
?> |
| 603 |
</span> |
| 604 |
</div> |
| 605 |
</div> |
| 606 |
</div> |
| 607 |
|
| 608 |
<div class="wpvulnerability-save-section"> |
| 609 |
<?php submit_button( __( 'Save Notification Settings', 'wpvulnerability' ), 'primary', 'submit', false ); ?> |
| 610 |
</div> |
| 611 |
</div> |
| 612 |
</form> |
| 613 |
|
| 614 |
<script> |
| 615 |
function wpvUpdateScheduleVisibility() { |
| 616 |
var period = document.querySelector('input[name="wpvulnerability-config[period]"]:checked').value; |
| 617 |
var scheduleControls = document.getElementById('wpvulnerability-schedule-controls'); |
| 618 |
var daySelector = document.getElementById('wpvulnerability-day-selector'); |
| 619 |
|
| 620 |
if (period === 'never') { |
| 621 |
scheduleControls.classList.add('wpvulnerability-hidden'); |
| 622 |
} else { |
| 623 |
scheduleControls.classList.remove('wpvulnerability-hidden'); |
| 624 |
if (period === 'weekly') { |
| 625 |
daySelector.style.display = 'block'; |
| 626 |
} else { |
| 627 |
daySelector.style.display = 'none'; |
| 628 |
} |
| 629 |
} |
| 630 |
} |
| 631 |
|
| 632 |
function wpvToggleChannelInput(channel) { |
| 633 |
var checkbox = document.querySelector('input[name="wpvulnerability-config[notify][' + channel + ']"]'); |
| 634 |
var inputs = document.getElementById('wpvulnerability-' + channel + '-inputs'); |
| 635 |
|
| 636 |
if (checkbox.checked) { |
| 637 |
inputs.classList.remove('wpvulnerability-hidden'); |
| 638 |
} else { |
| 639 |
inputs.classList.add('wpvulnerability-hidden'); |
| 640 |
} |
| 641 |
} |
| 642 |
|
| 643 |
// Initialize visibility on page load. |
| 644 |
document.addEventListener('DOMContentLoaded', function() { |
| 645 |
wpvUpdateScheduleVisibility(); |
| 646 |
wpvToggleChannelInput('email'); |
| 647 |
wpvToggleChannelInput('slack'); |
| 648 |
wpvToggleChannelInput('teams'); |
| 649 |
wpvToggleChannelInput('discord'); |
| 650 |
wpvToggleChannelInput('telegram'); |
| 651 |
}); |
| 652 |
</script> |
| 653 |
</section> |
| 654 |
<?php |
| 655 |
} |
| 656 |
|
| 657 |
/** |
| 658 |
* Outputs the Analysis tab contents. |
| 659 |
* |
| 660 |
* @since 4.1.2 |
| 661 |
* |
| 662 |
* @return void |
| 663 |
*/ |
| 664 |
function wpvulnerability_render_admin_tab_analysis() { |
| 665 |
$wpvulnerability_analyze = get_option( 'wpvulnerability-analyze', array() ); |
| 666 |
$components = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' ); |
| 667 |
$forced = array(); |
| 668 |
|
| 669 |
foreach ( $components as $component ) { |
| 670 |
if ( ! isset( $wpvulnerability_analyze[ $component ] ) ) { |
| 671 |
$wpvulnerability_analyze[ $component ] = 0; |
| 672 |
} |
| 673 |
$constant = 'WPVULNERABILITY_HIDE_' . strtoupper( (string) $component ); |
| 674 |
$forced[ $component ] = defined( $constant ) && constant( $constant ); |
| 675 |
if ( $forced[ $component ] ) { |
| 676 |
$wpvulnerability_analyze[ $component ] = 1; |
| 677 |
} |
| 678 |
} |
| 679 |
|
| 680 |
// Component configuration with labels and icons. |
| 681 |
$component_config = array( |
| 682 |
'wordpress' => array( |
| 683 |
'label' => __( 'WordPress Components', 'wpvulnerability' ), |
| 684 |
'items' => array( |
| 685 |
'core' => array( |
| 686 |
'label' => __( 'WordPress Core', 'wpvulnerability' ), |
| 687 |
'icon' => '🌐', |
| 688 |
), |
| 689 |
'plugins' => array( |
| 690 |
'label' => __( 'Plugins', 'wpvulnerability' ), |
| 691 |
'icon' => '🧩', |
| 692 |
), |
| 693 |
'themes' => array( |
| 694 |
'label' => __( 'Themes', 'wpvulnerability' ), |
| 695 |
'icon' => '🎨', |
| 696 |
), |
| 697 |
), |
| 698 |
), |
| 699 |
'software' => array( |
| 700 |
'label' => __( 'Software & Languages', 'wpvulnerability' ), |
| 701 |
'items' => array( |
| 702 |
'php' => array( |
| 703 |
'label' => __( 'PHP', 'wpvulnerability' ), |
| 704 |
'icon' => '🐘', |
| 705 |
), |
| 706 |
), |
| 707 |
), |
| 708 |
'webservers' => array( |
| 709 |
'label' => __( 'Web Servers', 'wpvulnerability' ), |
| 710 |
'items' => array( |
| 711 |
'apache' => array( |
| 712 |
'label' => __( 'Apache HTTPD', 'wpvulnerability' ), |
| 713 |
'icon' => '🪶', |
| 714 |
), |
| 715 |
'nginx' => array( |
| 716 |
'label' => __( 'nginx', 'wpvulnerability' ), |
| 717 |
'icon' => '🟩', |
| 718 |
), |
| 719 |
), |
| 720 |
), |
| 721 |
'databases' => array( |
| 722 |
'label' => __( 'Databases', 'wpvulnerability' ), |
| 723 |
'items' => array( |
| 724 |
'mariadb' => array( |
| 725 |
'label' => __( 'MariaDB', 'wpvulnerability' ), |
| 726 |
'icon' => '🐬', |
| 727 |
), |
| 728 |
'mysql' => array( |
| 729 |
'label' => __( 'MySQL', 'wpvulnerability' ), |
| 730 |
'icon' => '🐬', |
| 731 |
), |
| 732 |
'sqlite' => array( |
| 733 |
'label' => __( 'SQLite', 'wpvulnerability' ), |
| 734 |
'icon' => '💾', |
| 735 |
), |
| 736 |
), |
| 737 |
), |
| 738 |
'tools' => array( |
| 739 |
'label' => __( 'Additional Tools', 'wpvulnerability' ), |
| 740 |
'items' => array( |
| 741 |
'imagemagick' => array( |
| 742 |
'label' => __( 'ImageMagick', 'wpvulnerability' ), |
| 743 |
'icon' => '🖼️', |
| 744 |
), |
| 745 |
'curl' => array( |
| 746 |
'label' => __( 'curl', 'wpvulnerability' ), |
| 747 |
'icon' => '🌐', |
| 748 |
), |
| 749 |
'memcached' => array( |
| 750 |
'label' => __( 'memcached', 'wpvulnerability' ), |
| 751 |
'icon' => '⚡', |
| 752 |
), |
| 753 |
'redis' => array( |
| 754 |
'label' => __( 'Redis', 'wpvulnerability' ), |
| 755 |
'icon' => '🔴', |
| 756 |
), |
| 757 |
), |
| 758 |
), |
| 759 |
); |
| 760 |
?> |
| 761 |
<section class="section wpvulnerability-analysis-panel"> |
| 762 |
|
| 763 |
<form method="post" action="options.php"> |
| 764 |
<?php settings_fields( 'admin_wpvulnerability_analyze' ); ?> |
| 765 |
|
| 766 |
<div class="wpvulnerability-security-section"> |
| 767 |
<h3><?php esc_html_e( 'Component Analysis Settings', 'wpvulnerability' ); ?></h3> |
| 768 |
|
| 769 |
<div class="wpvulnerability-intro"> |
| 770 |
<p><strong><?php esc_html_e( 'Enable or disable vulnerability analysis for specific components.', 'wpvulnerability' ); ?></strong></p> |
| 771 |
<p><?php esc_html_e( 'Check the components you want to HIDE from vulnerability scans and reports. Unchecked components will be actively analyzed. Components with active analysis are shown in green, hidden components in red.', 'wpvulnerability' ); ?></p> |
| 772 |
</div> |
| 773 |
|
| 774 |
<?php foreach ( $component_config as $category_key => $category_data ) : ?> |
| 775 |
<div class="wpvulnerability-category"> |
| 776 |
<div class="wpvulnerability-category-title"><?php echo esc_html( $category_data['label'] ); ?></div> |
| 777 |
<div class="wpvulnerability-components-grid"> |
| 778 |
<?php foreach ( $category_data['items'] as $component => $component_data ) : ?> |
| 779 |
<?php |
| 780 |
$is_checked = ! empty( $wpvulnerability_analyze[ $component ] ); |
| 781 |
$is_forced = ! empty( $forced[ $component ] ); |
| 782 |
$card_class = 'wpvulnerability-component-card'; |
| 783 |
if ( $is_checked ) { |
| 784 |
$card_class .= ' wpvulnerability-checked'; |
| 785 |
} |
| 786 |
if ( $is_forced ) { |
| 787 |
$card_class .= ' wpvulnerability-disabled'; |
| 788 |
} |
| 789 |
?> |
| 790 |
<div class="<?php echo esc_attr( $card_class ); ?>" onclick="if (!this.classList.contains('wpvulnerability-disabled')) { var cb = this.querySelector('input[type=checkbox]'); cb.checked = !cb.checked; this.classList.toggle('wpvulnerability-checked'); }"> |
| 791 |
<label> |
| 792 |
<span class="wpvulnerability-component-icon"><?php echo esc_html( $component_data['icon'] ); ?></span> |
| 793 |
<span class="wpvulnerability-component-content"> |
| 794 |
<span class="wpvulnerability-component-label"> |
| 795 |
<?php echo esc_html( $component_data['label'] ); ?> |
| 796 |
<?php if ( $is_forced ) : ?> |
| 797 |
<span class="wpvulnerability-forced-badge"><?php esc_html_e( 'FORCED', 'wpvulnerability' ); ?></span> |
| 798 |
<?php endif; ?> |
| 799 |
</span> |
| 800 |
<span class="wpvulnerability-component-status"> |
| 801 |
<?php |
| 802 |
if ( $is_forced ) { |
| 803 |
echo '<span class="wpvulnerability-status-badge wpvulnerability-status-hidden">' . esc_html__( 'Hidden (forced by constant)', 'wpvulnerability' ) . '</span>'; |
| 804 |
} elseif ( $is_checked ) { |
| 805 |
// Checked = value is 1 = analysis is DISABLED (hidden). |
| 806 |
echo '<span class="wpvulnerability-status-badge wpvulnerability-status-hidden">' . esc_html__( '🔴 Analysis disabled', 'wpvulnerability' ) . '</span>'; |
| 807 |
} else { |
| 808 |
// Unchecked = value is 0 or not set = analysis is ENABLED (active). |
| 809 |
echo '<span class="wpvulnerability-status-badge wpvulnerability-status-active">' . esc_html__( '🟢 Analysis active', 'wpvulnerability' ) . '</span>'; |
| 810 |
} |
| 811 |
?> |
| 812 |
</span> |
| 813 |
</span> |
| 814 |
<input |
| 815 |
type="checkbox" |
| 816 |
name="wpvulnerability-analyze[<?php echo esc_attr( $component ); ?>]" |
| 817 |
value="<?php echo esc_attr( $component ); ?>" |
| 818 |
<?php checked( $is_checked ); ?> |
| 819 |
<?php disabled( $is_forced ); ?> |
| 820 |
onclick="event.stopPropagation();" |
| 821 |
/> |
| 822 |
</label> |
| 823 |
</div> |
| 824 |
<?php endforeach; ?> |
| 825 |
</div> |
| 826 |
</div> |
| 827 |
<?php endforeach; ?> |
| 828 |
|
| 829 |
<div class="wpvulnerability-info-box"> |
| 830 |
<p> |
| 831 |
<strong><?php esc_html_e( 'Tip:', 'wpvulnerability' ); ?></strong> |
| 832 |
<?php |
| 833 |
printf( |
| 834 |
/* translators: %s: documentation URL */ |
| 835 |
wp_kses_post( __( 'You can force-disable components via wp-config.php constants. <a href="%s" target="_blank" rel="noopener noreferrer">Learn more about force-hiding checks →</a>', 'wpvulnerability' ) ), |
| 836 |
esc_url( 'https://www.wpvulnerability.com/plugin/#force-hiding-checks' ) |
| 837 |
); |
| 838 |
?> |
| 839 |
</p> |
| 840 |
</div> |
| 841 |
|
| 842 |
<div class="wpvulnerability-save-section"> |
| 843 |
<?php submit_button( __( 'Save Analysis Settings', 'wpvulnerability' ), 'primary', 'submit', false ); ?> |
| 844 |
</div> |
| 845 |
</div> |
| 846 |
</form> |
| 847 |
</section> |
| 848 |
<?php |
| 849 |
} |
| 850 |
|
| 851 |
/** |
| 852 |
* Outputs the Logs tab contents. |
| 853 |
* |
| 854 |
* @since 4.2.0 |
| 855 |
* |
| 856 |
* @return void |
| 857 |
*/ |
| 858 |
function wpvulnerability_render_admin_tab_logs() { |
| 859 |
$choices = wpvulnerability_get_log_retention_values(); |
| 860 |
$current = wpvulnerability_log_retention_days(); |
| 861 |
$forced = wpvulnerability_forced_log_retention(); |
| 862 |
$per_page_options = wpvulnerability_get_log_per_page_options(); |
| 863 |
$logs_per_page = wpvulnerability_get_default_log_per_page(); |
| 864 |
$per_page_request = isset( $_GET['logs_per_page'] ) ? absint( wp_unslash( $_GET['logs_per_page'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 865 |
if ( in_array( $per_page_request, $per_page_options, true ) ) { |
| 866 |
$logs_per_page = $per_page_request; |
| 867 |
} |
| 868 |
$current_page = isset( $_GET['log_page'] ) ? absint( wp_unslash( $_GET['log_page'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 869 |
if ( $current_page < 1 ) { |
| 870 |
$current_page = 1; |
| 871 |
} |
| 872 |
$total_logs = wpvulnerability_count_api_logs(); |
| 873 |
$total_pages = max( 1, (int) ceil( $total_logs / $logs_per_page ) ); |
| 874 |
if ( $current_page > $total_pages ) { |
| 875 |
$current_page = $total_pages; |
| 876 |
} |
| 877 |
$logs = wpvulnerability_get_api_logs( $logs_per_page, $current_page ); |
| 878 |
$logs_page_url = add_query_arg( |
| 879 |
array( |
| 880 |
'page' => 'wpvulnerability-options', |
| 881 |
'tab' => 'logs', |
| 882 |
'logs_per_page' => $logs_per_page, |
| 883 |
'log_page' => $current_page, |
| 884 |
), |
| 885 |
admin_url( 'options-general.php' ) |
| 886 |
); |
| 887 |
$requested_log = isset( $_GET['log'] ) ? absint( wp_unslash( $_GET['log'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 888 |
$view_log = null; |
| 889 |
$log_error = ''; |
| 890 |
$pagination = ''; |
| 891 |
|
| 892 |
if ( $total_pages > 1 ) { |
| 893 |
$pagination_base = remove_query_arg( |
| 894 |
array( 'log', 'log_page' ), |
| 895 |
$logs_page_url |
| 896 |
); |
| 897 |
$pagination = paginate_links( |
| 898 |
array( |
| 899 |
'base' => add_query_arg( 'log_page', '%#%', $pagination_base ), |
| 900 |
'format' => '', |
| 901 |
'current' => $current_page, |
| 902 |
'total' => $total_pages, |
| 903 |
'prev_text' => __( '« Previous', 'wpvulnerability' ), |
| 904 |
'next_text' => __( 'Next »', 'wpvulnerability' ), |
| 905 |
'type' => 'list', |
| 906 |
) |
| 907 |
); |
| 908 |
} |
| 909 |
|
| 910 |
if ( $requested_log > 0 ) { |
| 911 |
$nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 912 |
if ( $nonce && wp_verify_nonce( $nonce, 'wpvulnerability_view_log_' . $requested_log ) ) { |
| 913 |
$view_log = wpvulnerability_get_api_log( $requested_log ); |
| 914 |
if ( ! $view_log ) { |
| 915 |
$log_error = __( 'Log entry not found or has been removed.', 'wpvulnerability' ); |
| 916 |
} |
| 917 |
} else { |
| 918 |
$log_error = __( 'Unable to load the requested log entry.', 'wpvulnerability' ); |
| 919 |
} |
| 920 |
} |
| 921 |
|
| 922 |
?> |
| 923 |
<section class="section wpvulnerability-logs-panel"> |
| 924 |
|
| 925 |
<?php if ( ! $view_log ) : ?> |
| 926 |
<!-- Configuration Section --> |
| 927 |
<div class="wpvulnerability-security-section"> |
| 928 |
<h3><?php esc_html_e( 'Log Configuration', 'wpvulnerability' ); ?></h3> |
| 929 |
|
| 930 |
<!-- Stats Row --> |
| 931 |
<div class="wpvulnerability-stats-row"> |
| 932 |
<div class="wpvulnerability-stat-card"> |
| 933 |
<div class="wpvulnerability-stat-label"><?php esc_html_e( 'Total Logs', 'wpvulnerability' ); ?></div> |
| 934 |
<div class="wpvulnerability-stat-value"><?php echo esc_html( number_format_i18n( $total_logs ) ); ?></div> |
| 935 |
</div> |
| 936 |
<div class="wpvulnerability-stat-card"> |
| 937 |
<div class="wpvulnerability-stat-label"><?php esc_html_e( 'Retention Period', 'wpvulnerability' ); ?></div> |
| 938 |
<div class="wpvulnerability-stat-value"> |
| 939 |
<?php |
| 940 |
echo esc_html( |
| 941 |
0 === $current |
| 942 |
? __( 'Disabled', 'wpvulnerability' ) |
| 943 |
: sprintf( |
| 944 |
/* translators: %d: Number of days. */ |
| 945 |
_n( '%d day', '%d days', $current, 'wpvulnerability' ), |
| 946 |
$current |
| 947 |
) |
| 948 |
); |
| 949 |
?> |
| 950 |
</div> |
| 951 |
</div> |
| 952 |
</div> |
| 953 |
|
| 954 |
<!-- Config Form --> |
| 955 |
<form method="post" action="options.php" class="wpvulnerability-config-form"> |
| 956 |
<?php settings_fields( 'admin_wpvulnerability_settings' ); ?> |
| 957 |
<label for="wpvulnerability_log_retention"> |
| 958 |
<?php esc_html_e( 'Log Retention Period', 'wpvulnerability' ); ?> |
| 959 |
</label> |
| 960 |
<select name="wpvulnerability-config[log_retention]" id="wpvulnerability_log_retention"<?php disabled( null !== $forced ); ?>> |
| 961 |
<?php |
| 962 |
foreach ( $choices as $days ) { |
| 963 |
$label = 0 === $days |
| 964 |
? __( 'None (Disabled)', 'wpvulnerability' ) |
| 965 |
: sprintf( |
| 966 |
/* translators: %d: Number of days. */ |
| 967 |
_n( '%d day', '%d days', $days, 'wpvulnerability' ), |
| 968 |
$days |
| 969 |
); |
| 970 |
printf( |
| 971 |
'<option value="%1$s"%2$s>%3$s</option>', |
| 972 |
esc_attr( $days ), |
| 973 |
selected( $current, $days, false ), |
| 974 |
esc_html( $label ) |
| 975 |
); |
| 976 |
} |
| 977 |
?> |
| 978 |
</select> |
| 979 |
<?php |
| 980 |
if ( null !== $forced ) { |
| 981 |
printf( |
| 982 |
'<input type="hidden" name="wpvulnerability-config[log_retention]" value="%s" />', |
| 983 |
esc_attr( $forced ) |
| 984 |
); |
| 985 |
printf( |
| 986 |
'<p class="description">%s</p>', |
| 987 |
esc_html__( 'This value is enforced by the WPVULNERABILITY_LOG_RETENTION_DAYS constant.', 'wpvulnerability' ) |
| 988 |
); |
| 989 |
} else { |
| 990 |
printf( |
| 991 |
'<p class="description">%s</p>', |
| 992 |
esc_html__( 'Choose how long WPVulnerability should keep API response logs. Older logs are automatically deleted.', 'wpvulnerability' ) |
| 993 |
); |
| 994 |
} |
| 995 |
?> |
| 996 |
<?php submit_button( __( 'Save Configuration', 'wpvulnerability' ), 'primary', 'submit', false ); ?> |
| 997 |
</form> |
| 998 |
|
| 999 |
<?php if ( 0 === $current ) : ?> |
| 1000 |
<div class="wpvulnerability-info-box" style="margin-top: 20px;"> |
| 1001 |
<p><strong><?php esc_html_e( 'Log retention is currently disabled.', 'wpvulnerability' ); ?></strong> <?php esc_html_e( 'API responses are not being saved.', 'wpvulnerability' ); ?></p> |
| 1002 |
</div> |
| 1003 |
<?php endif; ?> |
| 1004 |
</div> |
| 1005 |
|
| 1006 |
<?php if ( $log_error ) : ?> |
| 1007 |
<div class="notice notice-error"><p><?php echo esc_html( $log_error ); ?></p></div> |
| 1008 |
<?php endif; ?> |
| 1009 |
<?php endif; ?> |
| 1010 |
|
| 1011 |
<?php if ( $view_log ) : ?> |
| 1012 |
<!-- Log Detail View --> |
| 1013 |
<div class="wpvulnerability-log-detail"> |
| 1014 |
<h3><?php esc_html_e( 'Log Details', 'wpvulnerability' ); ?></h3> |
| 1015 |
|
| 1016 |
<div class="wpvulnerability-log-meta"> |
| 1017 |
<div class="wpvulnerability-log-meta-item"> |
| 1018 |
<div class="wpvulnerability-log-meta-label"><?php esc_html_e( 'Date', 'wpvulnerability' ); ?></div> |
| 1019 |
<div class="wpvulnerability-log-meta-value"><?php echo esc_html( wpvulnerability_format_log_date( $view_log ) ); ?></div> |
| 1020 |
</div> |
| 1021 |
<div class="wpvulnerability-log-meta-item"> |
| 1022 |
<div class="wpvulnerability-log-meta-label"><?php esc_html_e( 'API Endpoint', 'wpvulnerability' ); ?></div> |
| 1023 |
<div class="wpvulnerability-log-meta-value"><?php echo esc_html( get_the_title( $view_log ) ); ?></div> |
| 1024 |
</div> |
| 1025 |
</div> |
| 1026 |
|
| 1027 |
<h4 style="margin: 20px 0 12px 0; color: #1d2327; font-size: 15px;"><?php esc_html_e( 'API Response', 'wpvulnerability' ); ?></h4> |
| 1028 |
<pre><code><?php echo esc_html( wpvulnerability_format_log_content( $view_log->post_content ) ); ?></code></pre> |
| 1029 |
|
| 1030 |
<p style="margin-top: 20px;"> |
| 1031 |
<a class="button button-primary" href="<?php echo esc_url( $logs_page_url ); ?>"> |
| 1032 |
← <?php esc_html_e( 'Back to Logs', 'wpvulnerability' ); ?> |
| 1033 |
</a> |
| 1034 |
</p> |
| 1035 |
</div> |
| 1036 |
<?php else : ?> |
| 1037 |
<!-- Logs List Section --> |
| 1038 |
<?php if ( empty( $logs ) ) : ?> |
| 1039 |
<div class="wpvulnerability-empty-state"> |
| 1040 |
<div class="wpvulnerability-empty-state-icon">📋</div> |
| 1041 |
<h3><?php esc_html_e( 'No logs available', 'wpvulnerability' ); ?></h3> |
| 1042 |
<p><?php esc_html_e( 'API response logs will appear here once the vulnerability scanner runs.', 'wpvulnerability' ); ?></p> |
| 1043 |
</div> |
| 1044 |
<?php else : ?> |
| 1045 |
<div class="wpvulnerability-security-section"> |
| 1046 |
<h3><?php esc_html_e( 'API Response Logs', 'wpvulnerability' ); ?></h3> |
| 1047 |
|
| 1048 |
<!-- Toolbar --> |
| 1049 |
<div class="wpvulnerability-toolbar"> |
| 1050 |
<div class="wpvulnerability-toolbar-left"> |
| 1051 |
<form method="get" action="<?php echo esc_url( admin_url( 'options-general.php' ) ); ?>" style="display: flex; align-items: center; gap: 8px; margin: 0;"> |
| 1052 |
<input type="hidden" name="page" value="wpvulnerability-options" /> |
| 1053 |
<input type="hidden" name="tab" value="logs" /> |
| 1054 |
<input type="hidden" name="log_page" value="1" /> |
| 1055 |
<label for="wpvulnerability_logs_per_page" style="margin: 0; font-size: 13px; color: #646970;"> |
| 1056 |
<?php esc_html_e( 'Show:', 'wpvulnerability' ); ?> |
| 1057 |
</label> |
| 1058 |
<select name="logs_per_page" id="wpvulnerability_logs_per_page" style="min-width: 80px;"> |
| 1059 |
<?php foreach ( $per_page_options as $per_page_option ) : ?> |
| 1060 |
<option value="<?php echo esc_attr( $per_page_option ); ?>"<?php selected( $logs_per_page, $per_page_option ); ?>> |
| 1061 |
<?php echo esc_html( number_format_i18n( $per_page_option ) ); ?> |
| 1062 |
</option> |
| 1063 |
<?php endforeach; ?> |
| 1064 |
</select> |
| 1065 |
<?php submit_button( __( 'Apply', 'wpvulnerability' ), 'secondary', 'submit', false, array( 'style' => 'margin: 0; padding: 4px 12px; height: auto;' ) ); ?> |
| 1066 |
</form> |
| 1067 |
</div> |
| 1068 |
<div class="wpvulnerability-toolbar-right"> |
| 1069 |
<span style="font-size: 13px; color: #646970;"> |
| 1070 |
<?php |
| 1071 |
printf( |
| 1072 |
/* translators: 1: first item, 2: last item, 3: total items */ |
| 1073 |
esc_html__( 'Showing %1$s–%2$s of %3$s', 'wpvulnerability' ), |
| 1074 |
esc_html( number_format_i18n( ( ( $current_page - 1 ) * $logs_per_page ) + 1 ) ), |
| 1075 |
esc_html( number_format_i18n( min( $current_page * $logs_per_page, $total_logs ) ) ), |
| 1076 |
esc_html( number_format_i18n( $total_logs ) ) |
| 1077 |
); |
| 1078 |
?> |
| 1079 |
</span> |
| 1080 |
</div> |
| 1081 |
</div> |
| 1082 |
|
| 1083 |
<!-- Logs Table --> |
| 1084 |
<table class="wpvulnerability-logs-table"> |
| 1085 |
<thead> |
| 1086 |
<tr> |
| 1087 |
<th style="width: 200px;"><?php esc_html_e( 'Date', 'wpvulnerability' ); ?></th> |
| 1088 |
<th><?php esc_html_e( 'API Endpoint', 'wpvulnerability' ); ?></th> |
| 1089 |
<th style="width: 100px; text-align: center;"><?php esc_html_e( 'Actions', 'wpvulnerability' ); ?></th> |
| 1090 |
</tr> |
| 1091 |
</thead> |
| 1092 |
<tbody> |
| 1093 |
<?php foreach ( $logs as $log ) : ?> |
| 1094 |
<tr> |
| 1095 |
<td> |
| 1096 |
<span class="wpvulnerability-log-date"><?php echo esc_html( wpvulnerability_format_log_date( $log ) ); ?></span> |
| 1097 |
</td> |
| 1098 |
<td> |
| 1099 |
<span class="wpvulnerability-log-url"><?php echo esc_html( get_the_title( $log ) ); ?></span> |
| 1100 |
</td> |
| 1101 |
<td style="text-align: center;"> |
| 1102 |
<?php |
| 1103 |
$view_url = add_query_arg( |
| 1104 |
array( |
| 1105 |
'page' => 'wpvulnerability-options', |
| 1106 |
'tab' => 'logs', |
| 1107 |
'log' => $log->ID, |
| 1108 |
'logs_per_page' => $logs_per_page, |
| 1109 |
'log_page' => $current_page, |
| 1110 |
), |
| 1111 |
admin_url( 'options-general.php' ) |
| 1112 |
); |
| 1113 |
$view_url = wp_nonce_url( $view_url, 'wpvulnerability_view_log_' . $log->ID ); |
| 1114 |
?> |
| 1115 |
<a class="button button-small" href="<?php echo esc_url( $view_url ); ?>"> |
| 1116 |
<?php esc_html_e( 'View', 'wpvulnerability' ); ?> |
| 1117 |
</a> |
| 1118 |
</td> |
| 1119 |
</tr> |
| 1120 |
<?php endforeach; ?> |
| 1121 |
</tbody> |
| 1122 |
</table> |
| 1123 |
|
| 1124 |
<!-- Pagination --> |
| 1125 |
<?php if ( $pagination ) : ?> |
| 1126 |
<div class="wpvulnerability-pagination"> |
| 1127 |
<?php echo wp_kses_post( $pagination ); ?> |
| 1128 |
</div> |
| 1129 |
<?php endif; ?> |
| 1130 |
|
| 1131 |
<!-- Danger Zone --> |
| 1132 |
<div class="wpvulnerability-danger-zone"> |
| 1133 |
<h4><?php esc_html_e( 'Danger Zone', 'wpvulnerability' ); ?></h4> |
| 1134 |
<p style="margin: 0 0 12px 0; font-size: 13px; color: #646970;"> |
| 1135 |
<?php esc_html_e( 'Permanently delete all API response logs. This action cannot be undone.', 'wpvulnerability' ); ?> |
| 1136 |
</p> |
| 1137 |
<form method="post" action="" onsubmit="return confirm('<?php echo esc_js( __( 'Are you sure you want to delete all logs? This action cannot be undone.', 'wpvulnerability' ) ); ?>');"> |
| 1138 |
<?php wp_nonce_field( 'wpvulnerability_delete_logs_action', 'wpvulnerability_delete_logs_nonce' ); ?> |
| 1139 |
<input type="hidden" name="wpvulnerability_delete_logs" value="1" /> |
| 1140 |
<?php submit_button( __( 'Delete All Logs', 'wpvulnerability' ), 'delete', 'submit', false ); ?> |
| 1141 |
</form> |
| 1142 |
</div> |
| 1143 |
</div> |
| 1144 |
<?php endif; ?> |
| 1145 |
<?php endif; ?> |
| 1146 |
</section> |
| 1147 |
<?php |
| 1148 |
} |
| 1149 |
|
| 1150 |
/** |
| 1151 |
* Outputs the Tools tab contents. |
| 1152 |
* |
| 1153 |
* @since 4.1.2 |
| 1154 |
* |
| 1155 |
* @return void |
| 1156 |
*/ |
| 1157 |
function wpvulnerability_render_admin_tab_tools() { |
| 1158 |
global $wpvulnerability_settings; |
| 1159 |
|
| 1160 |
$tools_action = add_query_arg( |
| 1161 |
array( |
| 1162 |
'page' => 'wpvulnerability-options', |
| 1163 |
'tab' => 'tools', |
| 1164 |
), |
| 1165 |
admin_url( 'options-general.php' ) |
| 1166 |
); |
| 1167 |
|
| 1168 |
$wpvulnerability_cron_config = is_multisite() ? get_site_option( 'wpvulnerability-config', array() ) : get_option( 'wpvulnerability-config', array() ); |
| 1169 |
$is_main_site = ( ! is_multisite() || is_main_site() ); |
| 1170 |
$cron_status = wpvulnerability_get_cron_status( $wpvulnerability_cron_config, $is_main_site ); |
| 1171 |
$cron_schedules = function_exists( 'wp_get_schedules' ) ? wp_get_schedules() : array(); |
| 1172 |
$date_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' ); |
| 1173 |
?> |
| 1174 |
<section class="section wpvulnerability-tools-panel"> |
| 1175 |
|
| 1176 |
<!-- Reload Data Tool --> |
| 1177 |
<div class="wpvulnerability-tool-card"> |
| 1178 |
<h3> |
| 1179 |
<span class="wpvulnerability-tool-icon">🔄</span> |
| 1180 |
<?php esc_html_e( 'Reload Data from API', 'wpvulnerability' ); ?> |
| 1181 |
</h3> |
| 1182 |
<p class="wpvulnerability-tool-description"> |
| 1183 |
<?php esc_html_e( 'Reload all Core, Plugins, Themes and other components information directly from the API to have updated data. This will clear the cache and fetch fresh vulnerability information.', 'wpvulnerability' ); ?> |
| 1184 |
</p> |
| 1185 |
<div class="wpvulnerability-tool-actions"> |
| 1186 |
<form method="post" action="<?php echo esc_url( $tools_action ); ?>" style="display: inline;"> |
| 1187 |
<?php wp_nonce_field( 'wpvulnerability_reset_action', 'wpvulnerability_reset_nonce' ); ?> |
| 1188 |
<input type="submit" name="wpvulnerability_reset" value="<?php esc_attr_e( 'Reload Data', 'wpvulnerability' ); ?>" class="button button-primary"> |
| 1189 |
</form> |
| 1190 |
</div> |
| 1191 |
</div> |
| 1192 |
|
| 1193 |
<!-- Email Test Tool --> |
| 1194 |
<div class="wpvulnerability-tool-card"> |
| 1195 |
<h3> |
| 1196 |
<span class="wpvulnerability-tool-icon">📧</span> |
| 1197 |
<?php esc_html_e( 'Test Email Notifications', 'wpvulnerability' ); ?> |
| 1198 |
</h3> |
| 1199 |
<p class="wpvulnerability-tool-description"> |
| 1200 |
<?php esc_html_e( 'Send a test email notification with current vulnerability data to verify your email configuration is working correctly.', 'wpvulnerability' ); ?> |
| 1201 |
</p> |
| 1202 |
<?php |
| 1203 |
$from_email = null; |
| 1204 |
if ( defined( 'WPVULNERABILITY_MAIL' ) ) { |
| 1205 |
$from_email = sanitize_email( trim( (string) WPVULNERABILITY_MAIL ) ); |
| 1206 |
if ( is_email( $from_email ) ) { |
| 1207 |
?> |
| 1208 |
<div class="wpvulnerability-info-box"> |
| 1209 |
<p> |
| 1210 |
<strong><?php esc_html_e( 'From address (configured via constant):', 'wpvulnerability' ); ?></strong> |
| 1211 |
<code><?php echo esc_html( $from_email ); ?></code> |
| 1212 |
</p> |
| 1213 |
</div> |
| 1214 |
<?php |
| 1215 |
} |
| 1216 |
} |
| 1217 |
if ( ! $from_email ) { |
| 1218 |
$from_email = get_bloginfo( 'admin_email' ); |
| 1219 |
?> |
| 1220 |
<div class="wpvulnerability-info-box"> |
| 1221 |
<p> |
| 1222 |
<strong><?php esc_html_e( 'From address (default):', 'wpvulnerability' ); ?></strong> |
| 1223 |
<code><?php echo esc_html( $from_email ); ?></code> |
| 1224 |
</p> |
| 1225 |
</div> |
| 1226 |
<?php |
| 1227 |
} |
| 1228 |
?> |
| 1229 |
<p style="margin: 8px 0; font-size: 13px;"> |
| 1230 |
<a href="https://www.wpvulnerability.com/plugin/#from-mail" target="_blank" rel="noopener noreferrer"> |
| 1231 |
<?php esc_html_e( 'Learn how to customize the email sender address →', 'wpvulnerability' ); ?> |
| 1232 |
</a> |
| 1233 |
</p> |
| 1234 |
<div class="wpvulnerability-tool-actions"> |
| 1235 |
<form method="post" action="<?php echo esc_url( $tools_action ); ?>" style="display: inline;"> |
| 1236 |
<?php wp_nonce_field( 'wpvulnerability_email_action', 'wpvulnerability_email_nonce' ); ?> |
| 1237 |
<input type="submit" name="wpvulnerability_email" value="<?php esc_attr_e( 'Send Test Email', 'wpvulnerability' ); ?>" class="button button-primary"> |
| 1238 |
</form> |
| 1239 |
</div> |
| 1240 |
</div> |
| 1241 |
|
| 1242 |
<!-- WP-Cron Status Tool --> |
| 1243 |
<div class="wpvulnerability-tool-card"> |
| 1244 |
<h3> |
| 1245 |
<span class="wpvulnerability-tool-icon">⏰</span> |
| 1246 |
<?php esc_html_e( 'WP-Cron Status', 'wpvulnerability' ); ?> |
| 1247 |
</h3> |
| 1248 |
<p class="wpvulnerability-tool-description"> |
| 1249 |
<?php esc_html_e( 'View and manage WP-Cron scheduled events. Compare expected schedules with actual cron jobs to ensure automated tasks are running correctly.', 'wpvulnerability' ); ?> |
| 1250 |
</p> |
| 1251 |
|
| 1252 |
<?php if ( empty( $cron_status['expected'] ) ) : ?> |
| 1253 |
<div class="wpvulnerability-info-box"> |
| 1254 |
<p><?php esc_html_e( 'No cron data available.', 'wpvulnerability' ); ?></p> |
| 1255 |
</div> |
| 1256 |
<?php else : ?> |
| 1257 |
<table class="wpvulnerability-cron-table"> |
| 1258 |
<thead> |
| 1259 |
<tr> |
| 1260 |
<th><?php esc_html_e( 'Hook', 'wpvulnerability' ); ?></th> |
| 1261 |
<th><?php esc_html_e( 'Expected', 'wpvulnerability' ); ?></th> |
| 1262 |
<th><?php esc_html_e( 'Found', 'wpvulnerability' ); ?></th> |
| 1263 |
<th><?php esc_html_e( 'Next Run', 'wpvulnerability' ); ?></th> |
| 1264 |
<th><?php esc_html_e( 'Status', 'wpvulnerability' ); ?></th> |
| 1265 |
</tr> |
| 1266 |
</thead> |
| 1267 |
<tbody> |
| 1268 |
<?php foreach ( $cron_status['expected'] as $row ) : ?> |
| 1269 |
<?php |
| 1270 |
$expected_schedule = isset( $row['schedule'] ) ? (string) $row['schedule'] : ''; |
| 1271 |
$schedule_label = ''; |
| 1272 |
if ( ! $row['should_exist'] ) { |
| 1273 |
$schedule_label = __( 'Not expected', 'wpvulnerability' ); |
| 1274 |
} elseif ( '' === $expected_schedule ) { |
| 1275 |
$schedule_label = __( 'Disabled', 'wpvulnerability' ); |
| 1276 |
} elseif ( isset( $cron_schedules[ $expected_schedule ]['display'] ) ) { |
| 1277 |
$schedule_label = $cron_schedules[ $expected_schedule ]['display']; |
| 1278 |
} else { |
| 1279 |
$schedule_label = $expected_schedule; |
| 1280 |
} |
| 1281 |
|
| 1282 |
$found_schedules = array(); |
| 1283 |
if ( ! empty( $row['schedules_found'] ) ) { |
| 1284 |
foreach ( $row['schedules_found'] as $schedule_id ) { |
| 1285 |
if ( isset( $cron_schedules[ $schedule_id ]['display'] ) ) { |
| 1286 |
$found_schedules[] = $cron_schedules[ $schedule_id ]['display']; |
| 1287 |
} else { |
| 1288 |
$found_schedules[] = $schedule_id; |
| 1289 |
} |
| 1290 |
} |
| 1291 |
} |
| 1292 |
|
| 1293 |
$found_label = $row['count'] > 0 ? implode( ', ', $found_schedules ) : __( 'None', 'wpvulnerability' ); |
| 1294 |
$next_run = ( isset( $row['next_run'] ) && $row['next_run'] ) ? date_i18n( $date_format, (int) $row['next_run'] ) : '—'; |
| 1295 |
$status_text = isset( $row['messages'] ) && is_array( $row['messages'] ) ? implode( ' ', $row['messages'] ) : ''; |
| 1296 |
|
| 1297 |
// Determine status badge class. |
| 1298 |
$status_class = 'success'; |
| 1299 |
if ( strpos( $status_text, 'Missing' ) !== false || strpos( $status_text, 'Duplicate' ) !== false ) { |
| 1300 |
$status_class = 'error'; |
| 1301 |
} elseif ( strpos( $status_text, 'legacy' ) !== false ) { |
| 1302 |
$status_class = 'warning'; |
| 1303 |
} |
| 1304 |
?> |
| 1305 |
<tr> |
| 1306 |
<td> |
| 1307 |
<strong><?php echo esc_html( isset( $row['label'] ) ? $row['label'] : $row['hook'] ); ?></strong><br> |
| 1308 |
<code><?php echo esc_html( $row['hook'] ); ?></code> |
| 1309 |
</td> |
| 1310 |
<td><?php echo esc_html( $schedule_label ); ?></td> |
| 1311 |
<td><?php echo esc_html( $found_label ); ?></td> |
| 1312 |
<td><?php echo esc_html( $next_run ); ?></td> |
| 1313 |
<td> |
| 1314 |
<?php if ( $status_text ) : ?> |
| 1315 |
<span class="wpvulnerability-status-badge <?php echo esc_attr( $status_class ); ?>"> |
| 1316 |
<?php echo esc_html( $status_text ); ?> |
| 1317 |
</span> |
| 1318 |
<?php else : ?> |
| 1319 |
<span class="wpvulnerability-status-badge success">✓ <?php esc_html_e( 'OK', 'wpvulnerability' ); ?></span> |
| 1320 |
<?php endif; ?> |
| 1321 |
</td> |
| 1322 |
</tr> |
| 1323 |
<?php endforeach; ?> |
| 1324 |
</tbody> |
| 1325 |
</table> |
| 1326 |
|
| 1327 |
<?php if ( ! empty( $cron_status['unexpected'] ) ) : ?> |
| 1328 |
<div class="wpvulnerability-unexpected-list"> |
| 1329 |
<h4><?php esc_html_e( '⚠️ Unexpected WPVulnerability Events', 'wpvulnerability' ); ?></h4> |
| 1330 |
<ul> |
| 1331 |
<?php foreach ( $cron_status['unexpected'] as $unexpected ) : ?> |
| 1332 |
<?php |
| 1333 |
$unexpected_schedules = array(); |
| 1334 |
if ( ! empty( $unexpected['schedules'] ) ) { |
| 1335 |
foreach ( $unexpected['schedules'] as $schedule_id ) { |
| 1336 |
if ( isset( $cron_schedules[ $schedule_id ]['display'] ) ) { |
| 1337 |
$unexpected_schedules[] = $cron_schedules[ $schedule_id ]['display']; |
| 1338 |
} else { |
| 1339 |
$unexpected_schedules[] = $schedule_id; |
| 1340 |
} |
| 1341 |
} |
| 1342 |
} |
| 1343 |
$unexpected_label = empty( $unexpected_schedules ) ? __( 'No interval', 'wpvulnerability' ) : implode( ', ', $unexpected_schedules ); |
| 1344 |
$unexpected_next = ( isset( $unexpected['next_run'] ) && $unexpected['next_run'] ) ? date_i18n( $date_format, (int) $unexpected['next_run'] ) : '—'; |
| 1345 |
?> |
| 1346 |
<li> |
| 1347 |
<code><?php echo esc_html( $unexpected['hook'] ); ?></code> |
| 1348 |
– <?php echo esc_html( $unexpected_label ); ?> |
| 1349 |
– <?php esc_html_e( 'Next:', 'wpvulnerability' ); ?> <?php echo esc_html( $unexpected_next ); ?> |
| 1350 |
</li> |
| 1351 |
<?php endforeach; ?> |
| 1352 |
</ul> |
| 1353 |
</div> |
| 1354 |
<?php endif; ?> |
| 1355 |
|
| 1356 |
<div class="wpvulnerability-tool-actions"> |
| 1357 |
<form method="post" action="<?php echo esc_url( $tools_action ); ?>" style="display: inline;"> |
| 1358 |
<?php wp_nonce_field( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ); ?> |
| 1359 |
<input type="submit" name="wpvulnerability_repair_cron" value="<?php esc_attr_e( 'Repair Cron Events', 'wpvulnerability' ); ?>" class="button button-secondary"> |
| 1360 |
</form> |
| 1361 |
</div> |
| 1362 |
<?php endif; ?> |
| 1363 |
</div> |
| 1364 |
|
| 1365 |
<!-- Reset Plugin Tool --> |
| 1366 |
<div class="wpvulnerability-tool-card"> |
| 1367 |
<div class="wpvulnerability-danger-zone"> |
| 1368 |
<h4>⚠️ <?php esc_html_e( 'Reset WPVulnerability', 'wpvulnerability' ); ?></h4> |
| 1369 |
<p style="margin: 0 0 16px 0; color: #646970; font-size: 13px; line-height: 1.6;"> |
| 1370 |
<?php esc_html_e( 'Delete all WPVulnerability settings, cached data, logs, and scheduled events, then restore defaults and reload data from the API.', 'wpvulnerability' ); ?> |
| 1371 |
<br> |
| 1372 |
<strong style="color: #b32d2e;"><?php esc_html_e( 'This action cannot be undone.', 'wpvulnerability' ); ?></strong> |
| 1373 |
</p> |
| 1374 |
<form method="post" action="<?php echo esc_url( $tools_action ); ?>" onsubmit="return confirm('<?php echo esc_js( __( 'Are you sure you want to reset all WPVulnerability data? This action cannot be undone.', 'wpvulnerability' ) ); ?>');"> |
| 1375 |
<?php wp_nonce_field( 'wpvulnerability_reset_action', 'wpvulnerability_reset_nonce' ); ?> |
| 1376 |
<?php wp_nonce_field( 'wpvulnerability_full_reset_action', 'wpvulnerability_full_reset_nonce' ); ?> |
| 1377 |
<input type="submit" name="wpvulnerability_full_reset" value="<?php esc_attr_e( 'Reset Plugin', 'wpvulnerability' ); ?>" class="button button-delete"> |
| 1378 |
</form> |
| 1379 |
</div> |
| 1380 |
</div> |
| 1381 |
</section> |
| 1382 |
<?php |
| 1383 |
} |
| 1384 |
|
| 1385 |
/** |
| 1386 |
* Outputs the About tab contents. |
| 1387 |
* |
| 1388 |
* @since 4.1.2 |
| 1389 |
* |
| 1390 |
* @return void |
| 1391 |
*/ |
| 1392 |
function wpvulnerability_render_admin_tab_about() { |
| 1393 |
$wpvulnerability_statistics = json_decode( get_option( 'wpvulnerability-statistics' ), true ); |
| 1394 |
|
| 1395 |
if ( ! is_array( $wpvulnerability_statistics ) ) { |
| 1396 |
$wpvulnerability_statistics = array(); |
| 1397 |
} |
| 1398 |
|
| 1399 |
?> |
| 1400 |
<section class="section wpvulnerability-about-panel"> |
| 1401 |
|
| 1402 |
<!-- Database Statistics Section --> |
| 1403 |
<div class="wpvulnerability-security-section"> |
| 1404 |
<h3><?php esc_html_e( 'Vulnerability Database Statistics', 'wpvulnerability' ); ?></h3> |
| 1405 |
|
| 1406 |
<?php |
| 1407 |
$components = array( |
| 1408 |
'plugins' => __( 'Plugins', 'wpvulnerability' ), |
| 1409 |
'themes' => __( 'Themes', 'wpvulnerability' ), |
| 1410 |
'php' => __( 'PHP', 'wpvulnerability' ), |
| 1411 |
'apache' => __( 'Apache HTTPD', 'wpvulnerability' ), |
| 1412 |
'nginx' => __( 'nginx', 'wpvulnerability' ), |
| 1413 |
'mariadb' => __( 'MariaDB', 'wpvulnerability' ), |
| 1414 |
'mysql' => __( 'MySQL', 'wpvulnerability' ), |
| 1415 |
'imagemagick' => __( 'ImageMagick', 'wpvulnerability' ), |
| 1416 |
'curl' => __( 'curl', 'wpvulnerability' ), |
| 1417 |
'memcached' => __( 'memcached', 'wpvulnerability' ), |
| 1418 |
'redis' => __( 'Redis', 'wpvulnerability' ), |
| 1419 |
'sqlite' => __( 'SQLite', 'wpvulnerability' ), |
| 1420 |
); |
| 1421 |
?> |
| 1422 |
|
| 1423 |
<div class="wpvulnerability-stats-grid"> |
| 1424 |
<?php foreach ( $components as $component => $label ) : ?> |
| 1425 |
<?php |
| 1426 |
$has_data = isset( $wpvulnerability_statistics[ $component ] ); |
| 1427 |
$card_class = 'wpvulnerability-stat-card'; |
| 1428 |
if ( ! $has_data ) { |
| 1429 |
$card_class .= ' wpvulnerability-no-data'; |
| 1430 |
} |
| 1431 |
?> |
| 1432 |
<div class="<?php echo esc_attr( $card_class ); ?>"> |
| 1433 |
<div class="wpvulnerability-stat-label"><?php echo esc_html( $label ); ?></div> |
| 1434 |
<?php if ( $has_data ) : ?> |
| 1435 |
<div class="wpvulnerability-stat-value"> |
| 1436 |
<?php echo esc_html( number_format_i18n( absint( $wpvulnerability_statistics[ $component ]['vulnerabilities'] ) ) ); ?> |
| 1437 |
</div> |
| 1438 |
<div class="wpvulnerability-stat-meta"> |
| 1439 |
<?php |
| 1440 |
printf( |
| 1441 |
// translators: number of vulnerabilities. |
| 1442 |
esc_html( _n( '%s vulnerability', '%s vulnerabilities', absint( $wpvulnerability_statistics[ $component ]['vulnerabilities'] ), 'wpvulnerability' ) ), |
| 1443 |
'' |
| 1444 |
); |
| 1445 |
?> |
| 1446 |
<?php if ( isset( $wpvulnerability_statistics[ $component ]['products'] ) ) : ?> |
| 1447 |
<br> |
| 1448 |
<?php |
| 1449 |
printf( |
| 1450 |
// translators: number of products. |
| 1451 |
esc_html( _n( '(%s product)', '(%s products)', absint( $wpvulnerability_statistics[ $component ]['products'] ), 'wpvulnerability' ) ), |
| 1452 |
esc_html( number_format_i18n( absint( $wpvulnerability_statistics[ $component ]['products'] ) ) ) |
| 1453 |
); |
| 1454 |
?> |
| 1455 |
<?php endif; ?> |
| 1456 |
</div> |
| 1457 |
<?php else : ?> |
| 1458 |
<div class="wpvulnerability-stat-value"><?php esc_html_e( 'No data', 'wpvulnerability' ); ?></div> |
| 1459 |
<?php endif; ?> |
| 1460 |
</div> |
| 1461 |
<?php endforeach; ?> |
| 1462 |
</div> |
| 1463 |
|
| 1464 |
<?php if ( isset( $wpvulnerability_statistics['updated'] ) ) : ?> |
| 1465 |
<div class="wpvulnerability-info-box"> |
| 1466 |
<p> |
| 1467 |
<?php |
| 1468 |
if ( version_compare( $GLOBALS['wp_version'], '5.0', '>=' ) ) { |
| 1469 |
switch_to_locale( determine_locale() ); |
| 1470 |
} elseif ( version_compare( $GLOBALS['wp_version'], '4.7', '>=' ) ) { |
| 1471 |
switch_to_locale( get_locale() ); |
| 1472 |
} |
| 1473 |
$formatted_datetime = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), (int) $wpvulnerability_statistics['updated']['unixepoch'] ); |
| 1474 |
// translators: date of last update. |
| 1475 |
printf( esc_html__( 'Database last updated: %s', 'wpvulnerability' ), '<strong>' . esc_html( $formatted_datetime ) . '</strong>' ); |
| 1476 |
if ( version_compare( $GLOBALS['wp_version'], '4.7', '>=' ) ) { |
| 1477 |
restore_previous_locale(); |
| 1478 |
} |
| 1479 |
?> |
| 1480 |
</p> |
| 1481 |
</div> |
| 1482 |
<?php endif; ?> |
| 1483 |
</div> |
| 1484 |
|
| 1485 |
<!-- Sponsors Section --> |
| 1486 |
<div class="wpvulnerability-security-section"> |
| 1487 |
<h3><?php esc_html_e( 'Sponsors', 'wpvulnerability' ); ?></h3> |
| 1488 |
|
| 1489 |
<?php if ( isset( $wpvulnerability_statistics['sponsors'] ) && ! empty( $wpvulnerability_statistics['sponsors'] ) ) : ?> |
| 1490 |
<div class="wpvulnerability-people-grid"> |
| 1491 |
<?php foreach ( $wpvulnerability_statistics['sponsors'] as $sponsor ) : ?> |
| 1492 |
<div class="wpvulnerability-person-card"> |
| 1493 |
<img src="<?php echo esc_url( $sponsor['image'] ); ?>" alt="<?php echo esc_attr( $sponsor['name'] ); ?>"> |
| 1494 |
<a href="<?php echo esc_url( $sponsor['url'] ); ?>" target="_blank" rel="noreferrer noopener"> |
| 1495 |
<?php echo esc_html( $sponsor['name'] ); ?> |
| 1496 |
</a> |
| 1497 |
</div> |
| 1498 |
<?php endforeach; ?> |
| 1499 |
</div> |
| 1500 |
<?php else : ?> |
| 1501 |
<div class="wpvulnerability-empty-state"> |
| 1502 |
<div class="wpvulnerability-empty-state-icon">💎</div> |
| 1503 |
<p><strong><?php esc_html_e( 'No sponsor data available.', 'wpvulnerability' ); ?></strong></p> |
| 1504 |
</div> |
| 1505 |
<?php endif; ?> |
| 1506 |
</div> |
| 1507 |
|
| 1508 |
<!-- Contributors Section --> |
| 1509 |
<div class="wpvulnerability-security-section"> |
| 1510 |
<h3><?php esc_html_e( 'Contributors', 'wpvulnerability' ); ?></h3> |
| 1511 |
|
| 1512 |
<?php if ( isset( $wpvulnerability_statistics['contributors'] ) && ! empty( $wpvulnerability_statistics['contributors'] ) ) : ?> |
| 1513 |
<div class="wpvulnerability-people-grid"> |
| 1514 |
<?php foreach ( $wpvulnerability_statistics['contributors'] as $contributor ) : ?> |
| 1515 |
<div class="wpvulnerability-person-card"> |
| 1516 |
<img src="<?php echo esc_url( $contributor['image'] ); ?>" alt="<?php echo esc_attr( $contributor['name'] ); ?>"> |
| 1517 |
<a href="<?php echo esc_url( $contributor['url'] ); ?>" target="_blank" rel="noreferrer noopener"> |
| 1518 |
<?php echo esc_html( $contributor['name'] ); ?> |
| 1519 |
</a> |
| 1520 |
</div> |
| 1521 |
<?php endforeach; ?> |
| 1522 |
</div> |
| 1523 |
<?php else : ?> |
| 1524 |
<div class="wpvulnerability-empty-state"> |
| 1525 |
<div class="wpvulnerability-empty-state-icon">👥</div> |
| 1526 |
<p><strong><?php esc_html_e( 'No contributor data available.', 'wpvulnerability' ); ?></strong></p> |
| 1527 |
</div> |
| 1528 |
<?php endif; ?> |
| 1529 |
</div> |
| 1530 |
</section> |
| 1531 |
<?php |
| 1532 |
} |
| 1533 |
|
| 1534 |
/** |
| 1535 |
* Renders the plugin settings page in the WordPress admin area. |
| 1536 |
* |
| 1537 |
* @since 2.0.0 |
| 1538 |
* |
| 1539 |
* @return void |
| 1540 |
*/ |
| 1541 |
function wpvulnerability_create_admin_page() { |
| 1542 |
|
| 1543 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config' ); |
| 1544 |
?> |
| 1545 |
<div class="header-wrap"> |
| 1546 |
<div class="wrapper"> |
| 1547 |
<div class="header wpvulnerability-header"> |
| 1548 |
<div class="logo"> |
| 1549 |
<img src="<?php echo esc_url( WPVULNERABILITY_PLUGIN_URL ); ?>assets/icon.svg" style="height: 64px; vertical-align: text-top; width: 64px;" alt="" title="WPVulnerability"> |
| 1550 |
<h2><?php esc_html_e( 'WPVulnerability settings', 'wpvulnerability' ); ?></h2> |
| 1551 |
</div> |
| 1552 |
</div> |
| 1553 |
</div> |
| 1554 |
</div> |
| 1555 |
<?php |
| 1556 |
$wpvulnerability_message_manual_success = get_transient( 'wpvulnerability_message_manual_success' ); |
| 1557 |
if ( $wpvulnerability_message_manual_success ) { |
| 1558 |
echo '<div class="notice notice-success"><p>' . esc_html( (string) $wpvulnerability_message_manual_success ) . '</p></div>'; |
| 1559 |
delete_transient( 'wpvulnerability_message_manual_success' ); |
| 1560 |
unset( $wpvulnerability_message_manual_success ); |
| 1561 |
} |
| 1562 |
$wpvulnerability_message_manual_error = get_transient( 'wpvulnerability_message_manual_error' ); |
| 1563 |
if ( $wpvulnerability_message_manual_error ) { |
| 1564 |
echo '<div class="notice notice-error"><p>' . esc_html( (string) $wpvulnerability_message_manual_error ) . '</p></div>'; |
| 1565 |
delete_transient( 'wpvulnerability_message_manual_error' ); |
| 1566 |
unset( $wpvulnerability_message_manual_error ); |
| 1567 |
} |
| 1568 |
settings_errors( 'admin_wpvulnerability_settings' ); |
| 1569 |
settings_errors( 'admin_wpvulnerability_analyze' ); |
| 1570 |
|
| 1571 |
$tabs = wpvulnerability_get_admin_tabs(); |
| 1572 |
|
| 1573 |
if ( empty( $tabs ) ) { |
| 1574 |
return; |
| 1575 |
} |
| 1576 |
|
| 1577 |
$current_tab = wpvulnerability_get_current_admin_tab( $tabs ); |
| 1578 |
|
| 1579 |
if ( ! isset( $tabs[ $current_tab ] ) ) { |
| 1580 |
$tab_keys = array_keys( $tabs ); |
| 1581 |
$current_tab = reset( $tab_keys ); |
| 1582 |
} |
| 1583 |
|
| 1584 |
?> |
| 1585 |
<div class="wrap"> |
| 1586 |
<div class="wpvulnerability-settings"> |
| 1587 |
<h2 class="nav-tab-wrapper wpvulnerability-tab-nav" role="tablist"> |
| 1588 |
<?php |
| 1589 |
foreach ( $tabs as $tab_slug => $tab_data ) { |
| 1590 |
$tab_label = isset( $tab_data['label'] ) ? $tab_data['label'] : ''; |
| 1591 |
$is_active = ( $tab_slug === $current_tab ); |
| 1592 |
$tab_url = add_query_arg( |
| 1593 |
array( |
| 1594 |
'page' => 'wpvulnerability-options', |
| 1595 |
'tab' => $tab_slug, |
| 1596 |
), |
| 1597 |
admin_url( 'options-general.php' ) |
| 1598 |
); |
| 1599 |
$tab_class = 'nav-tab wpvulnerability-tab-link'; |
| 1600 |
if ( $is_active ) { |
| 1601 |
$tab_class .= ' nav-tab-active'; |
| 1602 |
} |
| 1603 |
?> |
| 1604 |
<a |
| 1605 |
href="<?php echo esc_url( $tab_url ); ?>" |
| 1606 |
class="<?php echo esc_attr( $tab_class ); ?>" |
| 1607 |
id="<?php echo esc_attr( 'wpvulnerability-tab-link-' . $tab_slug ); ?>" |
| 1608 |
role="tab" |
| 1609 |
aria-controls="<?php echo esc_attr( 'wpvulnerability-tab-panel-' . $tab_slug ); ?>" |
| 1610 |
aria-selected="<?php echo $is_active ? 'true' : 'false'; ?>" |
| 1611 |
<?php |
| 1612 |
if ( ! $is_active ) : |
| 1613 |
?> |
| 1614 |
tabindex="-1"<?php endif; ?> |
| 1615 |
> |
| 1616 |
<?php echo esc_html( $tab_label ); ?> |
| 1617 |
</a> |
| 1618 |
<?php |
| 1619 |
} |
| 1620 |
?> |
| 1621 |
</h2> |
| 1622 |
<div |
| 1623 |
id="<?php echo esc_attr( 'wpvulnerability-tab-panel-' . $current_tab ); ?>" |
| 1624 |
class="wpvulnerability-tab-panel is-active" |
| 1625 |
role="tabpanel" |
| 1626 |
aria-labelledby="<?php echo esc_attr( 'wpvulnerability-tab-link-' . $current_tab ); ?>" |
| 1627 |
tabindex="0" |
| 1628 |
> |
| 1629 |
<?php wpvulnerability_render_admin_tab( $current_tab ); ?> |
| 1630 |
</div> |
| 1631 |
</div> |
| 1632 |
</div> |
| 1633 |
<?php |
| 1634 |
} |
| 1635 |
|
| 1636 |
/** |
| 1637 |
* Registers the WPVulnerability settings page within the Settings menu. |
| 1638 |
* |
| 1639 |
* @since 2.0.0 |
| 1640 |
* |
| 1641 |
* @return void |
| 1642 |
*/ |
| 1643 |
function wpvulnerability_admin_menu() { |
| 1644 |
|
| 1645 |
// Adds a submenu page under the Settings menu. |
| 1646 |
add_submenu_page( |
| 1647 |
'options-general.php', |
| 1648 |
__( 'WPVulnerability', 'wpvulnerability' ), |
| 1649 |
__( 'WPVulnerability', 'wpvulnerability' ), |
| 1650 |
'manage_options', |
| 1651 |
'wpvulnerability-options', |
| 1652 |
'wpvulnerability_create_admin_page' |
| 1653 |
); |
| 1654 |
} |
| 1655 |
add_action( 'admin_menu', 'wpvulnerability_admin_menu' ); |
| 1656 |
|
| 1657 |
/** |
| 1658 |
* Print the settings header information for the notifications section. |
| 1659 |
* |
| 1660 |
* @since 2.0.0 |
| 1661 |
* |
| 1662 |
* @return void |
| 1663 |
*/ |
| 1664 |
function wpvulnerability_admin_section_notifications() { |
| 1665 |
|
| 1666 |
// Output the header information for the notifications section. |
| 1667 |
esc_html_e( 'Configure and save these settings to receive notifications.', 'wpvulnerability' ); |
| 1668 |
} |
| 1669 |
|
| 1670 |
/** |
| 1671 |
* Print the settings header information for the analyze section. |
| 1672 |
* |
| 1673 |
* @since 3.3.0 |
| 1674 |
* |
| 1675 |
* @return void |
| 1676 |
*/ |
| 1677 |
function wpvulnerability_admin_section_analyze() { |
| 1678 |
|
| 1679 |
// Output the header information for the analyze section. |
| 1680 |
esc_html_e( 'Configure and save these settings to hide vulnerabilities.', 'wpvulnerability' ); |
| 1681 |
} |
| 1682 |
|
| 1683 |
/** |
| 1684 |
* Callback function to display the email input field in the admin settings page. |
| 1685 |
* This function retrieves the current WPVulnerability plugin settings and displays the email input field |
| 1686 |
* for users to enter their email addresses. If no email is saved in the settings, the admin email is displayed. |
| 1687 |
* |
| 1688 |
* @since 2.0.0 |
| 1689 |
* |
| 1690 |
* @return void |
| 1691 |
*/ |
| 1692 |
function wpvulnerability_admin_emails_callback() { |
| 1693 |
|
| 1694 |
// Retrieve the WPVulnerability plugin settings. |
| 1695 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config' ); |
| 1696 |
|
| 1697 |
// Set a default value for the email input field if no email is saved in the settings. |
| 1698 |
if ( ! isset( $wpvulnerability_settings['emails'] ) ) { |
| 1699 |
$wpvulnerability_settings['emails'] = ''; |
| 1700 |
} |
| 1701 |
|
| 1702 |
// Output the email input field. |
| 1703 |
$admin_email = get_bloginfo( 'admin_email' ); |
| 1704 |
|
| 1705 |
// Output the email input field. Use the network admin email as a placeholder in a multisite environment. |
| 1706 |
?> |
| 1707 |
<input class="regular-text" type="text" name="wpvulnerability-config[emails]" id="wpvulnerability_emails" placeholder="<?php echo esc_attr( (string) $admin_email ); ?>" value="<?php echo esc_attr( (string) $wpvulnerability_settings['emails'] ); ?>"> |
| 1708 |
<br><small><?php esc_html_e( 'Default administrator email', 'wpvulnerability' ); ?>: <?php echo esc_attr( (string) $admin_email ); ?></small> |
| 1709 |
<?php |
| 1710 |
|
| 1711 |
unset( $admin_email ); |
| 1712 |
} |
| 1713 |
|
| 1714 |
/** |
| 1715 |
* Print the cache expiration selector. |
| 1716 |
* |
| 1717 |
* @since 4.1.0 |
| 1718 |
* |
| 1719 |
* @return void |
| 1720 |
*/ |
| 1721 |
function wpvulnerability_admin_cache_callback() { |
| 1722 |
|
| 1723 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config', array() ); |
| 1724 |
$options = array( 1, 6, 12, 24 ); |
| 1725 |
$forced_cache = null; |
| 1726 |
|
| 1727 |
if ( defined( 'WPVULNERABILITY_CACHE_HOURS' ) ) { |
| 1728 |
$forced_cache = (int) WPVULNERABILITY_CACHE_HOURS; |
| 1729 |
if ( ! in_array( $forced_cache, $options, true ) ) { |
| 1730 |
$options[] = $forced_cache; |
| 1731 |
sort( $options, SORT_NUMERIC ); |
| 1732 |
} |
| 1733 |
} |
| 1734 |
|
| 1735 |
$current = isset( $wpvulnerability_settings['cache'] ) ? (int) $wpvulnerability_settings['cache'] : 12; |
| 1736 |
if ( null !== $forced_cache ) { |
| 1737 |
$current = $forced_cache; |
| 1738 |
} |
| 1739 |
|
| 1740 |
echo '<select name="wpvulnerability-config[cache]" id="wpvulnerability_cache"'; |
| 1741 |
disabled( null !== $forced_cache ); |
| 1742 |
echo '>'; |
| 1743 |
foreach ( $options as $hours ) { |
| 1744 |
printf( |
| 1745 |
'<option value="%1$s"%2$s>%3$s</option>', |
| 1746 |
esc_attr( $hours ), |
| 1747 |
selected( $current, $hours, false ), |
| 1748 |
esc_html( |
| 1749 |
sprintf( |
| 1750 |
/* translators: %d: number of hours */ |
| 1751 |
_n( '%d hour', '%d hours', $hours, 'wpvulnerability' ), |
| 1752 |
$hours |
| 1753 |
) |
| 1754 |
) |
| 1755 |
); |
| 1756 |
} |
| 1757 |
echo '</select>'; |
| 1758 |
|
| 1759 |
if ( null !== $forced_cache ) { |
| 1760 |
printf( |
| 1761 |
'<input type="hidden" name="wpvulnerability-config[cache]" value="%s" />', |
| 1762 |
esc_attr( $current ) |
| 1763 |
); |
| 1764 |
} |
| 1765 |
|
| 1766 |
printf( |
| 1767 |
'<p class="description"><a href="%1$s" target="_blank"><small><i>%2$s</i></small></a></p>', |
| 1768 |
esc_url( 'https://www.wpvulnerability.com/plugin/#cache-duration' ), |
| 1769 |
esc_html__( 'Read more if you want to force the cache time.', 'wpvulnerability' ) |
| 1770 |
); |
| 1771 |
} |
| 1772 |
|
| 1773 |
/** |
| 1774 |
* Print when to send the vulnerability scan emails. |
| 1775 |
* |
| 1776 |
* @since 2.0.0 |
| 1777 |
* |
| 1778 |
* @return void |
| 1779 |
*/ |
| 1780 |
function wpvulnerability_admin_period_callback() { |
| 1781 |
|
| 1782 |
// Get the saved plugin settings. |
| 1783 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config', array() ); |
| 1784 |
$defaults = array( |
| 1785 |
'period' => 'weekly', |
| 1786 |
'day' => 'monday', |
| 1787 |
'hour' => 0, |
| 1788 |
'minute' => 0, |
| 1789 |
); |
| 1790 |
$wpvulnerability_settings = wp_parse_args( $wpvulnerability_settings, $defaults ); |
| 1791 |
|
| 1792 |
?> |
| 1793 |
<div id="wpvulnerability_period"> |
| 1794 |
<label> |
| 1795 |
<input type="radio" name="wpvulnerability-config[period]" value="never" <?php checked( $wpvulnerability_settings['period'], 'never' ); ?> /> |
| 1796 |
<?php esc_html_e( 'Never', 'wpvulnerability' ); ?> |
| 1797 |
</label> |
| 1798 |
<br/> |
| 1799 |
<label> |
| 1800 |
<input type="radio" name="wpvulnerability-config[period]" value="daily" <?php checked( $wpvulnerability_settings['period'], 'daily' ); ?> /> |
| 1801 |
<?php esc_html_e( 'Daily', 'wpvulnerability' ); ?> |
| 1802 |
</label> |
| 1803 |
<br/> |
| 1804 |
<label> |
| 1805 |
<input type="radio" name="wpvulnerability-config[period]" value="weekly" <?php checked( $wpvulnerability_settings['period'], 'weekly' ); ?> /> |
| 1806 |
<?php esc_html_e( 'Weekly', 'wpvulnerability' ); ?> |
| 1807 |
</label> |
| 1808 |
<div id="wpvulnerability_day_wrap"> |
| 1809 |
<br/> |
| 1810 |
<label for="wpvulnerability_day"><?php esc_html_e( 'Day', 'wpvulnerability' ); ?></label> |
| 1811 |
<select name="wpvulnerability-config[day]" id="wpvulnerability_day"> |
| 1812 |
<option value="monday" <?php selected( $wpvulnerability_settings['day'], 'monday' ); ?>><?php esc_html_e( 'Monday', 'wpvulnerability' ); ?></option> |
| 1813 |
<option value="tuesday" <?php selected( $wpvulnerability_settings['day'], 'tuesday' ); ?>><?php esc_html_e( 'Tuesday', 'wpvulnerability' ); ?></option> |
| 1814 |
<option value="wednesday" <?php selected( $wpvulnerability_settings['day'], 'wednesday' ); ?>><?php esc_html_e( 'Wednesday', 'wpvulnerability' ); ?></option> |
| 1815 |
<option value="thursday" <?php selected( $wpvulnerability_settings['day'], 'thursday' ); ?>><?php esc_html_e( 'Thursday', 'wpvulnerability' ); ?></option> |
| 1816 |
<option value="friday" <?php selected( $wpvulnerability_settings['day'], 'friday' ); ?>><?php esc_html_e( 'Friday', 'wpvulnerability' ); ?></option> |
| 1817 |
<option value="saturday" <?php selected( $wpvulnerability_settings['day'], 'saturday' ); ?>><?php esc_html_e( 'Saturday', 'wpvulnerability' ); ?></option> |
| 1818 |
<option value="sunday" <?php selected( $wpvulnerability_settings['day'], 'sunday' ); ?>><?php esc_html_e( 'Sunday', 'wpvulnerability' ); ?></option> |
| 1819 |
</select> |
| 1820 |
</div> |
| 1821 |
<div id="wpvulnerability_time_wrap"> |
| 1822 |
<br/> |
| 1823 |
<label for="wpvulnerability_hour"><?php esc_html_e( 'Hour', 'wpvulnerability' ); ?></label> |
| 1824 |
<input type="number" min="0" max="23" name="wpvulnerability-config[hour]" id="wpvulnerability_hour" value="<?php echo esc_attr( (string) $wpvulnerability_settings['hour'] ); ?>" /> |
| 1825 |
<label for="wpvulnerability_minute"><?php esc_html_e( 'Minute', 'wpvulnerability' ); ?></label> |
| 1826 |
<input type="number" min="0" max="59" name="wpvulnerability-config[minute]" id="wpvulnerability_minute" value="<?php echo esc_attr( (string) $wpvulnerability_settings['minute'] ); ?>" /> |
| 1827 |
</div> |
| 1828 |
</div> |
| 1829 |
<?php |
| 1830 |
} |
| 1831 |
|
| 1832 |
/** |
| 1833 |
* Print where to send the notifications. |
| 1834 |
* |
| 1835 |
* @since 3.6.0 |
| 1836 |
* |
| 1837 |
* @return void |
| 1838 |
*/ |
| 1839 |
function wpvulnerability_admin_notify_callback() { |
| 1840 |
|
| 1841 |
// Get the saved plugin settings. |
| 1842 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config', array() ); |
| 1843 |
$defaults = array( |
| 1844 |
'email' => 'y', |
| 1845 |
'slack' => 'n', |
| 1846 |
'teams' => 'n', |
| 1847 |
); |
| 1848 |
|
| 1849 |
if ( ! isset( $wpvulnerability_settings['notify'] ) || ! is_array( $wpvulnerability_settings['notify'] ) ) { |
| 1850 |
$wpvulnerability_settings['notify'] = $defaults; |
| 1851 |
} else { |
| 1852 |
$wpvulnerability_settings['notify'] = wp_parse_args( $wpvulnerability_settings['notify'], $defaults ); |
| 1853 |
} |
| 1854 |
|
| 1855 |
$wpvulnerability_settings['notify'] = wpvulnerability_normalize_notify_settings( $wpvulnerability_settings['notify'] ); |
| 1856 |
|
| 1857 |
$email_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['email'] ); |
| 1858 |
$slack_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['slack'] ); |
| 1859 |
$teams_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['teams'] ); |
| 1860 |
|
| 1861 |
?> |
| 1862 |
<div id="wpvulnerability_notify"> |
| 1863 |
<label> |
| 1864 |
<input type="checkbox" name="wpvulnerability-config[notify][email]" value="y" <?php checked( $email_enabled ); ?> /> |
| 1865 |
<?php esc_html_e( 'Email', 'wpvulnerability' ); ?> |
| 1866 |
</label> |
| 1867 |
<br/> |
| 1868 |
<label> |
| 1869 |
<input type="checkbox" name="wpvulnerability-config[notify][slack]" value="y" <?php checked( $slack_enabled ); ?> /> |
| 1870 |
<?php esc_html_e( 'Slack', 'wpvulnerability' ); ?> |
| 1871 |
</label> |
| 1872 |
<br/> |
| 1873 |
<label> |
| 1874 |
<input type="checkbox" name="wpvulnerability-config[notify][teams]" value="y" <?php checked( $teams_enabled ); ?> /> |
| 1875 |
<?php esc_html_e( 'Microsoft Teams', 'wpvulnerability' ); ?> |
| 1876 |
</label> |
| 1877 |
</div> |
| 1878 |
<?php |
| 1879 |
} |
| 1880 |
|
| 1881 |
/** |
| 1882 |
* Print the Slack webhook input field. |
| 1883 |
* |
| 1884 |
* @since 3.6.0 |
| 1885 |
* |
| 1886 |
* @return void |
| 1887 |
*/ |
| 1888 |
function wpvulnerability_admin_slack_callback() { |
| 1889 |
|
| 1890 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config', array() ); |
| 1891 |
$slack_webhook = isset( $wpvulnerability_settings['slack_webhook'] ) ? $wpvulnerability_settings['slack_webhook'] : ''; |
| 1892 |
|
| 1893 |
?> |
| 1894 |
<input class="regular-text" type="text" name="wpvulnerability-config[slack_webhook]" id="wpvulnerability_slack_webhook" placeholder="<?php echo esc_attr( 'https://hooks.slack.com/services/...' ); ?>" value="<?php echo esc_attr( (string) $slack_webhook ); ?>" /> |
| 1895 |
<?php |
| 1896 |
} |
| 1897 |
|
| 1898 |
/** |
| 1899 |
* Print the Teams webhook input field. |
| 1900 |
* |
| 1901 |
* @since 3.6.0 |
| 1902 |
* |
| 1903 |
* @return void |
| 1904 |
*/ |
| 1905 |
function wpvulnerability_admin_teams_callback() { |
| 1906 |
|
| 1907 |
$wpvulnerability_settings = get_option( 'wpvulnerability-config', array() ); |
| 1908 |
$teams_webhook = isset( $wpvulnerability_settings['teams_webhook'] ) ? $wpvulnerability_settings['teams_webhook'] : ''; |
| 1909 |
|
| 1910 |
?> |
| 1911 |
<input class="regular-text" type="text" name="wpvulnerability-config[teams_webhook]" id="wpvulnerability_teams_webhook" placeholder="<?php echo esc_attr( 'https://outlook.office.com/webhook/...' ); ?>" value="<?php echo esc_attr( (string) $teams_webhook ); ?>" /> |
| 1912 |
<?php |
| 1913 |
} |
| 1914 |
|
| 1915 |
/** |
| 1916 |
* Displays the WPVulnerability plugin analysis settings in the admin panel. |
| 1917 |
* |
| 1918 |
* This function retrieves the current WPVulnerability analysis settings and |
| 1919 |
* ensures all necessary options are set. It then outputs a multiple-select |
| 1920 |
* field allowing the user to select which components (core, plugins, themes, |
| 1921 |
* php, apache, nginx) to analyze. |
| 1922 |
* |
| 1923 |
* @since 3.3.0 |
| 1924 |
* |
| 1925 |
* @return void |
| 1926 |
*/ |
| 1927 |
function wpvulnerability_admin_analyze_callback() { |
| 1928 |
|
| 1929 |
// Retrieve the WPVulnerability plugin settings. |
| 1930 |
$wpvulnerability_analyze = get_option( 'wpvulnerability-analyze', array() ); |
| 1931 |
$components = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' ); |
| 1932 |
$forced = array(); |
| 1933 |
|
| 1934 |
foreach ( $components as $component ) { |
| 1935 |
if ( ! isset( $wpvulnerability_analyze[ $component ] ) ) { |
| 1936 |
$wpvulnerability_analyze[ $component ] = 0; |
| 1937 |
} |
| 1938 |
$constant = 'WPVULNERABILITY_HIDE_' . strtoupper( (string) $component ); |
| 1939 |
$forced[ $component ] = defined( $constant ) && constant( $constant ); |
| 1940 |
if ( $forced[ $component ] ) { |
| 1941 |
$wpvulnerability_analyze[ $component ] = 1; |
| 1942 |
} |
| 1943 |
} |
| 1944 |
|
| 1945 |
?> |
| 1946 |
<div id="wpvulnerability_analyze"> |
| 1947 |
<label> |
| 1948 |
<input type="checkbox" name="wpvulnerability-analyze[core]" value="core" <?php checked( $wpvulnerability_analyze['core'] ); ?> <?php disabled( $forced['core'] ); ?> /> |
| 1949 |
<?php esc_html_e( 'Core', 'wpvulnerability' ); ?> |
| 1950 |
</label> |
| 1951 |
<br/> |
| 1952 |
<label> |
| 1953 |
<input type="checkbox" name="wpvulnerability-analyze[plugins]" value="plugins" <?php checked( $wpvulnerability_analyze['plugins'] ); ?> <?php disabled( $forced['plugins'] ); ?> /> |
| 1954 |
<?php esc_html_e( 'Plugins', 'wpvulnerability' ); ?> |
| 1955 |
</label> |
| 1956 |
<br/> |
| 1957 |
<label> |
| 1958 |
<input type="checkbox" name="wpvulnerability-analyze[themes]" value="themes" <?php checked( $wpvulnerability_analyze['themes'] ); ?> <?php disabled( $forced['themes'] ); ?> /> |
| 1959 |
<?php esc_html_e( 'Themes', 'wpvulnerability' ); ?> |
| 1960 |
</label> |
| 1961 |
<br/> |
| 1962 |
<label> |
| 1963 |
<input type="checkbox" name="wpvulnerability-analyze[php]" value="php" <?php checked( $wpvulnerability_analyze['php'] ); ?> <?php disabled( $forced['php'] ); ?> /> |
| 1964 |
<?php esc_html_e( 'PHP', 'wpvulnerability' ); ?> |
| 1965 |
</label> |
| 1966 |
<br/> |
| 1967 |
<label> |
| 1968 |
<input type="checkbox" name="wpvulnerability-analyze[apache]" value="apache" <?php checked( $wpvulnerability_analyze['apache'] ); ?> <?php disabled( $forced['apache'] ); ?> /> |
| 1969 |
<?php esc_html_e( 'Apache HTTPD', 'wpvulnerability' ); ?> |
| 1970 |
</label> |
| 1971 |
<br/> |
| 1972 |
<label> |
| 1973 |
<input type="checkbox" name="wpvulnerability-analyze[nginx]" value="nginx" <?php checked( $wpvulnerability_analyze['nginx'] ); ?> <?php disabled( $forced['nginx'] ); ?> /> |
| 1974 |
<?php esc_html_e( 'nginx', 'wpvulnerability' ); ?> |
| 1975 |
</label> |
| 1976 |
<br/> |
| 1977 |
<label> |
| 1978 |
<input type="checkbox" name="wpvulnerability-analyze[mariadb]" value="mariadb" <?php checked( $wpvulnerability_analyze['mariadb'] ); ?> <?php disabled( $forced['mariadb'] ); ?> /> |
| 1979 |
<?php esc_html_e( 'MariaDB', 'wpvulnerability' ); ?> |
| 1980 |
</label> |
| 1981 |
<br/> |
| 1982 |
<label> |
| 1983 |
<input type="checkbox" name="wpvulnerability-analyze[mysql]" value="mysql" <?php checked( $wpvulnerability_analyze['mysql'] ); ?> <?php disabled( $forced['mysql'] ); ?> /> |
| 1984 |
<?php esc_html_e( 'MySQL', 'wpvulnerability' ); ?> |
| 1985 |
</label> |
| 1986 |
<br/> |
| 1987 |
<label> |
| 1988 |
<input type="checkbox" name="wpvulnerability-analyze[imagemagick]" value="imagemagick" <?php checked( $wpvulnerability_analyze['imagemagick'] ); ?> <?php disabled( $forced['imagemagick'] ); ?> /> |
| 1989 |
<?php esc_html_e( 'ImageMagick', 'wpvulnerability' ); ?> |
| 1990 |
</label> |
| 1991 |
<br/> |
| 1992 |
<label> |
| 1993 |
<input type="checkbox" name="wpvulnerability-analyze[curl]" value="curl" <?php checked( $wpvulnerability_analyze['curl'] ); ?> <?php disabled( $forced['curl'] ); ?> /> |
| 1994 |
<?php esc_html_e( 'curl', 'wpvulnerability' ); ?> |
| 1995 |
</label> |
| 1996 |
<br/> |
| 1997 |
<label> |
| 1998 |
<input type="checkbox" name="wpvulnerability-analyze[memcached]" value="memcached" <?php checked( $wpvulnerability_analyze['memcached'] ); ?> <?php disabled( $forced['memcached'] ); ?> /> |
| 1999 |
<?php esc_html_e( 'memcached', 'wpvulnerability' ); ?> |
| 2000 |
</label> |
| 2001 |
<br/> |
| 2002 |
<label> |
| 2003 |
<input type="checkbox" name="wpvulnerability-analyze[redis]" value="redis" <?php checked( $wpvulnerability_analyze['redis'] ); ?> <?php disabled( $forced['redis'] ); ?> /> |
| 2004 |
<?php esc_html_e( 'Redis', 'wpvulnerability' ); ?> |
| 2005 |
</label> |
| 2006 |
<br/> |
| 2007 |
<label> |
| 2008 |
<input type="checkbox" name="wpvulnerability-analyze[sqlite]" value="sqlite" <?php checked( $wpvulnerability_analyze['sqlite'] ); ?> <?php disabled( $forced['sqlite'] ); ?> /> |
| 2009 |
<?php esc_html_e( 'SQLite', 'wpvulnerability' ); ?> |
| 2010 |
</label> |
| 2011 |
<p><a href="https://www.wpvulnerability.com/plugin/#force-hiding-checks" target="_blank"><small><i><?php esc_html_e( 'Read more about how to force the deactivation of an item.', 'wpvulnerability' ); ?></i></small></a></p> |
| 2012 |
</div> |
| 2013 |
<?php |
| 2014 |
} |
| 2015 |
|
| 2016 |
/** |
| 2017 |
* Sanitize fields before saving into the database |
| 2018 |
* |
| 2019 |
* @since 2.0.0 |
| 2020 |
* |
| 2021 |
* @param array $input The input fields to sanitize. |
| 2022 |
* |
| 2023 |
* @return array The sanitized values. |
| 2024 |
*/ |
| 2025 |
function wpvulnerability_admin_sanitize( $input ) { |
| 2026 |
|
| 2027 |
$input_emails = array(); |
| 2028 |
$defaults = array( |
| 2029 |
'notify' => array( |
| 2030 |
'email' => 'n', |
| 2031 |
'slack' => 'n', |
| 2032 |
'teams' => 'n', |
| 2033 |
), |
| 2034 |
'slack_webhook' => '', |
| 2035 |
'teams_webhook' => '', |
| 2036 |
'day' => 'monday', |
| 2037 |
'hour' => 0, |
| 2038 |
'minute' => 0, |
| 2039 |
'cache' => 12, |
| 2040 |
'log_retention' => 0, |
| 2041 |
'emails' => null, |
| 2042 |
'period' => 'weekly', |
| 2043 |
); |
| 2044 |
|
| 2045 |
$current_values = is_multisite() ? get_site_option( 'wpvulnerability-config', array() ) : get_option( 'wpvulnerability-config', array() ); |
| 2046 |
if ( ! is_array( $current_values ) ) { |
| 2047 |
$current_values = array(); |
| 2048 |
} |
| 2049 |
|
| 2050 |
$sanitized_values = $current_values; |
| 2051 |
|
| 2052 |
if ( isset( $input['emails'] ) ) { |
| 2053 |
$input_email_text = explode( ',', $input['emails'] ); |
| 2054 |
|
| 2055 |
foreach ( $input_email_text as $input_email ) { |
| 2056 |
$input_email = sanitize_email( trim( (string) $input_email ) ); |
| 2057 |
|
| 2058 |
if ( $input_email ) { |
| 2059 |
$input_emails[] = $input_email; |
| 2060 |
} |
| 2061 |
} |
| 2062 |
|
| 2063 |
if ( count( $input_emails ) ) { |
| 2064 |
$sanitized_values['emails'] = implode( ',', $input_emails ); |
| 2065 |
} else { |
| 2066 |
$sanitized_values['emails'] = null; |
| 2067 |
} |
| 2068 |
} |
| 2069 |
|
| 2070 |
if ( isset( $input['period'] ) ) { |
| 2071 |
|
| 2072 |
// Check the value of the period field and sanitize it. |
| 2073 |
switch ( $input['period'] ) { |
| 2074 |
case 'never': |
| 2075 |
$sanitized_values['period'] = 'never'; |
| 2076 |
break; |
| 2077 |
case 'daily': |
| 2078 |
$sanitized_values['period'] = 'daily'; |
| 2079 |
break; |
| 2080 |
case 'weekly': |
| 2081 |
$sanitized_values['period'] = 'weekly'; |
| 2082 |
break; |
| 2083 |
default: |
| 2084 |
$sanitized_values['period'] = 'weekly'; |
| 2085 |
break; |
| 2086 |
} |
| 2087 |
} |
| 2088 |
|
| 2089 |
if ( isset( $input['day'] ) ) { |
| 2090 |
$day = strtolower( sanitize_text_field( (string) $input['day'] ) ); |
| 2091 |
$valid_days = array( 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' ); |
| 2092 |
$sanitized_values['day'] = in_array( $day, $valid_days, true ) ? $day : 'monday'; |
| 2093 |
} |
| 2094 |
|
| 2095 |
if ( isset( $input['hour'] ) ) { |
| 2096 |
$hour = (int) $input['hour']; |
| 2097 |
$sanitized_values['hour'] = max( 0, min( 23, $hour ) ); |
| 2098 |
} |
| 2099 |
|
| 2100 |
if ( isset( $input['minute'] ) ) { |
| 2101 |
$minute = (int) $input['minute']; |
| 2102 |
$sanitized_values['minute'] = max( 0, min( 59, $minute ) ); |
| 2103 |
} |
| 2104 |
|
| 2105 |
if ( isset( $input['cache'] ) ) { |
| 2106 |
$cache = (int) $input['cache']; |
| 2107 |
$sanitized_values['cache'] = in_array( $cache, array( 1, 6, 12, 24 ), true ) ? $cache : 12; |
| 2108 |
} |
| 2109 |
|
| 2110 |
if ( isset( $input['log_retention'] ) ) { |
| 2111 |
$retention = (int) $input['log_retention']; |
| 2112 |
if ( in_array( $retention, wpvulnerability_get_log_retention_values(), true ) ) { |
| 2113 |
$sanitized_values['log_retention'] = $retention; |
| 2114 |
} |
| 2115 |
} |
| 2116 |
|
| 2117 |
if ( isset( $input['notify'] ) && is_array( $input['notify'] ) ) { |
| 2118 |
$notify_input = array_map( 'sanitize_text_field', (array) wp_unslash( $input['notify'] ) ); |
| 2119 |
$sanitized_values['notify'] = wpvulnerability_normalize_notify_settings( $notify_input ); |
| 2120 |
} |
| 2121 |
|
| 2122 |
if ( isset( $input['slack_webhook'] ) ) { |
| 2123 |
$slack_url = trim( (string) $input['slack_webhook'] ); |
| 2124 |
if ( '' !== $slack_url ) { |
| 2125 |
$validated_slack = wpvulnerability_validate_webhook_url( |
| 2126 |
$slack_url, |
| 2127 |
array( 'hooks.slack.com' ) |
| 2128 |
); |
| 2129 |
if ( '' === $validated_slack ) { |
| 2130 |
add_settings_error( |
| 2131 |
'wpvulnerability-config', |
| 2132 |
'invalid-slack-webhook', |
| 2133 |
__( 'Invalid Slack webhook URL. Must be a valid HTTPS URL from hooks.slack.com', 'wpvulnerability' ), |
| 2134 |
'error' |
| 2135 |
); |
| 2136 |
$sanitized_values['slack_webhook'] = ''; |
| 2137 |
} else { |
| 2138 |
$sanitized_values['slack_webhook'] = $validated_slack; |
| 2139 |
} |
| 2140 |
} else { |
| 2141 |
$sanitized_values['slack_webhook'] = ''; |
| 2142 |
} |
| 2143 |
} |
| 2144 |
|
| 2145 |
if ( isset( $input['teams_webhook'] ) ) { |
| 2146 |
$teams_url = trim( (string) $input['teams_webhook'] ); |
| 2147 |
if ( '' !== $teams_url ) { |
| 2148 |
$validated_teams = wpvulnerability_validate_webhook_url( |
| 2149 |
$teams_url, |
| 2150 |
array( 'office.com', 'office365.com', 'api.hooks.microsoft.com' ) |
| 2151 |
); |
| 2152 |
if ( '' === $validated_teams ) { |
| 2153 |
add_settings_error( |
| 2154 |
'wpvulnerability-config', |
| 2155 |
'invalid-teams-webhook', |
| 2156 |
__( 'Invalid Microsoft Teams webhook URL. Must be a valid HTTPS URL from office.com, office365.com, or api.hooks.microsoft.com', 'wpvulnerability' ), |
| 2157 |
'error' |
| 2158 |
); |
| 2159 |
$sanitized_values['teams_webhook'] = ''; |
| 2160 |
} else { |
| 2161 |
$sanitized_values['teams_webhook'] = $validated_teams; |
| 2162 |
} |
| 2163 |
} else { |
| 2164 |
$sanitized_values['teams_webhook'] = ''; |
| 2165 |
} |
| 2166 |
} |
| 2167 |
|
| 2168 |
if ( isset( $input['discord_webhook'] ) ) { |
| 2169 |
$discord_url = trim( (string) $input['discord_webhook'] ); |
| 2170 |
if ( '' !== $discord_url ) { |
| 2171 |
$validated_discord = wpvulnerability_validate_webhook_url( |
| 2172 |
$discord_url, |
| 2173 |
array( 'discord.com', 'discordapp.com' ) |
| 2174 |
); |
| 2175 |
if ( '' === $validated_discord ) { |
| 2176 |
add_settings_error( |
| 2177 |
'wpvulnerability-config', |
| 2178 |
'invalid-discord-webhook', |
| 2179 |
__( 'Invalid Discord webhook URL. Must be a valid HTTPS URL from discord.com or discordapp.com', 'wpvulnerability' ), |
| 2180 |
'error' |
| 2181 |
); |
| 2182 |
$sanitized_values['discord_webhook'] = ''; |
| 2183 |
} else { |
| 2184 |
$sanitized_values['discord_webhook'] = $validated_discord; |
| 2185 |
} |
| 2186 |
} else { |
| 2187 |
$sanitized_values['discord_webhook'] = ''; |
| 2188 |
} |
| 2189 |
} |
| 2190 |
|
| 2191 |
if ( isset( $input['telegram_bot_token'] ) ) { |
| 2192 |
$telegram_bot_token = sanitize_text_field( trim( (string) $input['telegram_bot_token'] ) ); |
| 2193 |
if ( '' !== $telegram_bot_token ) { |
| 2194 |
if ( ! preg_match( '/^\d+:[A-Za-z0-9_-]+$/', $telegram_bot_token ) ) { |
| 2195 |
add_settings_error( |
| 2196 |
'wpvulnerability-config', |
| 2197 |
'invalid-telegram-token', |
| 2198 |
__( 'Invalid Telegram bot token format. Must be like: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', 'wpvulnerability' ), |
| 2199 |
'error' |
| 2200 |
); |
| 2201 |
$sanitized_values['telegram_bot_token'] = ''; |
| 2202 |
} else { |
| 2203 |
$sanitized_values['telegram_bot_token'] = $telegram_bot_token; |
| 2204 |
} |
| 2205 |
} else { |
| 2206 |
$sanitized_values['telegram_bot_token'] = ''; |
| 2207 |
} |
| 2208 |
} |
| 2209 |
|
| 2210 |
if ( isset( $input['telegram_chat_id'] ) ) { |
| 2211 |
$sanitized_values['telegram_chat_id'] = sanitize_text_field( trim( (string) $input['telegram_chat_id'] ) ); |
| 2212 |
} |
| 2213 |
|
| 2214 |
$sanitized_values = wp_parse_args( $sanitized_values, $defaults ); |
| 2215 |
|
| 2216 |
// Schedule notification based on sanitized values. |
| 2217 |
wpvulnerability_schedule_notification_event( $sanitized_values ); |
| 2218 |
return $sanitized_values; |
| 2219 |
} |
| 2220 |
|
| 2221 |
/** |
| 2222 |
* Sanitizes the input fields for vulnerability analysis. |
| 2223 |
* |
| 2224 |
* This function takes an array of input fields and sanitizes them by setting |
| 2225 |
* the corresponding values in the output array to 1 if they are present in |
| 2226 |
* the input. The possible fields are 'core', 'plugins', 'themes', 'php', |
| 2227 |
* 'apache', and 'nginx'. |
| 2228 |
* |
| 2229 |
* @since 3.3.0 |
| 2230 |
* |
| 2231 |
* @param array $input The input fields to sanitize. |
| 2232 |
* |
| 2233 |
* @return array The sanitized values with keys 'core', 'plugins', 'themes', 'php', 'apache', and 'nginx'. |
| 2234 |
*/ |
| 2235 |
function wpvulnerability_analyze_sanitize( $input ) { |
| 2236 |
$sanitized_values = array( |
| 2237 |
'core' => isset( $input['core'] ) ? 1 : 0, |
| 2238 |
'plugins' => isset( $input['plugins'] ) ? 1 : 0, |
| 2239 |
'themes' => isset( $input['themes'] ) ? 1 : 0, |
| 2240 |
'php' => isset( $input['php'] ) ? 1 : 0, |
| 2241 |
'apache' => isset( $input['apache'] ) ? 1 : 0, |
| 2242 |
'nginx' => isset( $input['nginx'] ) ? 1 : 0, |
| 2243 |
'mariadb' => isset( $input['mariadb'] ) ? 1 : 0, |
| 2244 |
'mysql' => isset( $input['mysql'] ) ? 1 : 0, |
| 2245 |
'imagemagick' => isset( $input['imagemagick'] ) ? 1 : 0, |
| 2246 |
'curl' => isset( $input['curl'] ) ? 1 : 0, |
| 2247 |
'memcached' => isset( $input['memcached'] ) ? 1 : 0, |
| 2248 |
'redis' => isset( $input['redis'] ) ? 1 : 0, |
| 2249 |
'sqlite' => isset( $input['sqlite'] ) ? 1 : 0, |
| 2250 |
); |
| 2251 |
|
| 2252 |
foreach ( $sanitized_values as $component => $value ) { |
| 2253 |
$constant = 'WPVULNERABILITY_HIDE_' . strtoupper( (string) $component ); |
| 2254 |
if ( defined( $constant ) && constant( $constant ) ) { |
| 2255 |
$sanitized_values[ $component ] = 1; |
| 2256 |
} |
| 2257 |
} |
| 2258 |
|
| 2259 |
return $sanitized_values; |
| 2260 |
} |
| 2261 |
|
| 2262 |
/** |
| 2263 |
* Content for the Dashboard Widget |
| 2264 |
* |
| 2265 |
* @since 2.2.0 |
| 2266 |
* |
| 2267 |
* @return void |
| 2268 |
*/ |
| 2269 |
function wpvulnerability_admin_dashboard_content() { |
| 2270 |
// Inline CSS for dashboard widget. |
| 2271 |
|
| 2272 |
// Get vulnerability counts for all components. |
| 2273 |
$core_count = (int) json_decode( get_option( 'wpvulnerability-core-vulnerable' ), true ); |
| 2274 |
$plugins_count = (int) json_decode( get_option( 'wpvulnerability-plugins-vulnerable' ), true ); |
| 2275 |
$themes_count = (int) json_decode( get_option( 'wpvulnerability-themes-vulnerable' ), true ); |
| 2276 |
$php_count = (int) json_decode( get_option( 'wpvulnerability-php-vulnerable' ), true ); |
| 2277 |
$apache_count = (int) json_decode( get_option( 'wpvulnerability-apache-vulnerable' ), true ); |
| 2278 |
$nginx_count = (int) json_decode( get_option( 'wpvulnerability-nginx-vulnerable' ), true ); |
| 2279 |
$mariadb_count = (int) json_decode( get_option( 'wpvulnerability-mariadb-vulnerable' ), true ); |
| 2280 |
$mysql_count = (int) json_decode( get_option( 'wpvulnerability-mysql-vulnerable' ), true ); |
| 2281 |
$imagemagick_count = (int) json_decode( get_option( 'wpvulnerability-imagemagick-vulnerable' ), true ); |
| 2282 |
$curl_count = (int) json_decode( get_option( 'wpvulnerability-curl-vulnerable' ), true ); |
| 2283 |
$memcached_count = (int) json_decode( get_option( 'wpvulnerability-memcached-vulnerable' ), true ); |
| 2284 |
$redis_count = (int) json_decode( get_option( 'wpvulnerability-redis-vulnerable' ), true ); |
| 2285 |
$sqlite_count = (int) json_decode( get_option( 'wpvulnerability-sqlite-vulnerable' ), true ); |
| 2286 |
|
| 2287 |
// Calculate total vulnerabilities. |
| 2288 |
$total_vulnerabilities = $core_count + $plugins_count + $themes_count + $php_count + |
| 2289 |
$apache_count + $nginx_count + $mariadb_count + $mysql_count + |
| 2290 |
$imagemagick_count + $curl_count + $memcached_count + $redis_count + $sqlite_count; |
| 2291 |
|
| 2292 |
// Determine status badge. |
| 2293 |
$status_class = 'wpvuln-status-secure'; |
| 2294 |
$status_text = '✓ ' . __( 'All Clear', 'wpvulnerability' ); |
| 2295 |
$status_icon = '✓'; |
| 2296 |
|
| 2297 |
if ( $total_vulnerabilities > 0 ) { |
| 2298 |
if ( $core_count > 0 || $php_count > 0 || $total_vulnerabilities > 5 ) { |
| 2299 |
$status_class = 'wpvuln-status-critical'; |
| 2300 |
$status_icon = '✕'; |
| 2301 |
/* translators: %d: number of vulnerabilities */ |
| 2302 |
$status_text = sprintf( _n( '%d Critical Issue Found', '%d Critical Issues Found', $total_vulnerabilities, 'wpvulnerability' ), $total_vulnerabilities ); |
| 2303 |
} else { |
| 2304 |
$status_class = 'wpvuln-status-warning'; |
| 2305 |
$status_icon = '⚠'; |
| 2306 |
/* translators: %d: number of vulnerabilities */ |
| 2307 |
$status_text = sprintf( _n( '%d Issue Found', '%d Issues Found', $total_vulnerabilities, 'wpvulnerability' ), $total_vulnerabilities ); |
| 2308 |
} |
| 2309 |
} |
| 2310 |
|
| 2311 |
// Get last check time. |
| 2312 |
$core_cache = json_decode( get_option( 'wpvulnerability-core-cache' ), true ); |
| 2313 |
$last_check_text = __( 'Never checked', 'wpvulnerability' ); |
| 2314 |
if ( $core_cache && is_numeric( $core_cache ) ) { |
| 2315 |
$cache_hours = wpvulnerability_cache_hours(); |
| 2316 |
$last_check_time = $core_cache - ( $cache_hours * 3600 ); |
| 2317 |
$time_diff = time() - $last_check_time; |
| 2318 |
if ( $time_diff < 3600 ) { |
| 2319 |
/* translators: %d: number of minutes */ |
| 2320 |
$last_check_text = sprintf( _n( '%d minute ago', '%d minutes ago', floor( $time_diff / 60 ), 'wpvulnerability' ), floor( $time_diff / 60 ) ); |
| 2321 |
} else { |
| 2322 |
/* translators: %d: number of hours */ |
| 2323 |
$last_check_text = sprintf( _n( '%d hour ago', '%d hours ago', floor( $time_diff / 3600 ), 'wpvulnerability' ), floor( $time_diff / 3600 ) ); |
| 2324 |
} |
| 2325 |
} |
| 2326 |
|
| 2327 |
// Status badge. |
| 2328 |
echo '<div class="wpvuln-status-badge ' . esc_attr( $status_class ) . '">'; |
| 2329 |
echo esc_html( $status_text ); |
| 2330 |
echo '</div>'; |
| 2331 |
|
| 2332 |
// Meta information. |
| 2333 |
echo '<div class="wpvuln-meta">'; |
| 2334 |
/* translators: %s: time since last check */ |
| 2335 |
echo esc_html( sprintf( __( 'Last checked: %s', 'wpvulnerability' ), $last_check_text ) ); |
| 2336 |
echo ' | <a href="' . esc_url( admin_url( 'options-general.php?page=wpvulnerability-options&tab=tools' ) ) . '" class="wpvuln-refresh-btn">↻ ' . esc_html( __( 'Refresh Now', 'wpvulnerability' ) ) . '</a>'; |
| 2337 |
echo '</div>'; |
| 2338 |
|
| 2339 |
// If no vulnerabilities, show empty state. |
| 2340 |
if ( 0 === $total_vulnerabilities ) { |
| 2341 |
echo '<div class="wpvuln-empty-state">'; |
| 2342 |
echo '<div class="wpvuln-empty-state-icon">✓</div>'; |
| 2343 |
echo '<div class="wpvuln-empty-state-title">' . esc_html( __( 'No vulnerabilities detected', 'wpvulnerability' ) ) . '</div>'; |
| 2344 |
echo '<div class="wpvuln-empty-state-text">' . esc_html( __( 'Your site is up to date and secure', 'wpvulnerability' ) ) . '</div>'; |
| 2345 |
echo '</div>'; |
| 2346 |
} else { |
| 2347 |
// WordPress Components section. |
| 2348 |
echo '<div class="wpvuln-section-title">' . esc_html( __( 'WordPress Components', 'wpvulnerability' ) ) . '</div>'; |
| 2349 |
|
| 2350 |
// Core. |
| 2351 |
if ( wpvulnerability_analyze_filter( 'core' ) ) { |
| 2352 |
$badge_class = $core_count > 0 ? 'wpvuln-badge-critical' : 'wpvuln-badge-secure'; |
| 2353 |
$badge_icon = $core_count > 0 ? '✕' : '✓'; |
| 2354 |
echo '<div class="wpvuln-component">'; |
| 2355 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-wordpress.svg" width="16" height="16" alt="">'; |
| 2356 |
echo '<span class="wpvuln-component-name">' . esc_html( __( 'WordPress Core', 'wpvulnerability' ) ) . '</span>'; |
| 2357 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $core_count ) . '</span>'; |
| 2358 |
echo '</div>'; |
| 2359 |
} |
| 2360 |
|
| 2361 |
// Plugins. |
| 2362 |
if ( wpvulnerability_analyze_filter( 'plugins' ) ) { |
| 2363 |
$badge_class = $plugins_count > 0 ? 'wpvuln-badge-critical' : 'wpvuln-badge-secure'; |
| 2364 |
$badge_icon = $plugins_count > 0 ? '✕' : '✓'; |
| 2365 |
echo '<div class="wpvuln-component">'; |
| 2366 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-plugin.svg" width="16" height="16" alt="">'; |
| 2367 |
echo '<span class="wpvuln-component-name">' . esc_html( __( 'Plugins', 'wpvulnerability' ) ) . '</span>'; |
| 2368 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $plugins_count ) . '</span>'; |
| 2369 |
echo '</div>'; |
| 2370 |
if ( $plugins_count > 0 ) { |
| 2371 |
echo '<div class="wpvuln-plugin-list">'; |
| 2372 |
echo wpvulnerability_list_plugins(); // phpcs:ignore |
| 2373 |
echo '</div>'; |
| 2374 |
} |
| 2375 |
} |
| 2376 |
|
| 2377 |
// Themes. |
| 2378 |
if ( wpvulnerability_analyze_filter( 'themes' ) ) { |
| 2379 |
$badge_class = $themes_count > 0 ? 'wpvuln-badge-critical' : 'wpvuln-badge-secure'; |
| 2380 |
$badge_icon = $themes_count > 0 ? '✕' : '✓'; |
| 2381 |
echo '<div class="wpvuln-component">'; |
| 2382 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-theme.svg" width="16" height="16" alt="">'; |
| 2383 |
echo '<span class="wpvuln-component-name">' . esc_html( __( 'Themes', 'wpvulnerability' ) ) . '</span>'; |
| 2384 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $themes_count ) . '</span>'; |
| 2385 |
echo '</div>'; |
| 2386 |
if ( $themes_count > 0 ) { |
| 2387 |
echo '<div class="wpvuln-plugin-list">'; |
| 2388 |
echo wpvulnerability_list_themes(); // phpcs:ignore |
| 2389 |
echo '</div>'; |
| 2390 |
} |
| 2391 |
} |
| 2392 |
|
| 2393 |
// Server Software section. |
| 2394 |
$php_version = wpvulnerability_detect_php(); |
| 2395 |
$webserver = wpvulnerability_detect_webserver(); |
| 2396 |
$sqlserver = wpvulnerability_detect_sqlserver(); |
| 2397 |
$show_server_section = false; |
| 2398 |
|
| 2399 |
// Check if any server software is detected. |
| 2400 |
if ( ( wpvulnerability_analyze_filter( 'php' ) && $php_version ) || |
| 2401 |
( isset( $webserver['id'] ) && isset( $webserver['version'] ) ) || |
| 2402 |
( isset( $sqlserver['id'] ) && isset( $sqlserver['version'] ) ) || |
| 2403 |
wpvulnerability_get_software_version( 'imagemagick' ) || |
| 2404 |
wpvulnerability_get_software_version( 'curl' ) || |
| 2405 |
wpvulnerability_get_software_version( 'memcached' ) || |
| 2406 |
wpvulnerability_get_software_version( 'redis' ) || |
| 2407 |
wpvulnerability_get_software_version( 'sqlite' ) ) { |
| 2408 |
$show_server_section = true; |
| 2409 |
} |
| 2410 |
|
| 2411 |
if ( $show_server_section ) { |
| 2412 |
echo '<div class="wpvuln-section-title">' . esc_html( __( 'Server Software', 'wpvulnerability' ) ) . '</div>'; |
| 2413 |
echo '<div class="wpvuln-grid">'; |
| 2414 |
|
| 2415 |
// PHP. |
| 2416 |
if ( wpvulnerability_analyze_filter( 'php' ) && $php_version ) { |
| 2417 |
$badge_class = $php_count > 0 ? 'wpvuln-badge-critical' : 'wpvuln-badge-secure'; |
| 2418 |
$badge_icon = $php_count > 0 ? '✕' : '✓'; |
| 2419 |
echo '<div class="wpvuln-component">'; |
| 2420 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-php.svg" width="16" height="16" alt="">'; |
| 2421 |
echo '<span class="wpvuln-component-name">PHP ' . esc_html( $php_version ) . '</span>'; |
| 2422 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $php_count ) . '</span>'; |
| 2423 |
echo '</div>'; |
| 2424 |
} |
| 2425 |
|
| 2426 |
// Web server (Apache/nginx). |
| 2427 |
if ( isset( $webserver['id'] ) && isset( $webserver['version'] ) ) { |
| 2428 |
if ( 'apache' === $webserver['id'] && wpvulnerability_analyze_filter( 'apache' ) ) { |
| 2429 |
$badge_class = $apache_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2430 |
$badge_icon = $apache_count > 0 ? '✕' : '✓'; |
| 2431 |
echo '<div class="wpvuln-component">'; |
| 2432 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-apache.svg" width="16" height="16" alt="">'; |
| 2433 |
echo '<span class="wpvuln-component-name">Apache ' . esc_html( $webserver['version'] ) . '</span>'; |
| 2434 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $apache_count ) . '</span>'; |
| 2435 |
echo '</div>'; |
| 2436 |
} elseif ( 'nginx' === $webserver['id'] && wpvulnerability_analyze_filter( 'nginx' ) ) { |
| 2437 |
$badge_class = $nginx_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2438 |
$badge_icon = $nginx_count > 0 ? '✕' : '✓'; |
| 2439 |
echo '<div class="wpvuln-component">'; |
| 2440 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-nginx.svg" width="16" height="16" alt="">'; |
| 2441 |
echo '<span class="wpvuln-component-name">nginx ' . esc_html( $webserver['version'] ) . '</span>'; |
| 2442 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $nginx_count ) . '</span>'; |
| 2443 |
echo '</div>'; |
| 2444 |
} |
| 2445 |
} |
| 2446 |
|
| 2447 |
// Database (MariaDB/MySQL). |
| 2448 |
if ( isset( $sqlserver['id'] ) && isset( $sqlserver['version'] ) ) { |
| 2449 |
if ( 'mariadb' === $sqlserver['id'] && wpvulnerability_analyze_filter( 'mariadb' ) ) { |
| 2450 |
$badge_class = $mariadb_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2451 |
$badge_icon = $mariadb_count > 0 ? '✕' : '✓'; |
| 2452 |
echo '<div class="wpvuln-component">'; |
| 2453 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-mariadb.svg" width="16" height="16" alt="">'; |
| 2454 |
echo '<span class="wpvuln-component-name">MariaDB ' . esc_html( $sqlserver['version'] ) . '</span>'; |
| 2455 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $mariadb_count ) . '</span>'; |
| 2456 |
echo '</div>'; |
| 2457 |
} elseif ( 'mysql' === $sqlserver['id'] && wpvulnerability_analyze_filter( 'mysql' ) ) { |
| 2458 |
$badge_class = $mysql_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2459 |
$badge_icon = $mysql_count > 0 ? '✕' : '✓'; |
| 2460 |
echo '<div class="wpvuln-component">'; |
| 2461 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-mysql.svg" width="16" height="16" alt="">'; |
| 2462 |
echo '<span class="wpvuln-component-name">MySQL ' . esc_html( $sqlserver['version'] ) . '</span>'; |
| 2463 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $mysql_count ) . '</span>'; |
| 2464 |
echo '</div>'; |
| 2465 |
} |
| 2466 |
} |
| 2467 |
|
| 2468 |
// ImageMagick. |
| 2469 |
$imagemagick_version = wpvulnerability_get_software_version( 'imagemagick' ); |
| 2470 |
if ( $imagemagick_version && wpvulnerability_analyze_filter( 'imagemagick' ) ) { |
| 2471 |
$badge_class = $imagemagick_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2472 |
$badge_icon = $imagemagick_count > 0 ? '✕' : '✓'; |
| 2473 |
echo '<div class="wpvuln-component">'; |
| 2474 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-imagemagick.svg" width="16" height="16" alt="">'; |
| 2475 |
echo '<span class="wpvuln-component-name">ImageMagick ' . esc_html( $imagemagick_version ) . '</span>'; |
| 2476 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $imagemagick_count ) . '</span>'; |
| 2477 |
echo '</div>'; |
| 2478 |
} |
| 2479 |
|
| 2480 |
// curl. |
| 2481 |
$curl_version = wpvulnerability_get_software_version( 'curl' ); |
| 2482 |
if ( $curl_version && wpvulnerability_analyze_filter( 'curl' ) ) { |
| 2483 |
$badge_class = $curl_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2484 |
$badge_icon = $curl_count > 0 ? '✕' : '✓'; |
| 2485 |
echo '<div class="wpvuln-component">'; |
| 2486 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-curl.svg" width="16" height="16" alt="">'; |
| 2487 |
echo '<span class="wpvuln-component-name">curl ' . esc_html( $curl_version ) . '</span>'; |
| 2488 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $curl_count ) . '</span>'; |
| 2489 |
echo '</div>'; |
| 2490 |
} |
| 2491 |
|
| 2492 |
// memcached. |
| 2493 |
$memcached_version = wpvulnerability_get_software_version( 'memcached' ); |
| 2494 |
if ( $memcached_version && wpvulnerability_analyze_filter( 'memcached' ) ) { |
| 2495 |
$badge_class = $memcached_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2496 |
$badge_icon = $memcached_count > 0 ? '✕' : '✓'; |
| 2497 |
echo '<div class="wpvuln-component">'; |
| 2498 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-memcached.svg" width="16" height="16" alt="">'; |
| 2499 |
echo '<span class="wpvuln-component-name">memcached ' . esc_html( $memcached_version ) . '</span>'; |
| 2500 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $memcached_count ) . '</span>'; |
| 2501 |
echo '</div>'; |
| 2502 |
} |
| 2503 |
|
| 2504 |
// Redis. |
| 2505 |
$redis_version = wpvulnerability_get_software_version( 'redis' ); |
| 2506 |
if ( $redis_version && wpvulnerability_analyze_filter( 'redis' ) ) { |
| 2507 |
$badge_class = $redis_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2508 |
$badge_icon = $redis_count > 0 ? '✕' : '✓'; |
| 2509 |
echo '<div class="wpvuln-component">'; |
| 2510 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-redis.svg" width="16" height="16" alt="">'; |
| 2511 |
echo '<span class="wpvuln-component-name">Redis ' . esc_html( $redis_version ) . '</span>'; |
| 2512 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $redis_count ) . '</span>'; |
| 2513 |
echo '</div>'; |
| 2514 |
} |
| 2515 |
|
| 2516 |
// SQLite. |
| 2517 |
$sqlite_version = wpvulnerability_get_software_version( 'sqlite' ); |
| 2518 |
if ( $sqlite_version && wpvulnerability_analyze_filter( 'sqlite' ) ) { |
| 2519 |
$badge_class = $sqlite_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure'; |
| 2520 |
$badge_icon = $sqlite_count > 0 ? '✕' : '✓'; |
| 2521 |
echo '<div class="wpvuln-component">'; |
| 2522 |
echo '<img src="' . esc_url( WPVULNERABILITY_PLUGIN_URL ) . 'assets/icon-sqlite.svg" width="16" height="16" alt="">'; |
| 2523 |
echo '<span class="wpvuln-component-name">SQLite ' . esc_html( $sqlite_version ) . '</span>'; |
| 2524 |
echo '<span class="wpvuln-badge ' . esc_attr( $badge_class ) . '">' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $sqlite_count ) . '</span>'; |
| 2525 |
echo '</div>'; |
| 2526 |
} |
| 2527 |
|
| 2528 |
echo '</div>'; |
| 2529 |
} |
| 2530 |
} |
| 2531 |
|
| 2532 |
// Footer links. |
| 2533 |
echo '<div class="wpvuln-footer">'; |
| 2534 |
if ( version_compare( get_bloginfo( 'version' ), '5.2', '>=' ) ) { |
| 2535 |
echo '<a href="' . esc_url( get_admin_url( null, 'site-health.php' ) ) . '">' . esc_html( __( 'Site Health', 'wpvulnerability' ) ) . '</a> | '; |
| 2536 |
} |
| 2537 |
echo '<a href="' . esc_url( admin_url( 'options-general.php?page=wpvulnerability-options' ) ) . '">' . esc_html( __( 'Settings', 'wpvulnerability' ) ) . '</a>'; |
| 2538 |
echo '</div>'; |
| 2539 |
} |
| 2540 |
|
| 2541 |
/** |
| 2542 |
* Created a widget in the WordPress dashboard with vulnerability info. |
| 2543 |
* |
| 2544 |
* @since 2.2.0 |
| 2545 |
* |
| 2546 |
* @return void |
| 2547 |
*/ |
| 2548 |
function wpvulnerability_admin_dashboard() { |
| 2549 |
if ( wpvulnerability_capabilities() ) { |
| 2550 |
wp_add_dashboard_widget( |
| 2551 |
'wpvulnerability', |
| 2552 |
__( 'WPVulnerability Status', 'wpvulnerability' ), |
| 2553 |
'wpvulnerability_admin_dashboard_content', |
| 2554 |
null, |
| 2555 |
null, |
| 2556 |
'side', |
| 2557 |
'high' |
| 2558 |
); |
| 2559 |
} |
| 2560 |
} |
| 2561 |
add_action( 'wp_dashboard_setup', 'wpvulnerability_admin_dashboard' ); |
| 2562 |
|
| 2563 |
/** |
| 2564 |
* Initializes the WP-Admin settings page for the WP Vulnerability plugin |
| 2565 |
* |
| 2566 |
* @since 2.0.0 |
| 2567 |
* |
| 2568 |
* @return void |
| 2569 |
*/ |
| 2570 |
function wpvulnerability_admin_init() { |
| 2571 |
// Register the plugin settings to be saved in the database. |
| 2572 |
register_setting( |
| 2573 |
'admin_wpvulnerability_settings', |
| 2574 |
'wpvulnerability-config', |
| 2575 |
'wpvulnerability_admin_sanitize' |
| 2576 |
); |
| 2577 |
|
| 2578 |
// Add a section to the settings page. |
| 2579 |
add_settings_section( |
| 2580 |
'admin_wpvulnerability_settings', |
| 2581 |
__( 'Receive vulnerability notifications', 'wpvulnerability' ), |
| 2582 |
'wpvulnerability_admin_section_notifications', |
| 2583 |
'wpvulnerability-config' |
| 2584 |
); |
| 2585 |
|
| 2586 |
// Add a field for the cache expiration time. |
| 2587 |
add_settings_field( |
| 2588 |
'wpvulnerability_cache', |
| 2589 |
__( 'Cache expiration time', 'wpvulnerability' ), |
| 2590 |
'wpvulnerability_admin_cache_callback', |
| 2591 |
'wpvulnerability-config', |
| 2592 |
'admin_wpvulnerability_settings' |
| 2593 |
); |
| 2594 |
|
| 2595 |
// Add a field for the notification period. |
| 2596 |
add_settings_field( |
| 2597 |
'wpvulnerability_period', |
| 2598 |
__( 'How often you want to receive notifications', 'wpvulnerability' ), |
| 2599 |
'wpvulnerability_admin_period_callback', |
| 2600 |
'wpvulnerability-config', |
| 2601 |
'admin_wpvulnerability_settings' |
| 2602 |
); |
| 2603 |
|
| 2604 |
// Add a field for notification methods. |
| 2605 |
add_settings_field( |
| 2606 |
'wpvulnerability_notify', |
| 2607 |
__( 'Where do you want to receive notifications?', 'wpvulnerability' ), |
| 2608 |
'wpvulnerability_admin_notify_callback', |
| 2609 |
'wpvulnerability-config', |
| 2610 |
'admin_wpvulnerability_settings' |
| 2611 |
); |
| 2612 |
|
| 2613 |
// Add a field for the email addresses. |
| 2614 |
add_settings_field( |
| 2615 |
'wpvulnerability_emails', |
| 2616 |
__( 'Email addresses to notify (separated by commas)', 'wpvulnerability' ), |
| 2617 |
'wpvulnerability_admin_emails_callback', |
| 2618 |
'wpvulnerability-config', |
| 2619 |
'admin_wpvulnerability_settings' |
| 2620 |
); |
| 2621 |
|
| 2622 |
// Add a field for the Slack webhook. |
| 2623 |
add_settings_field( |
| 2624 |
'wpvulnerability_slack_webhook', |
| 2625 |
__( 'Slack webhook URL', 'wpvulnerability' ), |
| 2626 |
'wpvulnerability_admin_slack_callback', |
| 2627 |
'wpvulnerability-config', |
| 2628 |
'admin_wpvulnerability_settings' |
| 2629 |
); |
| 2630 |
|
| 2631 |
// Add a field for the Teams webhook. |
| 2632 |
add_settings_field( |
| 2633 |
'wpvulnerability_teams_webhook', |
| 2634 |
__( 'Teams webhook URL', 'wpvulnerability' ), |
| 2635 |
'wpvulnerability_admin_teams_callback', |
| 2636 |
'wpvulnerability-config', |
| 2637 |
'admin_wpvulnerability_settings' |
| 2638 |
); |
| 2639 |
|
| 2640 |
// Register the settings for analysis. |
| 2641 |
register_setting( |
| 2642 |
'admin_wpvulnerability_analyze', |
| 2643 |
'wpvulnerability-analyze', |
| 2644 |
'wpvulnerability_analyze_sanitize' |
| 2645 |
); |
| 2646 |
|
| 2647 |
// Add a section for analyzing settings. |
| 2648 |
add_settings_section( |
| 2649 |
'admin_wpvulnerability_analyze', |
| 2650 |
__( 'Vulnerabilities to hide', 'wpvulnerability' ), |
| 2651 |
'wpvulnerability_admin_section_analyze', |
| 2652 |
'wpvulnerability-analyze' |
| 2653 |
); |
| 2654 |
|
| 2655 |
// Add a field for analysis options. |
| 2656 |
add_settings_field( |
| 2657 |
'wpvulnerability_analyze', |
| 2658 |
__( 'What do you want to hide?', 'wpvulnerability' ), |
| 2659 |
'wpvulnerability_admin_analyze_callback', |
| 2660 |
'wpvulnerability-analyze', |
| 2661 |
'admin_wpvulnerability_analyze' |
| 2662 |
); |
| 2663 |
} |
| 2664 |
add_action( 'admin_init', 'wpvulnerability_admin_init' ); |
| 2665 |
|
| 2666 |
/** |
| 2667 |
* Outputs the Security tab contents. |
| 2668 |
* |
| 2669 |
* Displays shell_exec security status, detection methods, and audit logs. |
| 2670 |
* |
| 2671 |
* @since 4.3.0 |
| 2672 |
* |
| 2673 |
* @return void |
| 2674 |
*/ |
| 2675 |
function wpvulnerability_render_admin_tab_security() { |
| 2676 |
?> |
| 2677 |
<section class="section wpvulnerability-security-panel"> |
| 2678 |
|
| 2679 |
<?php wpvulnerability_display_security_status(); ?> |
| 2680 |
<?php wpvulnerability_display_detection_methods(); ?> |
| 2681 |
<?php wpvulnerability_display_security_logs(); ?> |
| 2682 |
</section> |
| 2683 |
<?php |
| 2684 |
} |
| 2685 |
|
| 2686 |
/** |
| 2687 |
* Displays the security status section. |
| 2688 |
* |
| 2689 |
* Shows current security mode, shell_exec availability, and logging status. |
| 2690 |
* |
| 2691 |
* @since 4.3.0 |
| 2692 |
* |
| 2693 |
* @return void |
| 2694 |
*/ |
| 2695 |
function wpvulnerability_display_security_status() { |
| 2696 |
$security_mode = wpvulnerability_get_security_mode(); |
| 2697 |
$shell_exec_enabled = wpvulnerability_can_shell_exec(); |
| 2698 |
$log_retention = wpvulnerability_log_retention_days(); |
| 2699 |
$total_logs = wpvulnerability_count_shell_exec_logs(); |
| 2700 |
$last_log = null; |
| 2701 |
|
| 2702 |
$recent_logs = wpvulnerability_get_shell_exec_logs( 1, 1 ); |
| 2703 |
if ( ! empty( $recent_logs ) ) { |
| 2704 |
$last_log = $recent_logs[0]; |
| 2705 |
} |
| 2706 |
|
| 2707 |
$mode_labels = array( |
| 2708 |
'standard' => __( 'Standard (Hybrid Detection)', 'wpvulnerability' ), |
| 2709 |
'strict' => __( 'Strict (Extensions Only)', 'wpvulnerability' ), |
| 2710 |
'disabled' => __( 'Disabled (No Detection)', 'wpvulnerability' ), |
| 2711 |
); |
| 2712 |
|
| 2713 |
$mode_label = isset( $mode_labels[ $security_mode ] ) ? $mode_labels[ $security_mode ] : $security_mode; |
| 2714 |
?> |
| 2715 |
<div class="wpvulnerability-security-section"> |
| 2716 |
<h3><?php esc_html_e( 'Security Status', 'wpvulnerability' ); ?></h3> |
| 2717 |
|
| 2718 |
<div class="wpvulnerability-status-grid"> |
| 2719 |
<div class="wpvulnerability-status-item"> |
| 2720 |
<strong><?php esc_html_e( 'Security Mode', 'wpvulnerability' ); ?></strong> |
| 2721 |
<span><?php echo esc_html( $mode_label ); ?></span> |
| 2722 |
</div> |
| 2723 |
|
| 2724 |
<div class="wpvulnerability-status-item"> |
| 2725 |
<strong><?php esc_html_e( 'Shell Execution', 'wpvulnerability' ); ?></strong> |
| 2726 |
<?php if ( $shell_exec_enabled ) : ?> |
| 2727 |
<span class="wpvulnerability-status-badge success"><?php esc_html_e( 'Enabled', 'wpvulnerability' ); ?></span> |
| 2728 |
<?php else : ?> |
| 2729 |
<span class="wpvulnerability-status-badge disabled"><?php esc_html_e( 'Disabled', 'wpvulnerability' ); ?></span> |
| 2730 |
<?php endif; ?> |
| 2731 |
</div> |
| 2732 |
|
| 2733 |
<div class="wpvulnerability-status-item"> |
| 2734 |
<strong><?php esc_html_e( 'Audit Logging', 'wpvulnerability' ); ?></strong> |
| 2735 |
<?php if ( $log_retention > 0 ) : ?> |
| 2736 |
<span class="wpvulnerability-status-badge success"> |
| 2737 |
<?php |
| 2738 |
/* translators: %d: number of days */ |
| 2739 |
echo esc_html( sprintf( __( 'Enabled (%d days)', 'wpvulnerability' ), $log_retention ) ); |
| 2740 |
?> |
| 2741 |
</span> |
| 2742 |
<?php else : ?> |
| 2743 |
<span class="wpvulnerability-status-badge disabled"><?php esc_html_e( 'Disabled', 'wpvulnerability' ); ?></span> |
| 2744 |
<?php endif; ?> |
| 2745 |
</div> |
| 2746 |
|
| 2747 |
<div class="wpvulnerability-status-item"> |
| 2748 |
<strong><?php esc_html_e( 'Total Log Entries', 'wpvulnerability' ); ?></strong> |
| 2749 |
<span><?php echo esc_html( number_format_i18n( $total_logs ) ); ?></span> |
| 2750 |
</div> |
| 2751 |
</div> |
| 2752 |
|
| 2753 |
<?php if ( $last_log ) : ?> |
| 2754 |
<div class="wpvulnerability-status-item" style="margin-top: 10px;"> |
| 2755 |
<strong><?php esc_html_e( 'Last Shell Execution', 'wpvulnerability' ); ?></strong> |
| 2756 |
<span> |
| 2757 |
<?php |
| 2758 |
echo esc_html( |
| 2759 |
sprintf( |
| 2760 |
/* translators: %s: time ago */ |
| 2761 |
__( '%s ago', 'wpvulnerability' ), |
| 2762 |
human_time_diff( strtotime( $last_log->post_date ), time() ) |
| 2763 |
) |
| 2764 |
); |
| 2765 |
?> |
| 2766 |
</span> |
| 2767 |
</div> |
| 2768 |
<?php endif; ?> |
| 2769 |
|
| 2770 |
<div class="wpvulnerability-info-box"> |
| 2771 |
<p> |
| 2772 |
<?php |
| 2773 |
esc_html_e( 'Configure security settings via wp-config.php constants: WPVULNERABILITY_DISABLE_SHELL_EXEC, WPVULNERABILITY_SECURITY_MODE, WPVULNERABILITY_SHELL_EXEC_WHITELIST.', 'wpvulnerability' ); |
| 2774 |
?> |
| 2775 |
<br> |
| 2776 |
<?php |
| 2777 |
printf( |
| 2778 |
/* translators: %s: URL to security documentation */ |
| 2779 |
wp_kses_post( __( 'See <a href="%s" target="_blank" rel="noopener noreferrer">security configuration documentation</a> for details.', 'wpvulnerability' ) ), |
| 2780 |
esc_url( 'https://www.wpvulnerability.com/plugin/#security-configuration' ) |
| 2781 |
); |
| 2782 |
?> |
| 2783 |
</p> |
| 2784 |
</div> |
| 2785 |
</div> |
| 2786 |
<?php |
| 2787 |
} |
| 2788 |
|
| 2789 |
/** |
| 2790 |
* Displays the detection methods section. |
| 2791 |
* |
| 2792 |
* Shows which detection method was used for each software component |
| 2793 |
* with reliability scoring. |
| 2794 |
* |
| 2795 |
* @since 4.3.0 |
| 2796 |
* |
| 2797 |
* @return void |
| 2798 |
*/ |
| 2799 |
function wpvulnerability_display_detection_methods() { |
| 2800 |
$components = array( |
| 2801 |
'imagemagick' => __( 'ImageMagick', 'wpvulnerability' ), |
| 2802 |
'redis' => __( 'Redis', 'wpvulnerability' ), |
| 2803 |
'memcached' => __( 'Memcached', 'wpvulnerability' ), |
| 2804 |
'sqlite' => __( 'SQLite', 'wpvulnerability' ), |
| 2805 |
); |
| 2806 |
|
| 2807 |
$detections = array(); |
| 2808 |
|
| 2809 |
foreach ( array_keys( $components ) as $component ) { |
| 2810 |
$detection = null; |
| 2811 |
|
| 2812 |
switch ( $component ) { |
| 2813 |
case 'imagemagick': |
| 2814 |
$detection = wpvulnerability_detect_imagemagick(); |
| 2815 |
break; |
| 2816 |
case 'redis': |
| 2817 |
$detection = wpvulnerability_detect_redis(); |
| 2818 |
break; |
| 2819 |
case 'memcached': |
| 2820 |
$detection = wpvulnerability_detect_memcached(); |
| 2821 |
break; |
| 2822 |
case 'sqlite': |
| 2823 |
$detection = wpvulnerability_detect_sqlite(); |
| 2824 |
break; |
| 2825 |
} |
| 2826 |
|
| 2827 |
if ( is_array( $detection ) ) { |
| 2828 |
$detections[ $component ] = $detection; |
| 2829 |
} |
| 2830 |
} |
| 2831 |
|
| 2832 |
$method_labels = array( |
| 2833 |
'imagick_extension' => __( 'Imagick Extension', 'wpvulnerability' ), |
| 2834 |
'redis_extension' => __( 'Redis Extension', 'wpvulnerability' ), |
| 2835 |
'memcached_extension' => __( 'Memcached Extension', 'wpvulnerability' ), |
| 2836 |
'memcache_extension' => __( 'Memcache Extension', 'wpvulnerability' ), |
| 2837 |
'sqlite3_extension' => __( 'SQLite3 Extension', 'wpvulnerability' ), |
| 2838 |
'pdo_sqlite' => __( 'PDO SQLite', 'wpvulnerability' ), |
| 2839 |
'shell_exec' => __( 'Shell Command', 'wpvulnerability' ), |
| 2840 |
'binary_exists' => __( 'Binary Check', 'wpvulnerability' ), |
| 2841 |
'none' => __( 'Not Detected', 'wpvulnerability' ), |
| 2842 |
); |
| 2843 |
?> |
| 2844 |
<div class="wpvulnerability-security-section"> |
| 2845 |
<h3><?php esc_html_e( 'Software Detection Methods', 'wpvulnerability' ); ?></h3> |
| 2846 |
<p><?php esc_html_e( 'Shows which detection method was used for each software component and the reliability score.', 'wpvulnerability' ); ?></p> |
| 2847 |
|
| 2848 |
<table class="wpvulnerability-detection-table"> |
| 2849 |
<thead> |
| 2850 |
<tr> |
| 2851 |
<th><?php esc_html_e( 'Component', 'wpvulnerability' ); ?></th> |
| 2852 |
<th><?php esc_html_e( 'Version', 'wpvulnerability' ); ?></th> |
| 2853 |
<th><?php esc_html_e( 'Detection Method', 'wpvulnerability' ); ?></th> |
| 2854 |
<th><?php esc_html_e( 'Reliability', 'wpvulnerability' ); ?></th> |
| 2855 |
</tr> |
| 2856 |
</thead> |
| 2857 |
<tbody> |
| 2858 |
<?php foreach ( $detections as $component => $detection ) : ?> |
| 2859 |
<tr> |
| 2860 |
<td><strong><?php echo esc_html( $components[ $component ] ); ?></strong></td> |
| 2861 |
<td> |
| 2862 |
<?php |
| 2863 |
if ( ! empty( $detection['version'] ) && 'unknown' !== $detection['version'] ) { |
| 2864 |
echo esc_html( $detection['version'] ); |
| 2865 |
} else { |
| 2866 |
echo '<span style="color: #646970;">' . esc_html__( 'Not detected', 'wpvulnerability' ) . '</span>'; |
| 2867 |
} |
| 2868 |
?> |
| 2869 |
</td> |
| 2870 |
<td> |
| 2871 |
<?php |
| 2872 |
$method = isset( $method_labels[ $detection['method'] ] ) ? $method_labels[ $detection['method'] ] : $detection['method']; |
| 2873 |
echo esc_html( $method ); |
| 2874 |
?> |
| 2875 |
</td> |
| 2876 |
<td> |
| 2877 |
<?php |
| 2878 |
$reliability = isset( $detection['reliability'] ) ? (int) $detection['reliability'] : 0; |
| 2879 |
|
| 2880 |
if ( $reliability > 0 ) { |
| 2881 |
$reliability_class = 'low'; |
| 2882 |
if ( $reliability >= 80 ) { |
| 2883 |
$reliability_class = ''; |
| 2884 |
} elseif ( $reliability >= 50 ) { |
| 2885 |
$reliability_class = 'medium'; |
| 2886 |
} |
| 2887 |
?> |
| 2888 |
<span class="wpvulnerability-reliability-bar"> |
| 2889 |
<span class="wpvulnerability-reliability-fill <?php echo esc_attr( $reliability_class ); ?>" style="width: <?php echo esc_attr( $reliability ); ?>%;"></span> |
| 2890 |
</span> |
| 2891 |
<span><?php echo esc_html( $reliability ); ?>%</span> |
| 2892 |
<?php |
| 2893 |
} else { |
| 2894 |
?> |
| 2895 |
<span style="color: #646970;">—</span> |
| 2896 |
<?php |
| 2897 |
} |
| 2898 |
?> |
| 2899 |
</td> |
| 2900 |
</tr> |
| 2901 |
<?php endforeach; ?> |
| 2902 |
</tbody> |
| 2903 |
</table> |
| 2904 |
</div> |
| 2905 |
<?php |
| 2906 |
} |
| 2907 |
|
| 2908 |
/** |
| 2909 |
* Displays the shell execution audit logs section. |
| 2910 |
* |
| 2911 |
* Shows recent shell_exec calls with full details for security auditing. |
| 2912 |
* |
| 2913 |
* @since 4.3.0 |
| 2914 |
* |
| 2915 |
* @return void |
| 2916 |
*/ |
| 2917 |
function wpvulnerability_display_security_logs() { |
| 2918 |
$per_page = 20; |
| 2919 |
$logs = wpvulnerability_get_shell_exec_logs( $per_page, 1 ); |
| 2920 |
?> |
| 2921 |
<div class="wpvulnerability-security-section"> |
| 2922 |
<h3><?php esc_html_e( 'Shell Execution Audit Logs', 'wpvulnerability' ); ?></h3> |
| 2923 |
<p><?php esc_html_e( 'Complete audit trail of shell command executions for security monitoring.', 'wpvulnerability' ); ?></p> |
| 2924 |
|
| 2925 |
<?php if ( empty( $logs ) ) : ?> |
| 2926 |
<div class="wpvulnerability-empty-state"> |
| 2927 |
<div class="wpvulnerability-empty-state-icon">🔒</div> |
| 2928 |
<p><strong><?php esc_html_e( 'No shell execution logs found.', 'wpvulnerability' ); ?></strong></p> |
| 2929 |
<p><?php esc_html_e( 'Logs will appear here when shell commands are executed for software detection.', 'wpvulnerability' ); ?></p> |
| 2930 |
</div> |
| 2931 |
<?php else : ?> |
| 2932 |
<table class="wpvulnerability-logs-table"> |
| 2933 |
<thead> |
| 2934 |
<tr> |
| 2935 |
<th><?php esc_html_e( 'Time', 'wpvulnerability' ); ?></th> |
| 2936 |
<th><?php esc_html_e( 'Component', 'wpvulnerability' ); ?></th> |
| 2937 |
<th><?php esc_html_e( 'Command', 'wpvulnerability' ); ?></th> |
| 2938 |
<th><?php esc_html_e( 'Status', 'wpvulnerability' ); ?></th> |
| 2939 |
<th><?php esc_html_e( 'User', 'wpvulnerability' ); ?></th> |
| 2940 |
<th><?php esc_html_e( 'Output', 'wpvulnerability' ); ?></th> |
| 2941 |
</tr> |
| 2942 |
</thead> |
| 2943 |
<tbody> |
| 2944 |
<?php foreach ( $logs as $log ) : ?> |
| 2945 |
<?php |
| 2946 |
$log_data = json_decode( $log->post_content, true ); |
| 2947 |
if ( ! $log_data ) { |
| 2948 |
continue; |
| 2949 |
} |
| 2950 |
?> |
| 2951 |
<tr> |
| 2952 |
<td> |
| 2953 |
<?php |
| 2954 |
echo esc_html( |
| 2955 |
sprintf( |
| 2956 |
/* translators: %s: time ago */ |
| 2957 |
__( '%s ago', 'wpvulnerability' ), |
| 2958 |
human_time_diff( strtotime( $log->post_date ), time() ) |
| 2959 |
) |
| 2960 |
); |
| 2961 |
?> |
| 2962 |
</td> |
| 2963 |
<td><code><?php echo esc_html( $log_data['component'] ); ?></code></td> |
| 2964 |
<td><code><?php echo esc_html( $log_data['command'] ); ?></code></td> |
| 2965 |
<td> |
| 2966 |
<?php if ( $log_data['success'] ) : ?> |
| 2967 |
<span class="wpvulnerability-status-badge success"><?php echo esc_html( ucfirst( $log_data['reason'] ) ); ?></span> |
| 2968 |
<?php else : ?> |
| 2969 |
<span class="wpvulnerability-status-badge warning"><?php echo esc_html( ucfirst( $log_data['reason'] ) ); ?></span> |
| 2970 |
<?php endif; ?> |
| 2971 |
</td> |
| 2972 |
<td><?php echo esc_html( $log_data['user'] ); ?></td> |
| 2973 |
<td> |
| 2974 |
<?php if ( ! empty( $log_data['output'] ) ) : ?> |
| 2975 |
<div class="wpvulnerability-log-output" title="<?php echo esc_attr( $log_data['output'] ); ?>"> |
| 2976 |
<?php echo esc_html( substr( $log_data['output'], 0, 50 ) ); ?> |
| 2977 |
<?php if ( strlen( $log_data['output'] ) > 50 ) : ?> |
| 2978 |
<span>...</span> |
| 2979 |
<?php endif; ?> |
| 2980 |
</div> |
| 2981 |
<?php else : ?> |
| 2982 |
<span style="color: #646970;">—</span> |
| 2983 |
<?php endif; ?> |
| 2984 |
</td> |
| 2985 |
</tr> |
| 2986 |
<?php endforeach; ?> |
| 2987 |
</tbody> |
| 2988 |
</table> |
| 2989 |
|
| 2990 |
<p style="margin-top: 15px; color: #646970; font-size: 13px;"> |
| 2991 |
<?php |
| 2992 |
/* translators: %d: number of logs shown */ |
| 2993 |
echo esc_html( sprintf( __( 'Showing the %d most recent log entries.', 'wpvulnerability' ), $per_page ) ); |
| 2994 |
?> |
| 2995 |
</p> |
| 2996 |
<?php endif; ?> |
| 2997 |
</div> |
| 2998 |
<?php |
| 2999 |
} |
| 3000 |
|
| 3001 |
/** |
| 3002 |
* AJAX handler for testing API connectivity. |
| 3003 |
* |
| 3004 |
* @since 4.3.0 |
| 3005 |
* |
| 3006 |
* @return void |
| 3007 |
*/ |
| 3008 |
function wpvulnerability_ajax_test_api() { |
| 3009 |
// Verify nonce. |
| 3010 |
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'wpvulnerability_test_api' ) ) { |
| 3011 |
wp_send_json_error( array( 'message' => __( 'Invalid nonce.', 'wpvulnerability' ) ) ); |
| 3012 |
} |
| 3013 |
|
| 3014 |
// Check permissions. |
| 3015 |
if ( ! current_user_can( 'manage_options' ) ) { |
| 3016 |
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'wpvulnerability' ) ) ); |
| 3017 |
} |
| 3018 |
|
| 3019 |
// Get component. |
| 3020 |
$component = isset( $_POST['component'] ) ? sanitize_key( $_POST['component'] ) : ''; |
| 3021 |
if ( empty( $component ) ) { |
| 3022 |
wp_send_json_error( array( 'message' => __( 'No component specified.', 'wpvulnerability' ) ) ); |
| 3023 |
} |
| 3024 |
|
| 3025 |
// Load debug functions. |
| 3026 |
if ( ! function_exists( 'wpvulnerability_debug_test_api_component' ) ) { |
| 3027 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php'; |
| 3028 |
} |
| 3029 |
|
| 3030 |
// Test API. |
| 3031 |
$result = wpvulnerability_debug_test_api_component( $component ); |
| 3032 |
|
| 3033 |
wp_send_json_success( $result ); |
| 3034 |
} |
| 3035 |
add_action( 'wp_ajax_wpvulnerability_test_api', 'wpvulnerability_ajax_test_api' ); |
| 3036 |
|
| 3037 |
/** |
| 3038 |
* Outputs the Debug tab contents. |
| 3039 |
* |
| 3040 |
* @since 4.3.0 |
| 3041 |
* |
| 3042 |
* @return void |
| 3043 |
*/ |
| 3044 |
function wpvulnerability_render_admin_tab_debug() { |
| 3045 |
// Security check: only show in debug mode. |
| 3046 |
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) { |
| 3047 |
return; |
| 3048 |
} |
| 3049 |
|
| 3050 |
// Load debug functions if not already loaded. |
| 3051 |
if ( ! function_exists( 'wpvulnerability_debug_get_system_info' ) ) { |
| 3052 |
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php'; |
| 3053 |
} |
| 3054 |
|
| 3055 |
?> |
| 3056 |
<div class="wpvulnerability-section"> |
| 3057 |
<h2><?php esc_html_e( 'Debug Information', 'wpvulnerability' ); ?></h2> |
| 3058 |
<p style="color: #d63638; font-weight: 500;"> |
| 3059 |
<?php esc_html_e( 'This tab is only visible when WP_DEBUG is enabled. Use with caution.', 'wpvulnerability' ); ?> |
| 3060 |
</p> |
| 3061 |
|
| 3062 |
<?php |
| 3063 |
// Section 1: System Information. |
| 3064 |
wpvulnerability_render_debug_section_system_info(); |
| 3065 |
|
| 3066 |
// Section 2: Component Detection. |
| 3067 |
wpvulnerability_render_debug_section_components(); |
| 3068 |
|
| 3069 |
// Section 4: Configuration Summary. |
| 3070 |
wpvulnerability_render_debug_section_config(); |
| 3071 |
|
| 3072 |
// Section 5: Cron Status. |
| 3073 |
wpvulnerability_render_debug_section_cron(); |
| 3074 |
|
| 3075 |
// Section 3: API Testing. |
| 3076 |
wpvulnerability_render_debug_section_api_testing(); |
| 3077 |
|
| 3078 |
// Section 6: Database Options Viewer. |
| 3079 |
wpvulnerability_render_debug_section_database_options(); |
| 3080 |
|
| 3081 |
// Section 7: Quick Actions. |
| 3082 |
wpvulnerability_render_debug_section_quick_actions(); |
| 3083 |
?> |
| 3084 |
</div> |
| 3085 |
<?php |
| 3086 |
} |
| 3087 |
|
| 3088 |
/** |
| 3089 |
* Renders Section 1: System Information. |
| 3090 |
* |
| 3091 |
* @since 4.3.0 |
| 3092 |
* |
| 3093 |
* @return void |
| 3094 |
*/ |
| 3095 |
function wpvulnerability_render_debug_section_system_info() { |
| 3096 |
$system_info = wpvulnerability_debug_get_system_info(); |
| 3097 |
?> |
| 3098 |
<div class="wpvulnerability-subsection" style="margin-top: 20px;"> |
| 3099 |
<h3><?php esc_html_e( 'System Information', 'wpvulnerability' ); ?></h3> |
| 3100 |
<table class="widefat" style="margin-top: 10px;"> |
| 3101 |
<tbody> |
| 3102 |
<tr> |
| 3103 |
<td style="width: 200px; font-weight: 600;"><?php esc_html_e( 'WordPress Version', 'wpvulnerability' ); ?></td> |
| 3104 |
<td><?php echo esc_html( $system_info['wordpress']['version'] ); ?></td> |
| 3105 |
</tr> |
| 3106 |
<tr> |
| 3107 |
<td style="font-weight: 600;"><?php esc_html_e( 'Multisite', 'wpvulnerability' ); ?></td> |
| 3108 |
<td><?php echo $system_info['wordpress']['multisite'] ? esc_html__( 'Yes', 'wpvulnerability' ) : esc_html__( 'No', 'wpvulnerability' ); ?></td> |
| 3109 |
</tr> |
| 3110 |
<tr> |
| 3111 |
<td style="font-weight: 600;"><?php esc_html_e( 'Language', 'wpvulnerability' ); ?></td> |
| 3112 |
<td><?php echo esc_html( $system_info['wordpress']['language'] ); ?></td> |
| 3113 |
</tr> |
| 3114 |
<tr> |
| 3115 |
<td style="font-weight: 600;"><?php esc_html_e( 'PHP Version', 'wpvulnerability' ); ?></td> |
| 3116 |
<td><?php echo esc_html( $system_info['php']['version'] ); ?></td> |
| 3117 |
</tr> |
| 3118 |
<tr> |
| 3119 |
<td style="font-weight: 600;"><?php esc_html_e( 'PHP Extensions', 'wpvulnerability' ); ?></td> |
| 3120 |
<td> |
| 3121 |
<?php foreach ( $system_info['php']['extensions'] as $ext => $loaded ) : ?> |
| 3122 |
<span style="margin-right: 10px;"> |
| 3123 |
<span style="color: <?php echo $loaded ? '#00a32a' : '#d63638'; ?>;">●</span> |
| 3124 |
<?php echo esc_html( $ext ); ?> |
| 3125 |
</span> |
| 3126 |
<?php endforeach; ?> |
| 3127 |
</td> |
| 3128 |
</tr> |
| 3129 |
<tr> |
| 3130 |
<td style="font-weight: 600;"><?php esc_html_e( 'PHP Memory Limit', 'wpvulnerability' ); ?></td> |
| 3131 |
<td><?php echo esc_html( $system_info['php']['memory']['limit'] ); ?></td> |
| 3132 |
</tr> |
| 3133 |
<tr> |
| 3134 |
<td style="font-weight: 600;"><?php esc_html_e( 'Database', 'wpvulnerability' ); ?></td> |
| 3135 |
<td><?php echo esc_html( $system_info['database']['type'] . ' ' . $system_info['database']['version'] ); ?></td> |
| 3136 |
</tr> |
| 3137 |
<tr> |
| 3138 |
<td style="font-weight: 600;"><?php esc_html_e( 'Web Server', 'wpvulnerability' ); ?></td> |
| 3139 |
<td><?php echo esc_html( $system_info['webserver']['software'] ); ?></td> |
| 3140 |
</tr> |
| 3141 |
<tr> |
| 3142 |
<td style="font-weight: 600;"><?php esc_html_e( 'WP_DEBUG', 'wpvulnerability' ); ?></td> |
| 3143 |
<td> |
| 3144 |
<span style="color: <?php echo $system_info['debug']['wp_debug'] ? '#00a32a' : '#d63638'; ?>; font-weight: 600;"> |
| 3145 |
<?php echo $system_info['debug']['wp_debug'] ? esc_html__( 'Enabled', 'wpvulnerability' ) : esc_html__( 'Disabled', 'wpvulnerability' ); ?> |
| 3146 |
</span> |
| 3147 |
</td> |
| 3148 |
</tr> |
| 3149 |
<tr> |
| 3150 |
<td style="font-weight: 600;"><?php esc_html_e( 'WP_DEBUG_LOG', 'wpvulnerability' ); ?></td> |
| 3151 |
<td> |
| 3152 |
<span style="color: <?php echo $system_info['debug']['wp_debug_log'] ? '#00a32a' : '#d63638'; ?>; font-weight: 600;"> |
| 3153 |
<?php echo $system_info['debug']['wp_debug_log'] ? esc_html__( 'Enabled', 'wpvulnerability' ) : esc_html__( 'Disabled', 'wpvulnerability' ); ?> |
| 3154 |
</span> |
| 3155 |
<?php if ( $system_info['debug']['wp_debug_log'] && isset( $system_info['debug']['log_file'] ) ) : ?> |
| 3156 |
<?php $log_file = $system_info['debug']['log_file']; ?> |
| 3157 |
<?php if ( ! empty( $log_file['path'] ) ) : ?> |
| 3158 |
<br> |
| 3159 |
<span style="color: #646970; font-size: 12px;"> |
| 3160 |
<?php esc_html_e( 'Path:', 'wpvulnerability' ); ?> |
| 3161 |
<code style="background: #f0f0f0; padding: 2px 6px; border-radius: 3px;"><?php echo esc_html( $log_file['path'] ); ?></code> |
| 3162 |
</span> |
| 3163 |
<?php if ( $log_file['exists'] ) : ?> |
| 3164 |
<br> |
| 3165 |
<span style="color: #646970; font-size: 12px;"> |
| 3166 |
<?php |
| 3167 |
/* translators: %s: file size */ |
| 3168 |
echo esc_html( sprintf( __( 'Size: %s', 'wpvulnerability' ), size_format( $log_file['size'] ) ) ); |
| 3169 |
?> |
| 3170 |
</span> |
| 3171 |
<?php if ( $log_file['accessible'] && ! empty( $log_file['url'] ) ) : ?> |
| 3172 |
<br> |
| 3173 |
<a href="<?php echo esc_url( $log_file['url'] ); ?>" target="_blank" rel="noopener noreferrer" class="button button-small" style="margin-top: 5px;"> |
| 3174 |
<?php esc_html_e( 'View Log File', 'wpvulnerability' ); ?> |
| 3175 |
<span class="dashicons dashicons-external" style="font-size: 13px; margin-top: 3px;"></span> |
| 3176 |
</a> |
| 3177 |
<?php elseif ( $log_file['exists'] ) : ?> |
| 3178 |
<br> |
| 3179 |
<span style="color: #d63638; font-size: 12px;"> |
| 3180 |
<?php esc_html_e( 'Log file is not web-accessible (outside wp-content)', 'wpvulnerability' ); ?> |
| 3181 |
</span> |
| 3182 |
<?php endif; ?> |
| 3183 |
<?php else : ?> |
| 3184 |
<br> |
| 3185 |
<span style="color: #646970; font-size: 12px;"> |
| 3186 |
<?php esc_html_e( 'Log file does not exist yet', 'wpvulnerability' ); ?> |
| 3187 |
</span> |
| 3188 |
<?php endif; ?> |
| 3189 |
<?php endif; ?> |
| 3190 |
<?php endif; ?> |
| 3191 |
</td> |
| 3192 |
</tr> |
| 3193 |
<tr> |
| 3194 |
<td style="font-weight: 600;"><?php esc_html_e( 'Plugin Version', 'wpvulnerability' ); ?></td> |
| 3195 |
<td><?php echo esc_html( $system_info['plugin']['version'] ); ?></td> |
| 3196 |
</tr> |
| 3197 |
</tbody> |
| 3198 |
</table> |
| 3199 |
</div> |
| 3200 |
<?php |
| 3201 |
} |
| 3202 |
|
| 3203 |
/** |
| 3204 |
* Renders Section 2: Component Detection. |
| 3205 |
* |
| 3206 |
* @since 4.3.0 |
| 3207 |
* |
| 3208 |
* @return void |
| 3209 |
*/ |
| 3210 |
function wpvulnerability_render_debug_section_components() { |
| 3211 |
$components = wpvulnerability_debug_get_component_status(); |
| 3212 |
?> |
| 3213 |
<div class="wpvulnerability-subsection" style="margin-top: 30px;"> |
| 3214 |
<h3><?php esc_html_e( 'Component Detection', 'wpvulnerability' ); ?></h3> |
| 3215 |
<table class="widefat striped" style="margin-top: 10px;"> |
| 3216 |
<thead> |
| 3217 |
<tr> |
| 3218 |
<th><?php esc_html_e( 'Component', 'wpvulnerability' ); ?></th> |
| 3219 |
<th><?php esc_html_e( 'Status', 'wpvulnerability' ); ?></th> |
| 3220 |
<th><?php esc_html_e( 'Version Detected', 'wpvulnerability' ); ?></th> |
| 3221 |
<th><?php esc_html_e( 'Analyzed', 'wpvulnerability' ); ?></th> |
| 3222 |
<th><?php esc_html_e( 'Cache Status', 'wpvulnerability' ); ?></th> |
| 3223 |
</tr> |
| 3224 |
</thead> |
| 3225 |
<tbody> |
| 3226 |
<?php foreach ( $components as $comp ) : ?> |
| 3227 |
<tr> |
| 3228 |
<td style="font-weight: 600;"><?php echo esc_html( ucfirst( $comp['component'] ) ); ?></td> |
| 3229 |
<td> |
| 3230 |
<span style="color: <?php echo $comp['detected'] ? '#00a32a' : '#d63638'; ?>; font-size: 16px;"> |
| 3231 |
<?php echo $comp['detected'] ? '✓' : '✗'; ?> |
| 3232 |
</span> |
| 3233 |
</td> |
| 3234 |
<td><?php echo esc_html( $comp['version'] ); ?></td> |
| 3235 |
<td> |
| 3236 |
<span style="color: <?php echo $comp['analyzed'] ? '#00a32a' : '#d63638'; ?>;"> |
| 3237 |
<?php echo $comp['analyzed'] ? esc_html__( 'Yes', 'wpvulnerability' ) : esc_html__( 'No', 'wpvulnerability' ); ?> |
| 3238 |
</span> |
| 3239 |
</td> |
| 3240 |
<td> |
| 3241 |
<?php |
| 3242 |
$badge_color = '#646970'; |
| 3243 |
if ( strpos( $comp['cache_status'], 'Fresh' ) !== false ) { |
| 3244 |
$badge_color = '#00a32a'; |
| 3245 |
} elseif ( strpos( $comp['cache_status'], 'Expired' ) !== false ) { |
| 3246 |
$badge_color = '#d63638'; |
| 3247 |
} |
| 3248 |
?> |
| 3249 |
<span style="background: <?php echo esc_attr( $badge_color ); ?>; color: white; padding: 3px 8px; border-radius: 3px; font-size: 11px; font-weight: 600;"> |
| 3250 |
<?php echo esc_html( $comp['cache_status'] ); ?> |
| 3251 |
</span> |
| 3252 |
</td> |
| 3253 |
</tr> |
| 3254 |
<?php endforeach; ?> |
| 3255 |
</tbody> |
| 3256 |
</table> |
| 3257 |
</div> |
| 3258 |
<?php |
| 3259 |
} |
| 3260 |
|
| 3261 |
/** |
| 3262 |
* Renders Section 4: Configuration Summary. |
| 3263 |
* |
| 3264 |
* @since 4.3.0 |
| 3265 |
* |
| 3266 |
* @return void |
| 3267 |
*/ |
| 3268 |
function wpvulnerability_render_debug_section_config() { |
| 3269 |
$config = is_multisite() |
| 3270 |
? get_site_option( 'wpvulnerability-config', array() ) |
| 3271 |
: get_option( 'wpvulnerability-config', array() ); |
| 3272 |
?> |
| 3273 |
<div class="wpvulnerability-subsection" style="margin-top: 30px;"> |
| 3274 |
<h3><?php esc_html_e( 'Configuration Summary', 'wpvulnerability' ); ?></h3> |
| 3275 |
<table class="widefat" style="margin-top: 10px;"> |
| 3276 |
<tbody> |
| 3277 |
<tr> |
| 3278 |
<td style="width: 250px; font-weight: 600;"><?php esc_html_e( 'Cache Duration', 'wpvulnerability' ); ?></td> |
| 3279 |
<td> |
| 3280 |
<?php |
| 3281 |
$cache_hours = isset( $config['cache'] ) ? absint( $config['cache'] ) : 12; |
| 3282 |
/* translators: %d: number of hours */ |
| 3283 |
echo esc_html( sprintf( _n( '%d hour', '%d hours', $cache_hours, 'wpvulnerability' ), $cache_hours ) ); |
| 3284 |
?> |
| 3285 |
</td> |
| 3286 |
</tr> |
| 3287 |
<tr> |
| 3288 |
<td style="font-weight: 600;"><?php esc_html_e( 'Log Retention', 'wpvulnerability' ); ?></td> |
| 3289 |
<td> |
| 3290 |
<?php |
| 3291 |
$retention_days = isset( $config['log_retention_days'] ) ? absint( $config['log_retention_days'] ) : 14; |
| 3292 |
/* translators: %d: number of days */ |
| 3293 |
echo esc_html( sprintf( _n( '%d day', '%d days', $retention_days, 'wpvulnerability' ), $retention_days ) ); |
| 3294 |
?> |
| 3295 |
</td> |
| 3296 |
</tr> |
| 3297 |
<tr> |
| 3298 |
<td style="font-weight: 600;"><?php esc_html_e( 'Components Analyzed', 'wpvulnerability' ); ?></td> |
| 3299 |
<td> |
| 3300 |
<?php |
| 3301 |
$components = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mysql', 'mariadb', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' ); |
| 3302 |
$analyzed_count = 0; |
| 3303 |
foreach ( $components as $component ) { |
| 3304 |
if ( wpvulnerability_analyze_filter( $component ) ) { |
| 3305 |
++$analyzed_count; |
| 3306 |
} |
| 3307 |
} |
| 3308 |
echo esc_html( sprintf( '%d / %d', $analyzed_count, count( $components ) ) ); |
| 3309 |
?> |
| 3310 |
</td> |
| 3311 |
</tr> |
| 3312 |
<tr> |
| 3313 |
<td style="font-weight: 600;"><?php esc_html_e( 'Notification Email', 'wpvulnerability' ); ?></td> |
| 3314 |
<td><?php echo isset( $config['emails'] ) ? esc_html( $config['emails'] ) : '—'; ?></td> |
| 3315 |
</tr> |
| 3316 |
<tr> |
| 3317 |
<td style="font-weight: 600;"><?php esc_html_e( 'Notification Frequency', 'wpvulnerability' ); ?></td> |
| 3318 |
<td> |
| 3319 |
<?php |
| 3320 |
$period = isset( $config['period'] ) ? $config['period'] : 'weekly'; |
| 3321 |
echo esc_html( ucfirst( $period ) ); |
| 3322 |
if ( 'weekly' === $period && isset( $config['day'] ) ) { |
| 3323 |
echo ' (' . esc_html( ucfirst( $config['day'] ) ) . ')'; |
| 3324 |
} |
| 3325 |
if ( isset( $config['hour'] ) && isset( $config['minute'] ) ) { |
| 3326 |
echo ' ' . esc_html( sprintf( '%02d:%02d', absint( $config['hour'] ), absint( $config['minute'] ) ) ); |
| 3327 |
} |
| 3328 |
?> |
| 3329 |
</td> |
| 3330 |
</tr> |
| 3331 |
<tr> |
| 3332 |
<td style="font-weight: 600;"><?php esc_html_e( 'Slack Webhook', 'wpvulnerability' ); ?></td> |
| 3333 |
<td> |
| 3334 |
<?php |
| 3335 |
$slack_configured = ! empty( $config['slack_webhook'] ); |
| 3336 |
$slack_enabled = isset( $config['notify']['slack'] ) && 'y' === $config['notify']['slack']; |
| 3337 |
?> |
| 3338 |
<span style="color: <?php echo ( $slack_configured && $slack_enabled ) ? '#00a32a' : '#646970'; ?>;"> |
| 3339 |
<?php |
| 3340 |
if ( $slack_configured && $slack_enabled ) { |
| 3341 |
esc_html_e( 'Configured & Enabled', 'wpvulnerability' ); |
| 3342 |
} elseif ( $slack_configured ) { |
| 3343 |
esc_html_e( 'Configured (Disabled)', 'wpvulnerability' ); |
| 3344 |
} else { |
| 3345 |
esc_html_e( 'Not configured', 'wpvulnerability' ); |
| 3346 |
} |
| 3347 |
?> |
| 3348 |
</span> |
| 3349 |
</td> |
| 3350 |
</tr> |
| 3351 |
<tr> |
| 3352 |
<td style="font-weight: 600;"><?php esc_html_e( 'Teams Webhook', 'wpvulnerability' ); ?></td> |
| 3353 |
<td> |
| 3354 |
<?php |
| 3355 |
$teams_configured = ! empty( $config['teams_webhook'] ); |
| 3356 |
$teams_enabled = isset( $config['notify']['teams'] ) && 'y' === $config['notify']['teams']; |
| 3357 |
?> |
| 3358 |
<span style="color: <?php echo ( $teams_configured && $teams_enabled ) ? '#00a32a' : '#646970'; ?>;"> |
| 3359 |
<?php |
| 3360 |
if ( $teams_configured && $teams_enabled ) { |
| 3361 |
esc_html_e( 'Configured & Enabled', 'wpvulnerability' ); |
| 3362 |
} elseif ( $teams_configured ) { |
| 3363 |
esc_html_e( 'Configured (Disabled)', 'wpvulnerability' ); |
| 3364 |
} else { |
| 3365 |
esc_html_e( 'Not configured', 'wpvulnerability' ); |
| 3366 |
} |
| 3367 |
?> |
| 3368 |
</span> |
| 3369 |
</td> |
| 3370 |
</tr> |
| 3371 |
<tr> |
| 3372 |
<td style="font-weight: 600;"><?php esc_html_e( 'Discord Webhook', 'wpvulnerability' ); ?></td> |
| 3373 |
<td> |
| 3374 |
<?php |
| 3375 |
$discord_configured = ! empty( $config['discord_webhook'] ); |
| 3376 |
$discord_enabled = isset( $config['notify']['discord'] ) && 'y' === $config['notify']['discord']; |
| 3377 |
?> |
| 3378 |
<span style="color: <?php echo ( $discord_configured && $discord_enabled ) ? '#00a32a' : '#646970'; ?>;"> |
| 3379 |
<?php |
| 3380 |
if ( $discord_configured && $discord_enabled ) { |
| 3381 |
esc_html_e( 'Configured & Enabled', 'wpvulnerability' ); |
| 3382 |
} elseif ( $discord_configured ) { |
| 3383 |
esc_html_e( 'Configured (Disabled)', 'wpvulnerability' ); |
| 3384 |
} else { |
| 3385 |
esc_html_e( 'Not configured', 'wpvulnerability' ); |
| 3386 |
} |
| 3387 |
?> |
| 3388 |
</span> |
| 3389 |
</td> |
| 3390 |
</tr> |
| 3391 |
<tr> |
| 3392 |
<td style="font-weight: 600;"><?php esc_html_e( 'Telegram Bot', 'wpvulnerability' ); ?></td> |
| 3393 |
<td> |
| 3394 |
<?php |
| 3395 |
$telegram_configured = ! empty( $config['telegram_bot_token'] ) && ! empty( $config['telegram_chat_id'] ); |
| 3396 |
$telegram_enabled = isset( $config['notify']['telegram'] ) && 'y' === $config['notify']['telegram']; |
| 3397 |
?> |
| 3398 |
<span style="color: <?php echo ( $telegram_configured && $telegram_enabled ) ? '#00a32a' : '#646970'; ?>;"> |
| 3399 |
<?php |
| 3400 |
if ( $telegram_configured && $telegram_enabled ) { |
| 3401 |
esc_html_e( 'Configured & Enabled', 'wpvulnerability' ); |
| 3402 |
} elseif ( $telegram_configured ) { |
| 3403 |
esc_html_e( 'Configured (Disabled)', 'wpvulnerability' ); |
| 3404 |
} else { |
| 3405 |
esc_html_e( 'Not configured', 'wpvulnerability' ); |
| 3406 |
} |
| 3407 |
?> |
| 3408 |
</span> |
| 3409 |
</td> |
| 3410 |
</tr> |
| 3411 |
</tbody> |
| 3412 |
</table> |
| 3413 |
</div> |
| 3414 |
<?php |
| 3415 |
} |
| 3416 |
|
| 3417 |
/** |
| 3418 |
* Renders Section 5: Cron Status. |
| 3419 |
* |
| 3420 |
* @since 4.3.0 |
| 3421 |
* |
| 3422 |
* @return void |
| 3423 |
*/ |
| 3424 |
function wpvulnerability_render_debug_section_cron() { |
| 3425 |
$cron_status = wpvulnerability_debug_get_cron_status(); |
| 3426 |
$can_manage = current_user_can( 'manage_options' ); |
| 3427 |
?> |
| 3428 |
<div class="wpvulnerability-subsection" style="margin-top: 30px;"> |
| 3429 |
<h3><?php esc_html_e( 'Cron Status', 'wpvulnerability' ); ?></h3> |
| 3430 |
<table class="widefat" style="margin-top: 10px;"> |
| 3431 |
<tbody> |
| 3432 |
<tr> |
| 3433 |
<td style="width: 250px; font-weight: 600;"><?php esc_html_e( 'Update Database', 'wpvulnerability' ); ?></td> |
| 3434 |
<td> |
| 3435 |
<?php if ( $cron_status['update_database']['scheduled'] ) : ?> |
| 3436 |
<?php |
| 3437 |
/* translators: %s: date and time */ |
| 3438 |
echo esc_html( sprintf( __( 'Next run: %s', 'wpvulnerability' ), wp_date( 'Y-m-d H:i:s', $cron_status['update_database']['next_run'] ) ) ); |
| 3439 |
?> |
| 3440 |
<?php else : ?> |
| 3441 |
<span style="color: #d63638;"><?php esc_html_e( 'Not scheduled', 'wpvulnerability' ); ?></span> |
| 3442 |
<?php endif; ?> |
| 3443 |
</td> |
| 3444 |
</tr> |
| 3445 |
<tr> |
| 3446 |
<td style="font-weight: 600;"><?php esc_html_e( 'Send Notification', 'wpvulnerability' ); ?></td> |
| 3447 |
<td> |
| 3448 |
<?php if ( $cron_status['send_notification']['scheduled'] ) : ?> |
| 3449 |
<?php |
| 3450 |
/* translators: %s: date and time */ |
| 3451 |
echo esc_html( sprintf( __( 'Next run: %s', 'wpvulnerability' ), wp_date( 'Y-m-d H:i:s', $cron_status['send_notification']['next_run'] ) ) ); |
| 3452 |
?> |
| 3453 |
<?php else : ?> |
| 3454 |
<span style="color: #646970;"><?php esc_html_e( 'Not scheduled', 'wpvulnerability' ); ?></span> |
| 3455 |
<?php endif; ?> |
| 3456 |
</td> |
| 3457 |
</tr> |
| 3458 |
</tbody> |
| 3459 |
</table> |
| 3460 |
|
| 3461 |
<?php if ( $can_manage ) : ?> |
| 3462 |
<div style="margin-top: 15px;"> |
| 3463 |
<form method="post" style="display: inline-block; margin-right: 10px;"> |
| 3464 |
<?php wp_nonce_field( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ); ?> |
| 3465 |
<input type="hidden" name="wpvulnerability_run_update" value="1"> |
| 3466 |
<button type="submit" class="button button-secondary"> |
| 3467 |
<?php esc_html_e( 'Run Update Now', 'wpvulnerability' ); ?> |
| 3468 |
</button> |
| 3469 |
</form> |
| 3470 |
|
| 3471 |
<form method="post" style="display: inline-block;"> |
| 3472 |
<?php wp_nonce_field( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ); ?> |
| 3473 |
<input type="hidden" name="wpvulnerability_run_notification" value="1"> |
| 3474 |
<button type="submit" class="button button-secondary"> |
| 3475 |
<?php esc_html_e( 'Run Notification Now', 'wpvulnerability' ); ?> |
| 3476 |
</button> |
| 3477 |
</form> |
| 3478 |
</div> |
| 3479 |
<?php else : ?> |
| 3480 |
<p style="color: #d63638; margin-top: 10px;"> |
| 3481 |
<?php esc_html_e( 'You do not have permission to run these actions.', 'wpvulnerability' ); ?> |
| 3482 |
</p> |
| 3483 |
<?php endif; ?> |
| 3484 |
</div> |
| 3485 |
<?php |
| 3486 |
} |
| 3487 |
|
| 3488 |
/** |
| 3489 |
* Renders Section 3: API Testing. |
| 3490 |
* |
| 3491 |
* @since 4.3.0 |
| 3492 |
* |
| 3493 |
* @return void |
| 3494 |
*/ |
| 3495 |
function wpvulnerability_render_debug_section_api_testing() { |
| 3496 |
$can_manage = current_user_can( 'manage_options' ); |
| 3497 |
$components = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mysql', 'mariadb', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' ); |
| 3498 |
?> |
| 3499 |
<div class="wpvulnerability-subsection" style="margin-top: 30px;"> |
| 3500 |
<h3><?php esc_html_e( 'API Testing', 'wpvulnerability' ); ?></h3> |
| 3501 |
|
| 3502 |
<?php if ( $can_manage ) : ?> |
| 3503 |
<p><?php esc_html_e( 'Test API connectivity for each component. Click a button to send a test request.', 'wpvulnerability' ); ?></p> |
| 3504 |
|
| 3505 |
<div id="wpvulnerability-api-test-buttons" style="margin-top: 15px;"> |
| 3506 |
<?php foreach ( $components as $component ) : ?> |
| 3507 |
<button type="button" class="button button-secondary wpvulnerability-test-api-btn" data-component="<?php echo esc_attr( $component ); ?>" style="margin: 5px;"> |
| 3508 |
<?php |
| 3509 |
/* translators: %s: component name */ |
| 3510 |
echo esc_html( sprintf( __( 'Test %s', 'wpvulnerability' ), ucfirst( $component ) ) ); |
| 3511 |
?> |
| 3512 |
</button> |
| 3513 |
<?php endforeach; ?> |
| 3514 |
</div> |
| 3515 |
|
| 3516 |
<div id="wpvulnerability-api-test-results" style="margin-top: 20px;"></div> |
| 3517 |
|
| 3518 |
<script type="text/javascript"> |
| 3519 |
jQuery(document).ready(function($) { |
| 3520 |
$('.wpvulnerability-test-api-btn').on('click', function() { |
| 3521 |
var $btn = $(this); |
| 3522 |
var component = $btn.data('component'); |
| 3523 |
var $results = $('#wpvulnerability-api-test-results'); |
| 3524 |
|
| 3525 |
$btn.prop('disabled', true).text('<?php echo esc_js( __( 'Testing...', 'wpvulnerability' ) ); ?>'); |
| 3526 |
|
| 3527 |
$.ajax({ |
| 3528 |
url: ajaxurl, |
| 3529 |
type: 'POST', |
| 3530 |
data: { |
| 3531 |
action: 'wpvulnerability_test_api', |
| 3532 |
component: component, |
| 3533 |
nonce: '<?php echo esc_js( wp_create_nonce( 'wpvulnerability_test_api' ) ); ?>' |
| 3534 |
}, |
| 3535 |
success: function(response) { |
| 3536 |
if (response.success) { |
| 3537 |
var result = response.data; |
| 3538 |
var statusColor = result.success ? '#00a32a' : '#d63638'; |
| 3539 |
var resultHtml = '<div style="border: 1px solid ' + statusColor + '; padding: 15px; margin-top: 10px; border-radius: 4px;">'; |
| 3540 |
resultHtml += '<h4 style="margin-top: 0; color: ' + statusColor + ';">' + component.toUpperCase() + ' - ' + result.message + '</h4>'; |
| 3541 |
resultHtml += '<p><strong><?php echo esc_js( __( 'HTTP Code:', 'wpvulnerability' ) ); ?></strong> ' + result.http_code + '</p>'; |
| 3542 |
resultHtml += '<p><strong><?php echo esc_js( __( 'Response Time:', 'wpvulnerability' ) ); ?></strong> ' + result.response_time + ' ms</p>'; |
| 3543 |
if (result.data_preview) { |
| 3544 |
resultHtml += '<details style="margin-top: 10px;"><summary style="cursor: pointer; font-weight: 600;"><?php echo esc_js( __( 'Response Preview', 'wpvulnerability' ) ); ?></summary>'; |
| 3545 |
resultHtml += '<pre style="background: #f0f0f0; padding: 10px; overflow-x: auto; margin-top: 10px;">' + result.data_preview + '</pre>'; |
| 3546 |
resultHtml += '</details>'; |
| 3547 |
} |
| 3548 |
resultHtml += '</div>'; |
| 3549 |
$results.prepend(resultHtml); |
| 3550 |
} |
| 3551 |
$btn.prop('disabled', false).text('<?php echo esc_js( __( 'Test', 'wpvulnerability' ) ); ?> ' + component.charAt(0).toUpperCase() + component.slice(1)); |
| 3552 |
}, |
| 3553 |
error: function() { |
| 3554 |
$results.prepend('<div style="border: 1px solid #d63638; padding: 15px; margin-top: 10px; border-radius: 4px; color: #d63638;"><strong><?php echo esc_js( __( 'Error:', 'wpvulnerability' ) ); ?></strong> <?php echo esc_js( __( 'AJAX request failed.', 'wpvulnerability' ) ); ?></div>'); |
| 3555 |
$btn.prop('disabled', false).text('<?php echo esc_js( __( 'Test', 'wpvulnerability' ) ); ?> ' + component.charAt(0).toUpperCase() + component.slice(1)); |
| 3556 |
} |
| 3557 |
}); |
| 3558 |
}); |
| 3559 |
}); |
| 3560 |
</script> |
| 3561 |
<?php else : ?> |
| 3562 |
<p style="color: #d63638;"> |
| 3563 |
<?php esc_html_e( 'You do not have permission to test API connectivity.', 'wpvulnerability' ); ?> |
| 3564 |
</p> |
| 3565 |
<?php endif; ?> |
| 3566 |
</div> |
| 3567 |
<?php |
| 3568 |
} |
| 3569 |
|
| 3570 |
/** |
| 3571 |
* Renders Section 6: Database Options Viewer. |
| 3572 |
* |
| 3573 |
* @since 4.3.0 |
| 3574 |
* |
| 3575 |
* @return void |
| 3576 |
*/ |
| 3577 |
function wpvulnerability_render_debug_section_database_options() { |
| 3578 |
$option_names = wpvulnerability_debug_get_option_names(); |
| 3579 |
$selected_option = filter_input( INPUT_GET, 'debug_option', FILTER_SANITIZE_SPECIAL_CHARS ); |
| 3580 |
$selected_option = $selected_option ? sanitize_key( $selected_option ) : ''; |
| 3581 |
$page_value = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_SPECIAL_CHARS ); |
| 3582 |
?> |
| 3583 |
<div class="wpvulnerability-subsection" style="margin-top: 30px;"> |
| 3584 |
<h3><?php esc_html_e( 'Database Options Viewer', 'wpvulnerability' ); ?></h3> |
| 3585 |
<p><?php esc_html_e( 'View the raw data stored in WordPress options.', 'wpvulnerability' ); ?></p> |
| 3586 |
|
| 3587 |
<form method="get" style="margin-top: 15px;"> |
| 3588 |
<input type="hidden" name="page" value="<?php echo $page_value ? esc_attr( $page_value ) : ''; ?>"> |
| 3589 |
<input type="hidden" name="tab" value="debug"> |
| 3590 |
<select name="debug_option" style="min-width: 300px;"> |
| 3591 |
<option value=""><?php esc_html_e( 'Select an option...', 'wpvulnerability' ); ?></option> |
| 3592 |
<?php foreach ( $option_names as $option ) : ?> |
| 3593 |
<option value="<?php echo esc_attr( $option ); ?>" <?php selected( $selected_option, $option ); ?>> |
| 3594 |
<?php echo esc_html( $option ); ?> |
| 3595 |
</option> |
| 3596 |
<?php endforeach; ?> |
| 3597 |
</select> |
| 3598 |
<button type="submit" class="button button-secondary"><?php esc_html_e( 'View', 'wpvulnerability' ); ?></button> |
| 3599 |
</form> |
| 3600 |
|
| 3601 |
<?php if ( $selected_option && in_array( $selected_option, $option_names, true ) ) : ?> |
| 3602 |
<?php |
| 3603 |
$option_value = wpvulnerability_debug_get_option_value( $selected_option ); |
| 3604 |
?> |
| 3605 |
<div style="margin-top: 20px;"> |
| 3606 |
<h4><?php echo esc_html( $selected_option ); ?></h4> |
| 3607 |
<?php if ( null !== $option_value ) : ?> |
| 3608 |
<pre style="background: #f0f0f0; padding: 15px; overflow-x: auto; border: 1px solid #ddd; border-radius: 4px;"><?php echo esc_html( wp_json_encode( $option_value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) ); ?></pre> |
| 3609 |
<?php else : ?> |
| 3610 |
<p style="color: #646970;"><?php esc_html_e( 'Option not found or empty.', 'wpvulnerability' ); ?></p> |
| 3611 |
<?php endif; ?> |
| 3612 |
</div> |
| 3613 |
<?php endif; ?> |
| 3614 |
</div> |
| 3615 |
<?php |
| 3616 |
} |
| 3617 |
/** |
| 3618 |
* Renders Section 7: Quick Actions. |
| 3619 |
* |
| 3620 |
* @since 4.3.0 |
| 3621 |
* |
| 3622 |
* @return void |
| 3623 |
*/ |
| 3624 |
function wpvulnerability_render_debug_section_quick_actions() { |
| 3625 |
$can_manage = current_user_can( 'manage_options' ); |
| 3626 |
?> |
| 3627 |
<div class="wpvulnerability-subsection" style="margin-top: 30px;"> |
| 3628 |
<h3><?php esc_html_e( 'Quick Actions', 'wpvulnerability' ); ?></h3> |
| 3629 |
<p><?php esc_html_e( 'Perform debugging actions. Use with caution.', 'wpvulnerability' ); ?></p> |
| 3630 |
|
| 3631 |
<?php if ( $can_manage ) : ?> |
| 3632 |
<div style="margin-top: 15px;"> |
| 3633 |
<form method="post" style="display: inline-block; margin-right: 10px;" onsubmit="return confirm('<?php echo esc_js( __( 'Are you sure you want to clear all caches?', 'wpvulnerability' ) ); ?>');"> |
| 3634 |
<?php wp_nonce_field( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ); ?> |
| 3635 |
<input type="hidden" name="wpvulnerability_debug_clear_caches" value="1"> |
| 3636 |
<button type="submit" class="button button-secondary"> |
| 3637 |
<?php esc_html_e( 'Clear All Caches', 'wpvulnerability' ); ?> |
| 3638 |
</button> |
| 3639 |
</form> |
| 3640 |
|
| 3641 |
<form method="post" style="display: inline-block; margin-right: 10px;" onsubmit="return confirm('<?php echo esc_js( __( 'Are you sure you want to reset signatures?', 'wpvulnerability' ) ); ?>');"> |
| 3642 |
<?php wp_nonce_field( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ); ?> |
| 3643 |
<input type="hidden" name="wpvulnerability_debug_reset_signatures" value="1"> |
| 3644 |
<button type="submit" class="button button-secondary"> |
| 3645 |
<?php esc_html_e( 'Reset Signatures', 'wpvulnerability' ); ?> |
| 3646 |
</button> |
| 3647 |
</form> |
| 3648 |
|
| 3649 |
<form method="post" style="display: inline-block;"> |
| 3650 |
<?php wp_nonce_field( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ); ?> |
| 3651 |
<input type="hidden" name="wpvulnerability_debug_export" value="1"> |
| 3652 |
<button type="submit" class="button button-primary"> |
| 3653 |
<?php esc_html_e( 'Export Debug Info', 'wpvulnerability' ); ?> |
| 3654 |
</button> |
| 3655 |
</form> |
| 3656 |
</div> |
| 3657 |
<?php else : ?> |
| 3658 |
<p style="color: #d63638;"> |
| 3659 |
<?php esc_html_e( 'You do not have permission to perform these actions.', 'wpvulnerability' ); ?> |
| 3660 |
</p> |
| 3661 |
<?php endif; ?> |
| 3662 |
</div> |
| 3663 |
<?php |
| 3664 |
} |
| 3665 |
|