load_dependencies(); $this->init_hooks(); } /** * Load required files */ private function load_dependencies(): void { require_once ROI_APU_SEARCH_PLUGIN_DIR . 'includes/class-db-connection.php'; require_once ROI_APU_SEARCH_PLUGIN_DIR . 'includes/class-redis-cache.php'; require_once ROI_APU_SEARCH_PLUGIN_DIR . 'includes/class-search-engine.php'; require_once ROI_APU_SEARCH_PLUGIN_DIR . 'includes/class-shortcode.php'; require_once ROI_APU_SEARCH_PLUGIN_DIR . 'includes/class-analytics.php'; // Admin dashboard if (is_admin()) { require_once ROI_APU_SEARCH_PLUGIN_DIR . 'admin/class-metrics-repository.php'; require_once ROI_APU_SEARCH_PLUGIN_DIR . 'admin/class-analytics-dashboard.php'; } } /** * Initialize WordPress hooks */ private function init_hooks(): void { // Register shortcode add_action('init', [$this, 'register_shortcode']); // Enqueue assets add_action('wp_enqueue_scripts', [$this, 'enqueue_assets']); // AJAX handlers (for non-SHORTINIT fallback) add_action('wp_ajax_roi_apu_search', [$this, 'handle_ajax_search']); add_action('wp_ajax_nopriv_roi_apu_search', [$this, 'handle_ajax_search']); // Initialize admin dashboard if (is_admin()) { ROI_APU_Analytics_Dashboard::get_instance()->init(); } } /** * Register the shortcode */ public function register_shortcode(): void { $shortcode = new ROI_APU_Search_Shortcode(); add_shortcode('roi_apu_search', [$shortcode, 'render']); } /** * Enqueue frontend assets */ public function enqueue_assets(): void { // Only load if shortcode is used global $post; if (!$post || !has_shortcode($post->post_content, 'roi_apu_search')) { return; } wp_enqueue_style( 'roi-apu-search', ROI_APU_SEARCH_PLUGIN_URL . 'assets/css/search-ui.css', [], ROI_APU_SEARCH_VERSION ); wp_enqueue_script( 'roi-apu-search', ROI_APU_SEARCH_PLUGIN_URL . 'assets/js/search-handler.js', [], ROI_APU_SEARCH_VERSION, true ); // Obtener configuracion de AdSense del tema (si existe) // Verifica que la funcion exista para evitar errores si se usa otro tema $adsConfig = function_exists('roi_get_adsense_search_config') ? roi_get_adsense_search_config() : ['enabled' => false]; // Localize script with AJAX URL, nonce, click tracking URL, and ads config wp_localize_script('roi-apu-search', 'roiApuSearch', [ 'ajaxUrl' => admin_url('admin-ajax.php'), 'apiUrl' => ROI_APU_SEARCH_PLUGIN_URL . 'api/search-endpoint.php', 'clickUrl' => ROI_APU_SEARCH_PLUGIN_URL . 'api/click-endpoint.php', 'nonce' => wp_create_nonce('roi_apu_search'), 'ads' => $adsConfig, ]); } /** * Handle AJAX search request (fallback if SHORTINIT doesn't work) */ public function handle_ajax_search(): void { // Verify nonce if (!check_ajax_referer('roi_apu_search', 'nonce', false)) { wp_send_json_error(['message' => 'Invalid security token'], 403); } // Store raw term before sanitization $term_raw = isset($_POST['term']) ? (string) wp_unslash($_POST['term']) : ''; $term = sanitize_text_field($term_raw); $page = isset($_POST['page']) ? absint($_POST['page']) : 1; $per_page = isset($_POST['per_page']) ? absint($_POST['per_page']) : 10; $categories = isset($_POST['categories']) ? sanitize_text_field(wp_unslash($_POST['categories'])) : ''; // Validate term $min_len = 3; $max_len = 250; if (mb_strlen($term, 'UTF-8') < $min_len) { wp_send_json_error(['message' => "Minimo {$min_len} caracteres"], 400); } if (mb_strlen($term, 'UTF-8') > $max_len) { $term = mb_substr($term, 0, $max_len, 'UTF-8'); } // Execute search try { $db = ROI_APU_Search_DB::get_instance(); $pdo = $db->get_pdo(); $prefix = $db->get_prefix(); $search = new ROI_APU_Search_Engine($pdo); // Parse categories $category_ids = []; if (!empty($categories)) { $category_ids = $this->parse_categories($categories); } $offset = ($page - 1) * $per_page; $results = $search->run($term, $per_page, $offset, $category_ids); // Build permalinks for each result (search engine returns empty permalink) $site_url = rtrim(home_url(), '/'); $permalink_structure = get_option('permalink_structure', '/%postname%/'); foreach ($results['rows'] as &$row) { if (empty($row['permalink'])) { $postName = $row['post_name'] ?? ''; if (empty($postName)) { $row['permalink'] = $site_url . '/?p=' . $row['ID']; continue; } // Build according to permalink structure if (strpos($permalink_structure, '%post_id%') !== false) { $row['permalink'] = $site_url . '/' . $row['ID'] . '/'; } else { $row['permalink'] = $site_url . '/' . $postName . '/'; } } } unset($row); // Log search for analytics $analytics_cfg = ROI_APU_Search_Analytics::get_config(); $search_id = ROI_APU_Search_Analytics::logSearch( $pdo, $prefix, $analytics_cfg, $term_raw, $term, $results, $page, $per_page ); // Add search_id to response for click tracking $results['search_id'] = $search_id; wp_send_json_success($results); } catch (\Exception $e) { wp_send_json_error(['message' => 'Error en la busqueda'], 500); } } /** * Parse categories string to array of IDs */ private function parse_categories(string $categories): array { $parts = array_filter(array_map('trim', explode(',', $categories))); $ids = []; foreach ($parts as $part) { if (is_numeric($part)) { $ids[] = (int) $part; } else { // Try to get category by slug $term = get_term_by('slug', $part, 'category'); if ($term) { $ids[] = (int) $term->term_id; } } } return array_unique($ids); } } // Initialize plugin add_action('plugins_loaded', function () { ROI_APU_Search_Plugin::get_instance(); }); // Activation hook register_activation_hook(__FILE__, function () { // Check PHP version if (version_compare(PHP_VERSION, '8.0', '<')) { deactivate_plugins(plugin_basename(__FILE__)); wp_die('ROI APU Search requiere PHP 8.0 o superior.'); } // Flush rewrite rules flush_rewrite_rules(); }); // Deactivation hook register_deactivation_hook(__FILE__, function () { flush_rewrite_rules(); });