options_repository = $options_repository; $this->nonce_service = $nonce_service; $this->capabilities_service = $capabilities_service; $this->logger = $logger; } /** * Initialize selection mode functionality. */ public function init(): void { add_action('wp_ajax_adsd_toggle_selection_mode', [$this, 'handle_toggle_selection_mode']); add_action('wp_ajax_adsd_save_element_rule', [$this, 'handle_save_element_rule']); add_action('wp_ajax_adsd_test_xpath', [$this, 'handle_test_xpath']); // Initialize session if not already started if (session_status() === PHP_SESSION_NONE) { session_start(); } } /** * Handle AJAX request to toggle selection mode. */ public function handle_toggle_selection_mode(): void { // Verify nonce if (!$this->nonce_service->verify_nonce($_POST['nonce'] ?? '', 'adsd_selection_mode')) { wp_die('Security check failed'); } // Check capabilities if (!$this->capabilities_service->can_access_selection_mode()) { wp_die('Insufficient permissions'); } $enable = filter_var($_POST['enable'] ?? false, FILTER_VALIDATE_BOOLEAN); if ($enable) { $_SESSION['adsd_selection_mode'] = true; $this->logger->info('Selection mode enabled by user: ' . wp_get_current_user()->user_login); } else { unset($_SESSION['adsd_selection_mode']); $this->logger->info('Selection mode disabled by user: ' . wp_get_current_user()->user_login); } wp_send_json_success([ 'enabled' => $enable, 'message' => $enable ? __('Selection mode enabled', 'ads-destroyer') : __('Selection mode disabled', 'ads-destroyer'), ]); } /** * Handle AJAX request to save element rule. */ public function handle_save_element_rule(): void { // Verify nonce if (!$this->nonce_service->verify_nonce($_POST['nonce'] ?? '', 'adsd_selection_mode')) { wp_die('Security check failed'); } // Check capabilities if (!$this->capabilities_service->can_access_selection_mode()) { wp_die('Insufficient permissions'); } $xpath = sanitize_text_field($_POST['xpath'] ?? ''); $description = sanitize_text_field($_POST['description'] ?? ''); if (empty($xpath)) { wp_send_json_error(['message' => __('XPath is required', 'ads-destroyer')]); } // Get existing rules $rules = $this->options_repository->get_option('rules', []); // Add new rule $new_rule = [ 'id' => uniqid('rule_'), 'xpath' => $xpath, 'description' => $description ?: sprintf(__('Rule for %s', 'ads-destroyer'), $xpath), 'enabled' => true, 'created_at' => current_time('mysql'), 'created_by' => wp_get_current_user()->user_login, ]; $rules[] = $new_rule; // Save rules $this->options_repository->set_option('rules', $rules); $this->logger->info('New rule created by user: ' . wp_get_current_user()->user_login . ' - XPath: ' . $xpath); wp_send_json_success([ 'rule' => $new_rule, 'message' => __('Rule saved successfully', 'ads-destroyer'), ]); } /** * Handle AJAX request to test XPath. */ public function handle_test_xpath(): void { // Verify nonce if (!$this->nonce_service->verify_nonce($_POST['nonce'] ?? '', 'adsd_selection_mode')) { wp_die('Security check failed'); } // Check capabilities if (!$this->capabilities_service->can_access_selection_mode()) { wp_die('Insufficient permissions'); } $xpath = sanitize_text_field($_POST['xpath'] ?? ''); if (empty($xpath)) { wp_send_json_error(['message' => __('XPath is required', 'ads-destroyer')]); } // Test XPath by applying it to current page content $test_result = $this->test_xpath_on_current_page($xpath); wp_send_json_success([ 'valid' => $test_result['valid'], 'matches' => $test_result['matches'], 'message' => $test_result['message'], ]); } /** * Test XPath on current page content. * * @param string $xpath * @return array */ private function test_xpath_on_current_page(string $xpath): array { try { // Get current page content with sanitized URL $current_uri = sanitize_text_field($_SERVER['REQUEST_URI'] ?? ''); $url = home_url($current_uri); $response = wp_remote_get($url); if (is_wp_error($response)) { return [ 'valid' => false, 'matches' => 0, 'message' => __('Could not fetch page content for testing', 'ads-destroyer'), ]; } $html = wp_remote_retrieve_body($response); // Create DOMDocument $dom = new \DOMDocument(); libxml_use_internal_errors(true); $dom->loadHTML('' . $html); libxml_clear_errors(); // Create XPath $xpath_obj = new \DOMXPath($dom); $nodes = $xpath_obj->query($xpath); if ($nodes === false) { return [ 'valid' => false, 'matches' => 0, 'message' => __('Invalid XPath expression', 'ads-destroyer'), ]; } $matches = $nodes->length; return [ 'valid' => true, 'matches' => $matches, 'message' => sprintf( _n( 'XPath is valid and matches %d element', 'XPath is valid and matches %d elements', $matches, 'ads-destroyer' ), $matches ), ]; } catch (\Exception $e) { return [ 'valid' => false, 'matches' => 0, 'message' => sprintf(__('Error testing XPath: %s', 'ads-destroyer'), $e->getMessage()), ]; } } }