- Created Assets/css/critical-bootstrap.css (~10KB subset) Contains only Bootstrap classes used in above-the-fold components: container, navbar, flexbox, dropdown, spacing utilities - Created CriticalBootstrapService (singleton) Injects minified critical Bootstrap in <head> at priority 0 Output: <style id="roi-critical-bootstrap">...</style> - Modified enqueue-scripts.php Bootstrap now loads with media="print" + onload="this.media='all'" Full 31KB Bootstrap loads async, doesn't block rendering - Updated CriticalCSSHooksRegistrar Now registers both CriticalBootstrapService (priority 0) and CriticalCSSService (priority 1) Flow: 1. wp_head (priority 0) → Critical Bootstrap (~10KB inline) 2. wp_head (priority 1) → Critical Component CSS (~4KB inline) 3. Bootstrap full (31KB) loads deferred, non-blocking Expected PageSpeed improvement: ~400-600ms LCP reduction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
149 lines
3.8 KiB
PHP
149 lines
3.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Shared\Infrastructure\Services;
|
|
|
|
/**
|
|
* CriticalBootstrapService
|
|
*
|
|
* Inyecta CSS crítico de Bootstrap en wp_head para evitar
|
|
* bloqueo de renderizado por el Bootstrap completo.
|
|
*
|
|
* RESPONSABILIDAD:
|
|
* - Leer critical-bootstrap.css (subset de Bootstrap)
|
|
* - Inyectar en <head> 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: <style id="roi-critical-bootstrap">...</style>
|
|
*
|
|
* 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(
|
|
'<style id="roi-critical-bootstrap">%s</style>' . "\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);
|
|
}
|
|
}
|