connect(); } /** * Establish PDO connection with persistent connection enabled */ private function connect(): void { if ($this->pdo !== null) { return; } // Get WordPress database credentials $host = DB_HOST; $name = DB_NAME; $user = DB_USER; $pass = DB_PASSWORD; $charset = defined('DB_CHARSET') ? DB_CHARSET : 'utf8mb4'; // Handle port in host $port = 3306; if (strpos($host, ':') !== false) { [$host, $port] = explode(':', $host); $port = (int) $port; } $dsn = "mysql:host={$host};port={$port};dbname={$name};charset={$charset}"; $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => true, // Same as original buscar-apus (enables reusing :q placeholder) PDO::ATTR_PERSISTENT => true, // Enable persistent connections ]; try { $this->pdo = new PDO($dsn, $user, $pass, $options); // Set MySQL specific options (same as original buscar-apus) $this->pdo->exec("SET NAMES {$charset} COLLATE {$charset}_unicode_ci"); } catch (PDOException $e) { // Log error but don't expose details error_log('ROI APU Search DB Error: ' . $e->getMessage()); throw new RuntimeException('Database connection failed'); } } /** * Get the PDO instance */ public function get_pdo(): PDO { if ($this->pdo === null) { $this->connect(); } return $this->pdo; } /** * Get WordPress table prefix */ public function get_prefix(): string { global $table_prefix; return $table_prefix ?? 'wp_'; } /** * Prevent cloning */ private function __clone() { } /** * Prevent unserialization */ public function __wakeup() { throw new RuntimeException('Cannot unserialize singleton'); } }