options_repository = $options_repository; $this->nonce_service = $nonce_service; $this->capabilities_service = $capabilities_service; $this->logger = $logger; } /** * Initialize settings page. */ public function init(): void { add_action('admin_menu', [$this, 'add_admin_menu']); add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']); add_action('admin_post_adsd_update_general', [$this, 'handle_update_general']); add_action('admin_post_adsd_reset_rules', [$this, 'handle_reset_rules']); add_action('wp_ajax_adsd_update_rule', [$this, 'handle_ajax_update_rule']); add_action('wp_ajax_adsd_delete_rule', [$this, 'handle_ajax_delete_rule']); add_action('wp_ajax_adsd_toggle_rule', [$this, 'handle_ajax_toggle_rule']); add_action('wp_ajax_adsd_get_latest_log', [$this, 'handle_get_latest_log']); add_action('wp_ajax_adsd_download_latest_log', [$this, 'handle_download_latest_log']); add_action('wp_ajax_adsd_clear_all_logs', [$this, 'handle_clear_all_logs']); add_action('wp_ajax_adsd_log_js_message', [$this, 'handle_log_js_message']); } /** * Add admin menu item. */ public function add_admin_menu(): void { add_options_page( __('AdsDestroyer', 'ads-destroyer'), __('AdsDestroyer', 'ads-destroyer'), 'manage_options', $this->menu_slug, [$this, 'render_settings_page'] ); } /** * Enqueue admin scripts and styles for settings page. */ public function enqueue_admin_assets(): void { // Only load on our settings page $screen = get_current_screen(); if (!$screen || $screen->id !== 'settings_page_' . $this->menu_slug) { return; } // Enqueue admin settings CSS wp_enqueue_style( 'adsd-admin-settings-style', plugin_dir_url(\ADSD_PLUGIN_FILE) . 'build/css/admin-settings-style.min.css', [], ADSD_PLUGIN_VERSION ); // Enqueue admin settings JavaScript wp_enqueue_script( 'adsd-admin-settings', plugin_dir_url(\ADSD_PLUGIN_FILE) . 'build/js/admin-settings.js', ['jquery'], ADSD_PLUGIN_VERSION, true ); // Localize script with AJAX URL wp_localize_script('adsd-admin-settings', 'adsd_ajax', [ 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('adsd_update_rule_ajax'), ]); } /** * Render settings page. */ public function render_settings_page(): void { if (!current_user_can('manage_options')) { wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'ads-destroyer')); } $opts = $this->options_repository->get_all(); // Sanitize tab parameter with allowed values $allowed_tabs = ['rules', 'settings', 'logs']; $active_tab = sanitize_text_field($_GET['tab'] ?? 'rules'); if (!in_array($active_tab, $allowed_tabs, true)) { $active_tab = 'rules'; } ?>

render_admin_notices(); ?> render_rules_tab(); ?> render_settings_tab(); ?> render_logs_tab(); ?>

' . esc_html__('All rules have been reset successfully.', 'ads-destroyer') . '

'; } ?>

render_rules_table(); ?> render_instructions(); ?>
options_repository->get_all(); // Show success message if settings were updated if (isset($_GET['updated']) && $_GET['updated'] === '1') { echo '

' . esc_html__('Settings saved successfully.', 'ads-destroyer') . '

'; } ?>

options_repository->get_all(); // Update UI settings $opts['ui']['show_admin_bar_button'] = !empty($_POST['show_admin_bar_button']); // Update access settings $opts['access']['roles_allowed'] = array_map('sanitize_text_field', $_POST['roles_allowed'] ?? ['administrator']); // Update logging settings $opts['logging']['enabled'] = !empty($_POST['logging_enabled']); $opts['logging']['levels'] = array_map('sanitize_text_field', $_POST['log_levels'] ?? ['error']); $this->options_repository->save_all($opts); // Update logger settings if ($this->logger) { if ($opts['logging']['enabled']) { $this->logger->enable(); $this->logger->set_log_levels($opts['logging']['levels']); } else { $this->logger->disable(); } } // Add admin notice add_action('admin_notices', function() { echo '

' . esc_html__('Settings saved successfully.', 'ads-destroyer') . '

'; }); wp_redirect(add_query_arg(['updated' => '1'], admin_url('admin.php?page=ads-destroyer&tab=settings'))); exit; } /** * Handle get latest log AJAX request. */ public function handle_get_latest_log(): void { if (!wp_verify_nonce($_POST['_wpnonce'] ?? '', 'adsd_get_latest_log')) { wp_die(__('Security check failed', 'ads-destroyer')); } $latest_file = $this->logger->get_latest_log_file(); if ($latest_file) { $content = $this->logger->read_log_file($latest_file, 1000); echo $content; } else { echo __('No log files found.', 'ads-destroyer'); } wp_die(); } /** * Handle download latest log AJAX request. */ public function handle_download_latest_log(): void { if (!wp_verify_nonce($_POST['_wpnonce'] ?? '', 'adsd_download_latest_log')) { wp_die(__('Security check failed', 'ads-destroyer')); } $latest_file = $this->logger->get_latest_log_file(); if ($latest_file && file_exists($latest_file)) { $content = file_get_contents($latest_file); header('Content-Type: text/plain'); header('Content-Disposition: attachment; filename="ads-destroyer-latest.log"'); header('Content-Length: ' . strlen($content)); echo $content; } else { wp_die(__('No log files found.', 'ads-destroyer')); } exit; } /** * Handle clear all logs AJAX request. */ public function handle_clear_all_logs(): void { if (!wp_verify_nonce($_POST['_wpnonce'] ?? '', 'adsd_clear_all_logs')) { wp_send_json_error(__('Security check failed', 'ads-destroyer')); } $deleted_count = $this->logger->clear_all_logs(); wp_send_json_success([ 'count' => $deleted_count, 'message' => sprintf(__('Cleared %d log files.', 'ads-destroyer'), $deleted_count) ]); } /** * Handle JavaScript log message AJAX request. */ public function handle_log_js_message(): void { if (!wp_verify_nonce($_POST['_wpnonce'] ?? '', 'adsd_log_js_message')) { wp_die(__('Security check failed', 'ads-destroyer')); } $log_entry_json = $_POST['log_entry'] ?? ''; $log_entry = json_decode($log_entry_json, true); if (!$log_entry) { wp_die(__('Invalid log entry', 'ads-destroyer')); } // Log the JavaScript message using PHP logger $message = sprintf('[JS] %s', $log_entry['message']); $context = array_merge($log_entry['context'] ?? [], [ 'source' => 'javascript', 'user_agent' => $log_entry['userAgent'] ?? '', 'url' => $log_entry['url'] ?? '' ]); $this->logger->log($log_entry['level'], $message, $context); wp_die(); } /** * Render admin notices. */ private function render_admin_notices(): void { $notice_code = isset($_GET['adsd_notice']) ? sanitize_key((string) $_GET['adsd_notice']) : ''; $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : ''; if ($notice_code && $nonce && wp_verify_nonce($nonce, 'adsd_notice_' . $notice_code)) { $messages = [ 'general_ok' => __('Settings saved.', 'ads-destroyer'), 'logging_ok' => __('Settings saved.', 'ads-destroyer'), 'reset_ok' => __('All rules have been reset.', 'ads-destroyer'), 'delete_ok' => __('Rule deleted.', 'ads-destroyer'), 'update_ok' => __('Rule updated.', 'ads-destroyer'), 'toggle_ok' => __('Rule status updated.', 'ads-destroyer'), ]; $msg = $messages[$notice_code] ?? ''; if ($msg) { echo '

' . esc_html($msg) . '

'; } } } /** * Render rules table using WP_List_Table. */ private function render_rules_table(): void { $rules_table = new RulesListTable($this->options_repository); $rules_table->display(); // Add modal for editing rules $this->render_edit_modal(); } /** * Render modal for editing rules. */ private function render_edit_modal(): void { ?> options_repository->get_all(); $opts['rules'] = []; $this->options_repository->save_all($opts); if ($this->logger) { $this->logger->info('All rules reset by user: ' . wp_get_current_user()->user_login); } wp_redirect(add_query_arg(['updated' => '1'], admin_url('admin.php?page=ads-destroyer&tab=rules'))); exit; } /** * Handle AJAX update rule. */ public function handle_ajax_update_rule(): void { if (!$this->nonce_service->verify_nonce($_POST['nonce'] ?? '', 'adsd_update_rule_ajax')) { wp_die(__('Security check failed', 'ads-destroyer')); } if (!$this->capabilities_service->can_access_settings()) { wp_die(__('Insufficient permissions', 'ads-destroyer')); } $rule_id = sanitize_text_field($_POST['rule_id'] ?? ''); $xpath = sanitize_text_field($_POST['xpath'] ?? ''); $page_info = sanitize_text_field($_POST['page_info'] ?? ''); $enabled = isset($_POST['enabled']); if (empty($rule_id) || empty($xpath)) { wp_send_json_error(['message' => __('Invalid data', 'ads-destroyer')]); } $opts = $this->options_repository->get_all(); $rules = $opts['rules'] ?? []; foreach ($rules as &$rule) { if (($rule['id'] ?? '') === $rule_id) { $rule['xpath'] = $xpath; $rule['page_info'] = $page_info; $rule['enabled'] = $enabled; break; } } $opts['rules'] = $rules; $this->options_repository->save_all($opts); $this->logger->info('Rule updated by user: ' . wp_get_current_user()->user_login . ' - Rule ID: ' . $rule_id); wp_send_json_success(['message' => __('Rule updated successfully', 'ads-destroyer')]); } /** * Handle AJAX delete rule. */ public function handle_ajax_delete_rule(): void { if (!$this->nonce_service->verify_nonce($_POST['nonce'] ?? '', 'adsd_update_rule_ajax')) { wp_die(__('Security check failed', 'ads-destroyer')); } if (!$this->capabilities_service->can_access_settings()) { wp_die(__('Insufficient permissions', 'ads-destroyer')); } $rule_id = sanitize_text_field($_POST['rule_id'] ?? ''); if (empty($rule_id)) { wp_send_json_error(['message' => __('Invalid rule ID', 'ads-destroyer')]); } $opts = $this->options_repository->get_all(); $rules = $opts['rules'] ?? []; $rules = array_filter($rules, function($rule) use ($rule_id) { return ($rule['id'] ?? '') !== $rule_id; }); $opts['rules'] = array_values($rules); $this->options_repository->save_all($opts); $this->logger->info('Rule deleted by user: ' . wp_get_current_user()->user_login . ' - Rule ID: ' . $rule_id); wp_send_json_success(['message' => __('Rule deleted successfully', 'ads-destroyer')]); } /** * Handle AJAX toggle rule. */ public function handle_ajax_toggle_rule(): void { if (!$this->nonce_service->verify_nonce($_POST['nonce'] ?? '', 'adsd_update_rule_ajax')) { wp_die(__('Security check failed', 'ads-destroyer')); } if (!$this->capabilities_service->can_access_settings()) { wp_die(__('Insufficient permissions', 'ads-destroyer')); } $rule_id = sanitize_text_field($_POST['rule_id'] ?? ''); $enabled = filter_var($_POST['enabled'] ?? false, FILTER_VALIDATE_BOOLEAN); if (empty($rule_id)) { wp_send_json_error(['message' => __('Invalid rule ID', 'ads-destroyer')]); } $opts = $this->options_repository->get_all(); $rules = $opts['rules'] ?? []; foreach ($rules as &$rule) { if (($rule['id'] ?? '') === $rule_id) { $rule['enabled'] = $enabled; break; } } $opts['rules'] = $rules; $this->options_repository->save_all($opts); $this->logger->info('Rule toggled by user: ' . wp_get_current_user()->user_login . ' - Rule ID: ' . $rule_id . ' - Enabled: ' . ($enabled ? 'true' : 'false')); wp_send_json_success(['message' => __('Rule status updated', 'ads-destroyer')]); } }