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 '';
}
}
}
/**
* 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')]);
}
}