getAjaxController(); } catch (\Throwable $e) { // Manejar errores de inicialización (no crítico, solo log) if (defined('WP_DEBUG') && WP_DEBUG) { error_log('ROI Theme: Failed to initialize DI Container: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine()); } // NO hacer return - permitir que el tema continúe funcionando $container = null; } // ============================================================================= // 3.1. INICIALIZAR PANEL DE ADMINISTRACIÓN (Clean Architecture) // ============================================================================= use ROITheme\Admin\Domain\ValueObjects\MenuItem; use ROITheme\Admin\Application\UseCases\RenderDashboardUseCase; use ROITheme\Admin\Infrastructure\Ui\AdminDashboardRenderer; use ROITheme\Admin\Infrastructure\Api\WordPress\AdminMenuRegistrar; use ROITheme\Admin\Infrastructure\Services\AdminAssetEnqueuer; try { // Obtener Use Case para cargar configuraciones $getComponentSettingsUseCase = $container?->getGetComponentSettingsUseCase(); // Crear MenuItem con configuración del panel $menuItem = new MenuItem( pageTitle: 'ROI Theme - Panel de Administración', menuTitle: 'ROI Theme', capability: 'manage_options', menuSlug: 'roi-theme-admin', icon: 'dashicons-admin-settings', position: 60 ); // Crear GroupRegistry para la nueva UI de Cards/Grupos $groupRegistry = new \ROITheme\Admin\Infrastructure\Ui\ComponentGroupRegistry(); // Crear renderer del dashboard con inyección del Use Case y GroupRegistry $dashboardRenderer = new AdminDashboardRenderer($getComponentSettingsUseCase, $groupRegistry); // Crear caso de uso para renderizar $renderDashboardUseCase = new RenderDashboardUseCase($dashboardRenderer); // Crear y registrar el menú de administración $adminMenuRegistrar = new AdminMenuRegistrar($menuItem, $renderDashboardUseCase); $adminMenuRegistrar->register(); // Crear y registrar el enqueuer de assets $adminAssetEnqueuer = new AdminAssetEnqueuer(get_template_directory_uri()); $adminAssetEnqueuer->register(); // Obtener Use Case para guardar configuraciones $saveComponentSettingsUseCase = $container?->getSaveComponentSettingsUseCase(); // === FIELD MAPPER REGISTRY (Auto-registro escalable) === $fieldMapperRegistry = new \ROITheme\Admin\Shared\Infrastructure\FieldMapping\FieldMapperRegistry(); $fieldMapperProvider = new \ROITheme\Admin\Shared\Infrastructure\FieldMapping\FieldMapperProvider($fieldMapperRegistry); $fieldMapperProvider->registerAll(); // === ADMIN AJAX HANDLER === $adminAjaxHandler = new \ROITheme\Admin\Shared\Infrastructure\Api\WordPress\AdminAjaxHandler( $saveComponentSettingsUseCase, $fieldMapperRegistry ); $adminAjaxHandler->register(); // Crear y registrar el handler AJAX para el Contact Form (público) $contactFormAjaxHandler = new \ROITheme\Public\ContactForm\Infrastructure\Api\WordPress\ContactFormAjaxHandler( $container->getComponentSettingsRepository() ); $contactFormAjaxHandler->register(); // Crear y registrar el handler AJAX para Newsletter (público) $newsletterAjaxHandler = new \ROITheme\Public\Footer\Infrastructure\Api\WordPress\NewsletterAjaxHandler( $container->getComponentSettingsRepository() ); $newsletterAjaxHandler->register(); // Crear y registrar el inyector de Theme Settings (GA, Custom CSS/JS) $themeSettingsRenderer = new \ROITheme\Public\ThemeSettings\Infrastructure\Ui\ThemeSettingsRenderer(); $themeSettingsInjector = new \ROITheme\Public\ThemeSettings\Infrastructure\Services\ThemeSettingsInjector( $container->getComponentSettingsRepository(), $themeSettingsRenderer ); $themeSettingsInjector->register(); // === YOUTUBE FACADE (PageSpeed Optimization Phase 2.4) === // Lazy-load YouTube iframes to reduce TBT by ~2000ms $youtubeFacadeRenderer = new \ROITheme\Public\YoutubeFacade\Infrastructure\Ui\YoutubeFacadeRenderer(); $youtubeFacadeFilter = new \ROITheme\Public\YoutubeFacade\Infrastructure\Services\YoutubeFacadeContentFilter( $youtubeFacadeRenderer ); $youtubeFacadeHooksRegistrar = new \ROITheme\Public\YoutubeFacade\Infrastructure\Wordpress\YoutubeFacadeHooksRegistrar( $youtubeFacadeFilter ); $youtubeFacadeHooksRegistrar->register(); // === CACHE-FIRST ARCHITECTURE (Plan 1000.01) === // Hook para plugins externos que necesitan evaluar acceso antes de servir página // @see openspec/specs/cache-first-architecture/spec.md $cacheFirstHooksRegistrar = new \ROITheme\Shared\Infrastructure\Hooks\CacheFirstHooksRegistrar(); $cacheFirstHooksRegistrar->register(); // Log en modo debug if (defined('WP_DEBUG') && WP_DEBUG) { error_log('ROI Theme: Admin Panel initialized successfully'); } } catch (\Throwable $e) { // Manejar errores de inicialización del panel if (defined('WP_DEBUG') && WP_DEBUG) { error_log('ROI Theme: Failed to initialize Admin Panel: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine()); } } // ============================================================================= // 4. CONFIGURACIÓN DEL TEMA // ============================================================================= /** * Setup del tema * * Configuraciones básicas de WordPress theme support */ add_action('after_setup_theme', function() { // Soporte para título del documento add_theme_support('title-tag'); // Soporte para imágenes destacadas add_theme_support('post-thumbnails'); // Soporte para HTML5 add_theme_support('html5', [ 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 'style', 'script' ]); // Soporte para feeds automáticos add_theme_support('automatic-feed-links'); // Registro de ubicaciones de menús register_nav_menus([ 'primary' => __('Primary Menu', 'roi-theme'), 'footer' => __('Footer Menu', 'roi-theme'), 'footer_menu_1' => __('Footer Menu 1 (Widget 1)', 'roi-theme'), 'footer_menu_2' => __('Footer Menu 2 (Widget 2)', 'roi-theme'), 'footer_menu_3' => __('Footer Menu 3 (Widget 3)', 'roi-theme'), 'footer_menu_4' => __('Footer Menu 4 (Widget 1B - Bases de datos)', 'roi-theme'), ]); // TODO: Agregar más configuraciones según sea necesario }); // ============================================================================= // 5. HOOKS DE INICIALIZACIÓN (Para fases posteriores) // ============================================================================= /** * Hook para sincronización de schemas * TODO: Implementar en Fase 6 */ // add_action('admin_init', function() use ($container) { // $syncService = $container->getSchemaSyncService(); // // Verificar si hay schemas desactualizados // }); /** * Hook para detección de schemas desactualizados * TODO: Implementar en Fase 6 */ // add_action('admin_notices', function() use ($container) { // // Mostrar aviso si hay schemas desactualizados // }); // ============================================================================= // 5. RENDERIZAR MODAL DE CONTACTO (Let's Talk) // ============================================================================= /** * Renderizar modal de contacto en el footer * Usa la misma configuracion que contact-form (mismo webhook) */ add_action('wp_footer', function() use ($container) { if ($container === null) { return; } try { // Obtener configuracion del contact-form $repository = $container->getComponentSettingsRepository(); $settings = $repository->getComponentSettings('contact-form'); if (empty($settings)) { return; } // Crear Component entity $componentName = new \ROITheme\Shared\Domain\ValueObjects\ComponentName('contact-form'); $component = new \ROITheme\Shared\Domain\Entities\Component( name: $componentName, configuration: \ROITheme\Shared\Domain\ValueObjects\ComponentConfiguration::fromArray($settings), visibility: \ROITheme\Shared\Domain\ValueObjects\ComponentVisibility::allDevices() ); // Crear renderer y renderizar modal $cssGenerator = new \ROITheme\Shared\Infrastructure\Services\CSSGeneratorService(); $renderer = new \ROITheme\Public\ContactForm\Infrastructure\Ui\ContactFormRenderer($cssGenerator); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $renderer->renderModal($component); } catch (\Throwable $e) { if (defined('WP_DEBUG') && WP_DEBUG) { error_log('ROI Theme: Failed to render contact modal: ' . $e->getMessage()); } } }, 99); // Prioridad alta para que se renderice al final del footer // ============================================================================= // 5.2. CUSTOM CSS MANAGER (TIPO 3: CSS Crítico Personalizado) // ============================================================================= /** * Bootstrap CustomCSSManager * * Inicializa el sistema de CSS personalizado configurable. * - Frontend: Inyecta CSS crítico (head) y diferido (footer) * - Admin: El FormBuilder se auto-registra cuando es instanciado por el dashboard */ // Registrar hooks de inyección CSS directamente (sin wrapper) if (!is_admin()) { try { global $wpdb; $repository = new \ROITheme\Admin\CustomCSSManager\Infrastructure\Persistence\WordPressSnippetRepository($wpdb); $getCriticalUseCase = new \ROITheme\Public\CustomCSSManager\Application\UseCases\GetCriticalSnippetsUseCase($repository); $getDeferredUseCase = new \ROITheme\Public\CustomCSSManager\Application\UseCases\GetDeferredSnippetsUseCase($repository); $injector = new \ROITheme\Public\CustomCSSManager\Infrastructure\Services\CustomCSSInjector( $getCriticalUseCase, $getDeferredUseCase ); $injector->register(); if (defined('WP_DEBUG') && WP_DEBUG) { error_log('ROI Theme: CustomCSSManager hooks registered successfully'); } } catch (\Throwable $e) { error_log('ROI Theme: CustomCSSManager FAILED: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine()); } } // ============================================================================= // 5.2.1. CUSTOM CSS MANAGER BOOTSTRAP (Handler de formulario POST) // ============================================================================= /** * Inicializar Bootstrap de CustomCSSManager para admin * * IMPORTANTE: Este Bootstrap registra el handler de formulario POST en admin_init, * ANTES de que WordPress envíe headers HTTP. Esto permite que wp_redirect() * funcione correctamente después de guardar/eliminar snippets. */ if (is_admin()) { \ROITheme\Admin\CustomCSSManager\Infrastructure\Bootstrap\CustomCSSManagerBootstrap::init(); } // ============================================================================= // 5.3. INFORMACIÓN DE DEBUG (Solo en desarrollo) // ============================================================================= if (defined('WP_DEBUG') && WP_DEBUG) { // Registrar que el tema se inicializó correctamente error_log('ROI Theme: Bootstrap completed successfully'); } // ============================================================================= // 5.4. CRITICAL CSS TIPO 4 (CSS Below-the-fold) // ============================================================================= /** * Bootstrap CriticalCSS TIPO 4 * * Inyecta CSS critico (variables, responsive) inline en wp_head * antes de cualquier otro CSS para evitar FOUC. * * Incluye auto-regeneracion: si los archivos fuente cambian, * el cache se regenera automaticamente sin intervencion manual. * Costo: ~0.1ms (2 llamadas a filemtime()) */ if (!is_admin()) { $criticalCSSCache = new \ROITheme\Public\CriticalCSS\Infrastructure\Cache\CriticalCSSFileCache(); $criticalCSSExtractor = new \ROITheme\Public\CriticalCSS\Infrastructure\Services\CriticalCSSExtractor( $criticalCSSCache ); // Auto-regenerar si archivos fuente cambiaron if ($criticalCSSExtractor->needsRegeneration()) { $criticalCSSExtractor->generateAll(); } $criticalCSSInjector = new \ROITheme\Public\CriticalCSS\Infrastructure\Services\CriticalCSSInjector( $criticalCSSCache ); $criticalCSSInjector->register(); } // Registrar comando WP-CLI (util para forzar regeneracion o limpiar cache) if (defined('WP_CLI') && WP_CLI) { require_once get_template_directory() . '/bin/generate-critical-css.php'; } // ============================================================================= // 5.5. LAZY CSS LOADER TIPO 5 (CSS No Critico) // ============================================================================= /** * Bootstrap LazyCSSLoader TIPO 5 * * Carga CSS no critico de forma lazy: * - Animaciones: requestIdleCallback o timeout 2s * - Print: solo cuando usuario va a imprimir (beforeprint event) * * @since 1.0.20 */ if (!is_admin()) { $lazyCSSRegistrar = new \ROITheme\Public\LazyCSSLoader\Infrastructure\Services\LazyCSSRegistrar(); $lazyCSSRegistrar->register(); if (defined('WP_DEBUG') && WP_DEBUG) { error_log('ROI Theme: TIPO 5 LazyCSSLoader registered'); } } // ============================================================================= // 6. INSTALACIÓN DE TABLAS DEL TEMA // ============================================================================= /** * Crear tablas del tema en la activación * * Este hook se ejecuta cuando el tema se activa en WordPress. * Crea las tablas necesarias si no existen. */ add_action('after_switch_theme', function() { global $wpdb; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); $charset_collate = $wpdb->get_charset_collate(); // Tabla de configuración de componentes (normalizada) $table_settings = $wpdb->prefix . 'roi_theme_component_settings'; $sql_settings = "CREATE TABLE {$table_settings} ( id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, component_name VARCHAR(100) NOT NULL, group_name VARCHAR(100) NOT NULL, attribute_name VARCHAR(100) NOT NULL, attribute_value LONGTEXT NOT NULL, is_editable TINYINT(1) NOT NULL DEFAULT 1, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY unique_setting (component_name, group_name, attribute_name), INDEX idx_component (component_name), INDEX idx_editable (is_editable) ) {$charset_collate};"; // Crear/actualizar tabla dbDelta($sql_settings); // Log en modo debug if (defined('WP_DEBUG') && WP_DEBUG) { error_log('ROI Theme: Database tables created/updated'); } }); // ============================================================================= // REGISTRO DE COMANDOS WP-CLI // ============================================================================= if (defined('WP_CLI') && WP_CLI) { require_once get_template_directory() . '/Shared/Infrastructure/Api/WordPress/MigrationCommand.php'; }