via wp_head (priority 0, antes de CriticalCSSService) * - Cachear contenido para evitar lecturas repetidas * * FLUJO: * 1. wp_head (priority 0) → render() * 2. Lee Assets/css/critical-bootstrap.css * 3. Output: * * IMPORTANTE: * - Este servicio se ejecuta ANTES de CriticalCSSService (priority 0 vs 1) * - Bootstrap completo se carga diferido (media="print" + onload) * * @package ROITheme\Shared\Infrastructure\Services */ final class CriticalBootstrapService { /** * Instancia singleton */ private static ?self $instance = null; /** * Cache del contenido CSS */ private ?string $cssCache = null; /** * Ruta al archivo CSS crítico */ private string $cssFilePath; /** * Constructor privado (singleton) */ private function __construct() { $this->cssFilePath = get_template_directory() . '/Assets/Css/critical-bootstrap.css'; } /** * Obtiene la instancia singleton * * @return self */ public static function getInstance(): self { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Renderiza Critical Bootstrap CSS en wp_head * * Este método se llama desde wp_head con priority 0 (muy temprano). * Inyecta el subset de Bootstrap antes del CSS de componentes. * * @return void */ public function render(): void { $css = $this->getCriticalCSS(); if (empty($css)) { return; } // Minificar CSS removiendo comentarios y espacios innecesarios $minifiedCSS = $this->minifyCSS($css); printf( '' . "\n", $minifiedCSS ); } /** * Obtiene el contenido del CSS crítico * * @return string CSS crítico o string vacío si no existe */ private function getCriticalCSS(): string { // Usar cache si existe if ($this->cssCache !== null) { return $this->cssCache; } // Verificar que el archivo existe if (!file_exists($this->cssFilePath)) { error_log('ROI Theme: Critical Bootstrap CSS file not found: ' . $this->cssFilePath); $this->cssCache = ''; return ''; } // Leer contenido $content = file_get_contents($this->cssFilePath); if ($content === false) { error_log('ROI Theme: Failed to read Critical Bootstrap CSS'); $this->cssCache = ''; return ''; } $this->cssCache = $content; return $content; } /** * Minifica CSS removiendo comentarios y espacios innecesarios * * @param string $css CSS a minificar * @return string CSS minificado */ private function minifyCSS(string $css): string { // Remover comentarios $css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css); // Remover espacios, tabs y newlines $css = str_replace(["\r\n", "\r", "\n", "\t"], '', $css); // Remover espacios múltiples $css = preg_replace('/\s+/', ' ', $css); // Remover espacios alrededor de caracteres especiales $css = preg_replace('/\s*([{}:;,>+~])\s*/', '$1', $css); // Remover último punto y coma antes de } $css = str_replace(';}', '}', $css); return trim($css); } }