Files
roi-theme/functions.php
FrankZamora 9cb0dd1491 feat(custom-css-manager): implementar TIPO 3 - CSS Crítico Personalizado
Nuevo sistema de gestión de CSS personalizado con panel admin:
- Admin/CustomCSSManager: CRUD de snippets CSS (crítico/diferido)
- Public/CustomCSSManager: Inyección dinámica en frontend
- Schema JSON para configuración del componente

Migración de CSS estático a BD:
- Tablas APU (~14KB) → snippet diferido en BD
- Tablas Genéricas (~10KB) → snippet diferido en BD
- Comentadas funciones legacy en enqueue-scripts.php

Limpieza de archivos obsoletos:
- Eliminado build-bootstrap-subset.js
- Eliminado migrate-legacy-options.php
- Eliminado minify-css.php
- Eliminado purgecss.config.js

Beneficios:
- CSS editable desde admin sin tocar código
- Soporte crítico (head) y diferido (footer)
- Filtrado por scope (all/home/single/archive)

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

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

392 lines
15 KiB
PHP

<?php
declare(strict_types=1);
/**
* ROI Theme - Clean Architecture Bootstrap
*
* Este archivo es el punto de entrada del tema.
* Solo contiene bootstrap (carga del autoloader e inicialización del DI Container).
* TODO el código de lógica de negocio está en admin/, public/, shared/
*
* @package ROITheme
* @version 1.0.0
*/
// Prevenir acceso directo
if (!defined('ABSPATH')) {
exit;
}
// Definir constante de versión del tema
define('ROI_VERSION', '1.0.20');
// =============================================================================
// 1. CARGAR AUTOLOADER MANUAL
// =============================================================================
// IMPORTANTE: Cargar functions-addon.php PRIMERO para registrar el autoloader
// que permite cargar clases de ROITheme automáticamente
require_once __DIR__ . '/functions-addon.php';
// =============================================================================
// 2. CARGAR ARCHIVOS DE INC/ (ANTES DE LA CONFIGURACIÓN)
// =============================================================================
// IMPORTANTE: Cargar archivos inc/ ANTES del DI Container
// para que los estilos y scripts se registren correctamente
require_once get_template_directory() . '/Inc/sanitize-functions.php';
// ELIMINADO: Inc/theme-options-helpers.php (FASE 6 - Clean Architecture)
require_once get_template_directory() . '/Inc/nav-walker.php';
require_once get_template_directory() . '/Inc/enqueue-scripts.php';
// ELIMINADO: Inc/customizer-fonts.php (FASE 6 - Clean Architecture)
require_once get_template_directory() . '/Inc/seo.php';
require_once get_template_directory() . '/Inc/performance.php';
// ELIMINADO: Inc/critical-css.php (CSS crítico ahora viene de CriticalCSSService.php)
require_once get_template_directory() . '/Inc/image-optimization.php';
require_once get_template_directory() . '/Inc/template-functions.php';
require_once get_template_directory() . '/Inc/template-tags.php';
require_once get_template_directory() . '/Inc/featured-image.php';
require_once get_template_directory() . '/Inc/category-badge.php';
require_once get_template_directory() . '/Inc/adsense-delay.php';
require_once get_template_directory() . '/Inc/adsense-placement.php';
require_once get_template_directory() . '/Inc/related-posts.php';
// ELIMINADO: Inc/toc.php (FASE 6 - Clean Architecture: usa TableOfContentsRenderer)
require_once get_template_directory() . '/Inc/apu-tables.php';
require_once get_template_directory() . '/Inc/search-disable.php';
require_once get_template_directory() . '/Inc/comments-disable.php';
require_once get_template_directory() . '/Inc/social-share.php';
// =============================================================================
// 3. INICIALIZAR DI CONTAINER (Clean Architecture)
// =============================================================================
use ROITheme\Shared\Infrastructure\Di\DIContainer;
// Declarar $container como global para que esté disponible en Inc/*.php
global $container;
try {
global $wpdb;
// Path a los schemas
$schemas_path = get_template_directory() . '/schemas';
// Crear instancia del DI Container con dependencias
$container = new DIContainer($wpdb, $schemas_path);
// TODO: Inicializar controladores cuando estén implementados (Fase 5+)
// $ajaxController = $container->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();
// 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
*/
add_action('after_setup_theme', function() {
// Solo inyectar CSS en frontend (no admin)
if (is_admin()) {
return;
}
global $wpdb;
// Repository compartido
$repository = new \ROITheme\Admin\CustomCSSManager\Infrastructure\Persistence\WordPressSnippetRepository($wpdb);
// Use Cases para Public
$getCriticalUseCase = new \ROITheme\Public\CustomCSSManager\Application\UseCases\GetCriticalSnippetsUseCase($repository);
$getDeferredUseCase = new \ROITheme\Public\CustomCSSManager\Application\UseCases\GetDeferredSnippetsUseCase($repository);
// Injector de CSS en frontend
$injector = new \ROITheme\Public\CustomCSSManager\Infrastructure\Services\CustomCSSInjector(
$getCriticalUseCase,
$getDeferredUseCase
);
// Registrar hooks
$injector->register();
}, 5); // Priority 5: después de theme setup básico
// =============================================================================
// 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');
}
// =============================================================================
// 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';
}