Files
FrankZamora e01605ec37 feat(critical-css): implementar TIPO 4 y TIPO 5 - CSS Below-the-fold y Lazy Loading
## TIPO 4: CSS Below-the-fold (Critical Variables + Responsive)
- Inyecta variables CSS críticas inline en wp_head P:-1
- Inyecta media queries críticas inline en wp_head P:2 (corregido de P:1)
- Auto-regeneración cuando archivos fuente cambian (filemtime check)
- Cache en Assets/CriticalCSS/ para evitar lecturas repetidas
- Comando WP-CLI: wp roi-theme generate-critical-css

Archivos TIPO 4:
- Public/CriticalCSS/Domain/Contracts/ - Interfaces (DIP)
- Public/CriticalCSS/Application/UseCases/GetCriticalCSSUseCase.php
- Public/CriticalCSS/Infrastructure/Cache/CriticalCSSFileCache.php
- Public/CriticalCSS/Infrastructure/Services/CriticalCSSExtractor.php
- Public/CriticalCSS/Infrastructure/Services/CriticalCSSInjector.php
- bin/generate-critical-css.php

## TIPO 5: CSS No Crítico (Lazy Loading)
- Animaciones CSS: carga 2s después de page load via requestIdleCallback
- Print CSS: carga solo al imprimir via beforeprint event
- Fallback <noscript> para usuarios sin JavaScript
- Safari fallback: setTimeout cuando requestIdleCallback no disponible

Archivos TIPO 5:
- Assets/Js/lazy-css-loader.js
- Public/LazyCSSLoader/Infrastructure/Contracts/LazyCSSRegistrarInterface.php
- Public/LazyCSSLoader/Infrastructure/Services/LazyCSSRegistrar.php

## Fix: Colisión de prioridades wp_head
Antes: TIPO 1 (P:1), TIPO 4 responsive (P:1), TIPO 3 (P:2) - CONFLICTO
Después: TIPO 1 (P:1), TIPO 4 responsive (P:2), TIPO 3 (P:3) - OK

Nuevo orden de prioridades:
P:-1 roi-critical-variables (TIPO 4)
P:0  roi-critical-bootstrap (TIPO 2)
P:1  roi-critical-css (TIPO 1)
P:2  roi-critical-responsive (TIPO 4)
P:3  roi-custom-critical-css (TIPO 3)
P:5  roi-theme-layout-css (ThemeSettings)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 23:06:12 -06:00

125 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
namespace ROITheme\Public\LazyCSSLoader\Infrastructure\Services;
use ROITheme\Public\LazyCSSLoader\Infrastructure\Contracts\LazyCSSRegistrarInterface;
/**
* Registra CSS para carga lazy (TIPO 5)
*
* Separa CSS de TIPO 2 (diferido inmediato) vs TIPO 5 (lazy loading)
*
* CSS incluidos en TIPO 5:
* - Animaciones: requestIdleCallback (2s timeout)
* - Print: beforeprint event
*
* @package ROITheme\Public\LazyCSSLoader\Infrastructure\Services
*/
final class LazyCSSRegistrar implements LazyCSSRegistrarInterface
{
/**
* CSS que se mueve de TIPO 2 a TIPO 5
*
* @var array<int, array{id: string, path: string, trigger: string, handle: string}>
*/
private const LAZY_CSS_FILES = [
[
'id' => 'animations',
'path' => '/Assets/Css/css-global-animations.css',
'trigger' => 'idle',
'handle' => 'roi-animations',
],
[
'id' => 'print',
'path' => '/Assets/Css/css-global-print.css',
'trigger' => 'print',
'handle' => 'roi-print',
],
];
/**
* Timeout en ms para requestIdleCallback
*/
private const IDLE_TIMEOUT = 2000;
/**
* Registra hooks de WordPress
*/
public function register(): void
{
// Dequeue CSS que ahora es TIPO 5
add_action('wp_enqueue_scripts', [$this, 'dequeueType5CSS'], 999);
// Agregar script loader y configuracion
add_action('wp_enqueue_scripts', [$this, 'enqueueLoader'], 20);
// Agregar fallback noscript
add_action('wp_head', [$this, 'addNoscriptFallback'], 99);
}
/**
* Remueve CSS que ahora es TIPO 5 del enqueue normal
*/
public function dequeueType5CSS(): void
{
foreach (self::LAZY_CSS_FILES as $file) {
wp_dequeue_style($file['handle']);
wp_deregister_style($file['handle']);
}
}
/**
* Encola el loader JavaScript con configuracion
*/
public function enqueueLoader(): void
{
$loaderPath = get_template_directory() . '/Assets/Js/lazy-css-loader.js';
// Solo encolar si el archivo existe
if (!file_exists($loaderPath)) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('ROI Theme TIPO 5: lazy-css-loader.js not found');
}
return;
}
wp_enqueue_script(
'roi-lazy-css-loader',
get_template_directory_uri() . '/Assets/Js/lazy-css-loader.js',
[],
ROI_VERSION,
true // En footer
);
// Pasar configuracion al JS
wp_localize_script('roi-lazy-css-loader', 'roiLazyCSSConfig', [
'baseUrl' => get_template_directory_uri(),
'version' => ROI_VERSION,
'idleTimeout' => self::IDLE_TIMEOUT,
'cssFiles' => self::LAZY_CSS_FILES,
]);
}
/**
* Agrega fallback noscript para accesibilidad
*/
public function addNoscriptFallback(): void
{
echo '<noscript>' . "\n";
foreach (self::LAZY_CSS_FILES as $file) {
$href = esc_url(get_template_directory_uri() . $file['path'] . '?ver=' . ROI_VERSION);
$media = $file['trigger'] === 'print' ? 'print' : 'all';
printf(
'<link rel="stylesheet" href="%s" media="%s">' . "\n",
$href,
$media
);
}
echo '</noscript>' . "\n";
}
}