. * Esto permite diferir el bootstrap-subset.min.css sin causar CLS. * * @since 1.0.21 * @updated 1.0.23 - Bootstrap diferido gracias a critical-bootstrap.css */ define('ROI_DEFERRED_CSS', [ // Critical CSS inline - estos archivos se difieren 'roi-fonts', // @font-face inline en critical-bootstrap.css 'roi-bootstrap', // Critical inline via CriticalBootstrapService 'roi-variables', // Variables ahora inline en critical CSS // Componentes específicos (below the fold) 'roi-badges', 'roi-pagination', 'roi-generic-tables', 'roi-video', 'roi-animations', 'roi-youtube-facade', 'roi-tables-apu', // CSS globales no críticos 'roi-utilities', 'roi-accessibility', 'roi-responsive', 'bootstrap-icons', ]); /** * Add async loading to deferred stylesheets (Fase 4.2 PageSpeed) * * Converts media="print" to media="all" after load to prevent render-blocking. * * @since 1.0.21 * @param string $html The link tag HTML. * @param string $handle The stylesheet handle. * @return string Modified link tag. */ function roi_add_deferred_css_onload($html, $handle) { if (!in_array($handle, ROI_DEFERRED_CSS, true)) { return $html; } // Add onload attribute to switch media to "all" after load $html = str_replace( "media='print'", "media='print' onload=\"this.media='all'\"", $html ); // Add noscript fallback for users without JavaScript $href = preg_match('/href=[\'"]([^\'"]+)[\'"]/', $html, $matches) ? $matches[1] : ''; if ($href) { $html .= '' . "\n"; } return $html; } add_filter('style_loader_tag', 'roi_add_deferred_css_onload', 10, 2); /** * Enqueue typography system * * SELF-HOSTED: Fuentes Poppins ahora se cargan desde Assets/fonts/ * Eliminada dependencia de Google Fonts para: * - Mejorar rendimiento (sin requests externos) * - Cumplimiento GDPR (sin tracking de Google) * - Evitar bloqueo de renderizado * * NOTA: @font-face críticos están inline en critical-bootstrap.css * Este archivo ahora es DIFERIDO (solo utilidades de texto) */ function roi_enqueue_fonts() { // Fonts CSS local - DIFERIDO (critical @font-face inline) wp_enqueue_style( 'roi-fonts', get_template_directory_uri() . '/Assets/Css/css-global-fonts.css', array(), '1.1.1', // Bump version: deferred loading 'print' // DIFERIDO - @font-face inline en critical CSS ); } add_action('wp_enqueue_scripts', 'roi_enqueue_fonts', 1); /** * Enqueue Bootstrap 5 styles and scripts * * OPTIMIZACIÓN LCP (PageSpeed Fase 5): * - Usa bootstrap-subset.min.css (145KB) en lugar de bootstrap.min.css (227KB) * - Reducción: 36% menos CSS para parsear * - Generado con PurgeCSS: node build-bootstrap-subset.js * * NOTA: Bootstrap AHORA es DIFERIDO (media='print' + onload). * CriticalBootstrapService inyecta inline las clases críticas: * - Grid system (row, col-*) * - Navbar component * - Flexbox utilities * - Spacing utilities * Esto evita CLS mientras mejora LCP significativamente. */ function roi_enqueue_bootstrap() { // Bootstrap CSS SUBSET - DIFERIDO (critical CSS es inline) // Original: 227KB -> Subset: 145KB (36% reducción) // Critical: ~20KB inline en via CriticalBootstrapService wp_enqueue_style( 'roi-bootstrap', get_template_directory_uri() . '/Assets/Vendor/Bootstrap/Css/bootstrap-subset.min.css', array('roi-fonts'), '5.3.2-subset', 'print' // DIFERIDO - critical CSS inline evita CLS ); // Bootstrap Icons CSS - SUBSET OPTIMIZADO (Fase 4.1 PageSpeed) // Original: 211 KB (2050 iconos) -> Subset: 13 KB (104 iconos) = 94% reduccion // DIFERIDO: Fase 4.3 - no crítico para renderizado inicial wp_enqueue_style( 'bootstrap-icons', get_template_directory_uri() . '/Assets/Vendor/bootstrap-icons-subset.min.css', array('roi-bootstrap'), ROI_VERSION, 'print' ); // Variables CSS del Template RDash - DIFERIDO // Variables críticas inline en critical-bootstrap.css wp_enqueue_style( 'roi-variables', get_template_directory_uri() . '/Assets/Css/css-global-variables.css', array('roi-bootstrap'), ROI_VERSION, 'print' // DIFERIDO - variables críticas inline ); // Bootstrap JS Bundle - in footer with defer wp_enqueue_script( 'roi-bootstrap-js', get_template_directory_uri() . '/Assets/Vendor/Bootstrap/Js/bootstrap.bundle.min.js', array(), '5.3.2', array( 'in_footer' => true, 'strategy' => 'defer', ) ); // Dequeue jQuery if it was enqueued wp_dequeue_script('jquery'); wp_deregister_script('jquery'); } add_action('wp_enqueue_scripts', 'roi_enqueue_bootstrap', 5); /** * Enqueue main theme stylesheet * FASE 1 - Este es el archivo CSS principal del tema * * OPTIMIZACIÓN PageSpeed: Diferido con media='print' + onload * Los estilos críticos ya están en critical-bootstrap.css (inline en ) * @see Shared/Infrastructure/Services/CriticalBootstrapService.php */ function roi_enqueue_main_stylesheet() { wp_enqueue_style( 'roi-main-style', get_template_directory_uri() . '/Assets/Css/style.min.css', array('roi-variables'), '1.0.9', // Minificado + Diferido - estilos no críticos del tema 'print' // Diferido: no bloquea renderizado ); } add_action('wp_enqueue_scripts', 'roi_enqueue_main_stylesheet', 5); /** * Agregar onload para cambiar media de 'print' a 'all' en style.css * * Esto permite que el CSS se cargue de forma asíncrona sin bloquear * el renderizado inicial, mejorando LCP y FCP. * * @param string $html El tag link del estilo encolado. * @param string $handle El handle registrado del estilo. * @return string Tag link modificado */ function roi_defer_main_style( $html, $handle ) { if ( 'roi-main-style' !== $handle ) { return $html; } // Agregar onload para cambiar media a 'all' después de cargar $html = str_replace( "media='print'", "media='print' onload=\"this.media='all'\"", $html ); // Agregar fallback noscript para navegadores sin JS $html .= ''; return $html; } add_filter( 'style_loader_tag', 'roi_defer_main_style', 10, 2 ); /** * Enqueue FASE 2 CSS - Template RDash Component Styles (Issues #58-64) * * Estilos que replican componentes del template RDash * * NOTA: Hero Section, Post Content y Related Posts ahora usan * estilos generados dinámicamente desde sus Renderers. */ function roi_enqueue_fase2_styles() { // Hero Section CSS - DESHABILITADO: estilos generados por HeroRenderer // @see Public/Hero/Infrastructure/Ui/HeroRenderer.php // Category Badges CSS - Clase genérica (Issue #62) // DIFERIDO: Fase 4.2 PageSpeed - media='print' + onload wp_enqueue_style( 'roi-badges', get_template_directory_uri() . '/Assets/Css/css-global-badges.css', array('roi-bootstrap'), filemtime(get_template_directory() . '/Assets/Css/css-global-badges.css'), 'print' // Diferido para no bloquear renderizado ); // Pagination CSS - Estilos personalizados (Issue #64) // DIFERIDO: Fase 4.2 PageSpeed - below the fold wp_enqueue_style( 'roi-pagination', get_template_directory_uri() . '/Assets/Css/css-global-pagination.css', array('roi-bootstrap'), filemtime(get_template_directory() . '/Assets/Css/css-global-pagination.css'), 'print' // Diferido para no bloquear renderizado ); // Post Content Typography y Related Posts - DESHABILITADOS // Los estilos ahora están integrados en style.css o generados dinámicamente } add_action('wp_enqueue_scripts', 'roi_enqueue_fase2_styles', 6); /** * Enqueue Global Components CSS * * ARQUITECTURA: Componentes globales que aparecen en todas las páginas * Issue #121 - Separación de componentes del style.css * * @since 1.0.7 */ function roi_enqueue_global_components() { // Notification Bar CSS - DESHABILITADO: Los estilos de la barra de notificación ahora se generan // dinámicamente desde el TopNotificationBarRenderer basado en los valores de la BD. // @see Public/TopNotificationBar/Infrastructure/Ui/TopNotificationBarRenderer.php /* wp_enqueue_style( 'roi-notification-bar', get_template_directory_uri() . '/Assets/Css/componente-top-bar.css', array('roi-bootstrap'), filemtime(get_template_directory() . '/Assets/Css/componente-top-bar.css'), 'all' ); */ // Navbar CSS - DESHABILITADO: Los estilos del navbar ahora se generan // dinámicamente desde el NavbarRenderer basado en los valores de la BD. // El archivo componente-navbar.css tenía !important que sobrescribía // los estilos configurados por el usuario en el Admin Panel. // @see Public/Navbar/Infrastructure/Ui/NavbarRenderer.php /* wp_enqueue_style( 'roi-navbar', get_template_directory_uri() . '/Assets/Css/componente-navbar.css', array('roi-bootstrap'), filemtime(get_template_directory() . '/Assets/Css/componente-navbar.css'), 'all' ); */ // Buttons CSS - DESHABILITADO: Los estilos del botón Let's Talk ahora se generan // dinámicamente desde el CtaLetsTalkRenderer basado en los valores de la BD. // El archivo componente-boton-lets-talk.css tenía !important que sobrescribía // los estilos configurados por el usuario en el Admin Panel. // @see Public/CtaLetsTalk/Infrastructure/Ui/CtaLetsTalkRenderer.php /* wp_enqueue_style( 'roi-buttons', get_template_directory_uri() . '/Assets/Css/componente-boton-lets-talk.css', array('roi-bootstrap'), filemtime(get_template_directory() . '/Assets/Css/componente-boton-lets-talk.css'), 'all' ); */ } add_action('wp_enqueue_scripts', 'roi_enqueue_global_components', 7); /** * Enqueue header scripts * * NOTA: CSS del header se genera dinámicamente desde NavbarRenderer * @see Public/Navbar/Infrastructure/Ui/NavbarRenderer.php * * DESHABILITADO: header.js (2025-11-27 - Optimización TBT Fase 2.3) * Motivo: ~90% código muerto. Los elementos que busca no existen: * - mobile-menu-toggle: no existe (sitio usa .navbar-toggler de Bootstrap) * - mobile-menu: no existe (usa Bootstrap collapse) * - masthead: no existe * - Smooth scroll duplicado de main.js * Reducción: ~343 líneas de JS eliminadas del parsing */ // function roi_enqueue_header() { // wp_enqueue_script( // 'roi-header-js', // get_template_directory_uri() . '/Assets/Js/header.js', // array(), // '1.0.0', // array( // 'in_footer' => true, // 'strategy' => 'defer', // ) // ); // } // add_action('wp_enqueue_scripts', 'roi_enqueue_header', 10); /** * Enqueue generic tables styles * * ARQUITECTURA: Estilos para tablas genéricas en post-content * Solo en posts individuales */ function roi_enqueue_generic_tables() { // Only enqueue on single posts if (!is_single()) { return; } // ELIMINADO: Generic Tables CSS // Motivo: Migrado a CustomCSSManager (TIPO 3: CSS Crítico Personalizado) // Los estilos ahora se inyectan dinámicamente desde la BD via CustomCSSInjector // Fecha: 2025-12-01 // @see Admin/CustomCSSManager/ - Sistema de gestión de CSS personalizado // @see Public/CustomCSSManager/Infrastructure/Services/CustomCSSInjector.php // wp_enqueue_style( // 'roi-generic-tables', // get_template_directory_uri() . '/Assets/Css/css-global-generic-tables.css', // array('roi-bootstrap'), // ROI_VERSION, // 'print' // ); } add_action('wp_enqueue_scripts', 'roi_enqueue_generic_tables', 11); /** * Enqueue video iframe styles * * ARQUITECTURA: Estilos para videos embebidos (YouTube, Vimeo) * Solo en posts individuales */ function roi_enqueue_video_styles() { // Only enqueue on single posts if (!is_single()) { return; } // Video CSS // DIFERIDO: Fase 4.2 PageSpeed - below the fold wp_enqueue_style( 'roi-video', get_template_directory_uri() . '/Assets/Css/css-global-video.css', array('roi-bootstrap'), ROI_VERSION, 'print' // Diferido para no bloquear renderizado ); } add_action('wp_enqueue_scripts', 'roi_enqueue_video_styles', 11); /** * Enqueue main JavaScript * * ELIMINADO: custom-style.css (Issue #131) * Motivo: Archivo contenía 95% código duplicado de style.css y otros componentes * Código único movido a: generic-tables.css, video.css */ function roi_enqueue_main_javascript() { // Main JavaScript - navbar scroll effects // OPTIMIZACIÓN TBT Fase 2.3: Eliminado ~300 líneas de código muerto // Solo mantiene: navbar scroll effect (agrega clase 'scrolled') wp_enqueue_script( 'roi-main-js', get_template_directory_uri() . '/Assets/Js/main.js', array('roi-bootstrap-js'), '1.0.5', // TBT Fase 2.3: eliminado código muerto (~315 → ~25 líneas) array( 'in_footer' => true, 'strategy' => 'defer', ) ); } add_action('wp_enqueue_scripts', 'roi_enqueue_main_javascript', 11); // ELIMINADO: roi_remove_defer_from_main_js // Motivo: wp_localize_script ya no se usa, main.js ahora puede usar defer // Fecha: 2025-11-27 - Optimización TBT Fase 2 /** * ELIMINADO: roi_enqueue_footer_styles * Motivo: footer.css NO está documentado - CSS debe estar en style.css * Ver: theme-documentation/16-componente-footer-contact-form/CSS-ESPECIFICO.md */ /** * Enqueue accessibility styles and scripts */ function roi_enqueue_accessibility() { // Accessibility CSS // DIFERIDO: Fase 4.3 - no crítico para renderizado inicial wp_enqueue_style( 'roi-accessibility', get_template_directory_uri() . '/Assets/Css/css-global-accessibility.min.css', array('roi-main-style'), ROI_VERSION, 'print' ); // Accessibility JavaScript wp_enqueue_script( 'roi-accessibility-js', get_template_directory_uri() . '/Assets/Js/accessibility.js', array('roi-bootstrap-js'), ROI_VERSION, array( 'in_footer' => true, 'strategy' => 'defer', ) ); } add_action('wp_enqueue_scripts', 'roi_enqueue_accessibility', 15); /** * Enqueue del script de carga retrasada de AdSense * * Este script se encarga de detectar la primera interacción del usuario * (scroll, click, touch, etc.) y cargar los scripts de AdSense solo * en ese momento, mejorando significativamente el rendimiento inicial. */ function roi_enqueue_adsense_loader() { // Solo ejecutar en frontend if (is_admin()) { return; } // Verificar si el retardo de AdSense está habilitado (Clean Architecture) $is_enabled = roi_get_component_setting('adsense-delay', 'visibility', 'is_enabled', true); if (!$is_enabled) { return; } // Enqueue del script de carga de AdSense wp_enqueue_script( 'roi-adsense-loader', get_template_directory_uri() . '/Assets/Js/adsense-loader.js', array(), ROI_VERSION, array( 'in_footer' => true, 'strategy' => 'defer', ) ); } add_action('wp_enqueue_scripts', 'roi_enqueue_adsense_loader', 10); /** * Enqueue theme core styles * * ELIMINADO: theme.css (Issue #125) * Motivo: theme.css contenía código experimental y sobrescrituras Bootstrap no documentadas * Resultado: 638 líneas eliminadas - TODO el CSS documentado va en style.css * Fecha: 2025-01-07 */ function roi_enqueue_theme_styles() { // Theme Core Styles - ELIMINADO theme.css // wp_enqueue_style( // 'roi-theme', // get_template_directory_uri() . '/Assets/Css/theme.css', // array('roi-bootstrap'), // '1.0.0', // 'all' // ); // Theme Animations // DIFERIDO: Fase 4.2 PageSpeed - mejoras visuales no críticas wp_enqueue_style( 'roi-animations', get_template_directory_uri() . '/Assets/Css/css-global-animations.css', array('roi-bootstrap'), '1.0.0', 'print' // Diferido para no bloquear renderizado ); // Theme Responsive Styles // DIFERIDO: Fase 4.3 - media queries no críticas para primer paint wp_enqueue_style( 'roi-responsive', get_template_directory_uri() . '/Assets/Css/css-global-responsive.css', array('roi-bootstrap'), '1.1.0', 'print' ); // Theme Utilities // DIFERIDO: Fase 4.3 - clases utilitarias no críticas wp_enqueue_style( 'roi-utilities', get_template_directory_uri() . '/Assets/Css/css-global-utilities.css', array('roi-bootstrap'), '1.0.0', 'print' ); // Print Styles wp_enqueue_style( 'roi-print', get_template_directory_uri() . '/Assets/Css/css-global-print.css', array(), '1.0.0', 'print' ); } add_action('wp_enqueue_scripts', 'roi_enqueue_theme_styles', 13); /** * Enqueue social share styles * * DESHABILITADO: Los estilos de Social Share ahora se generan * dinámicamente desde SocialShareRenderer basado en valores de BD. * @see Public/SocialShare/Infrastructure/Ui/SocialShareRenderer.php */ // function roi_enqueue_social_share_styles() - REMOVED /** * Enqueue APU Tables styles - ASYNC LOADING * * OPTIMIZACIÓN: Los estilos críticos de tablas APU (anchos de columna, filas especiales) * están en critical-bootstrap.css que se inyecta inline en via CriticalBootstrapService. * * Este CSS completo carga de forma ASYNC para no bloquear el renderizado: * - media="print" evita bloqueo inicial * - onload="this.media='all'" aplica estilos cuando termina de cargar * * @see Assets/Css/critical-bootstrap.css - CSS crítico inline * @see Shared/Infrastructure/Services/CriticalBootstrapService.php */ // ELIMINADO: roi_enqueue_apu_tables_styles y roi_async_apu_tables_css_tag // Motivo: Migrado a CustomCSSManager (TIPO 3: CSS Crítico Personalizado) // Los estilos de tablas APU ahora se inyectan dinámicamente desde la BD // via CustomCSSInjector en wp_footer con id="roi-custom-deferred-css" // Fecha: 2025-12-01 // @see Admin/CustomCSSManager/ - Sistema de gestión de CSS personalizado // @see Public/CustomCSSManager/Infrastructure/Services/CustomCSSInjector.php // function roi_enqueue_apu_tables_styles() { // wp_enqueue_style( // 'roi-tables-apu', // get_template_directory_uri() . '/Assets/Css/css-tablas-apu.css', // array('roi-bootstrap'), // ROI_VERSION, // 'print' // ); // } // add_action('wp_enqueue_scripts', 'roi_enqueue_apu_tables_styles', 5); // function roi_async_apu_tables_css_tag($tag, $handle) { // if ($handle === 'roi-tables-apu') { // $tag = str_replace( // "media='print'", // "media='print' onload=\"this.media='all'\"", // $tag // ); // $noscript_url = get_template_directory_uri() . '/Assets/Css/css-tablas-apu.css?ver=' . ROI_VERSION; // $tag .= ''; // } // return $tag; // } // add_filter('style_loader_tag', 'roi_async_apu_tables_css_tag', 10, 2); /** * Enqueue APU Tables auto-class JavaScript * * DESHABILITADO: Este script causaba CLS de 0.692 en Lab Data. * La manipulación del DOM con JS después de DOMContentLoaded causa Layout Shift. * * La lógica ha sido movida a PHP server-side en Inc/apu-tables.php * @see roi_add_apu_row_classes() * * Issue #132 - Original implementation */ // function roi_enqueue_apu_tables_autoclass_script() { // // APU Tables Auto-Class JS // wp_enqueue_script( // 'roi-apu-tables-autoclass', // get_template_directory_uri() . '/Assets/Js/apu-tables-auto-class.js', // array(), // ROI_VERSION, // array( // 'in_footer' => true, // 'strategy' => 'defer', // ) // ); // } // add_action('wp_enqueue_scripts', 'roi_enqueue_apu_tables_autoclass_script', 15); // DISABLED: Moved to server-side PHP to prevent CLS /** * Enqueue CTA Box Sidebar styles (Issue #36) * * DESHABILITADO: Los estilos del CTA Box Sidebar ahora se generan * dinámicamente desde CtaBoxSidebarRenderer basado en valores de BD. * @see Public/CtaBoxSidebar/Infrastructure/Ui/CtaBoxSidebarRenderer.php */ // function roi_enqueue_cta_box_sidebar_assets() - REMOVED /** * Enqueue TOC Sidebar styles (only on single posts) * * DESHABILITADO: Los estilos del TOC ahora se generan * dinámicamente desde TableOfContentsRenderer basado en valores de BD. * @see Public/TableOfContents/Infrastructure/Ui/TableOfContentsRenderer.php * * @since 1.0.5 */ // function roi_enqueue_toc_sidebar_assets() - REMOVED /** * Enqueue Footer Contact Form styles * * DESHABILITADO: Los estilos del Contact Form ahora se generan * dinámicamente desde ContactFormRenderer basado en valores de BD. * @see Public/ContactForm/Infrastructure/Ui/ContactFormRenderer.php */ // function roi_enqueue_footer_contact_assets() - REMOVED