Migración completa a Clean Architecture con componentes funcionales
- Reorganización de estructura: Admin/, Public/, Shared/, Schemas/ - 12 componentes migrados: TopNotificationBar, Navbar, CtaLetsTalk, Hero, FeaturedImage, TableOfContents, CtaBoxSidebar, SocialShare, CtaPost, RelatedPost, ContactForm, Footer - Panel de administración con tabs Bootstrap 5 funcionales - Schemas JSON para configuración de componentes - Renderers dinámicos con CSSGeneratorService (cero CSS hardcodeado) - FormBuilders para UI admin con Design System consistente - Fix: Bootstrap JS cargado en header para tabs funcionales - Fix: buildTextInput maneja valores mixed (bool/string) - Eliminación de estructura legacy (src/, admin/, assets/css/componente-*) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
232
functions-addon.php
Normal file
232
functions-addon.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
// =============================================================================
|
||||
// AUTOLOADER PARA COMPONENTES
|
||||
// =============================================================================
|
||||
|
||||
spl_autoload_register(function ($class) {
|
||||
// Mapeo de namespaces a directorios
|
||||
$prefixes = [
|
||||
'ROITheme\\Shared\\' => get_template_directory() . '/Shared/',
|
||||
'ROITheme\\Public\\' => get_template_directory() . '/Public/',
|
||||
'ROITheme\\Admin\\' => get_template_directory() . '/Admin/',
|
||||
];
|
||||
|
||||
foreach ($prefixes as $prefix => $base_dir) {
|
||||
$len = strlen($prefix);
|
||||
if (strncmp($prefix, $class, $len) === 0) {
|
||||
$relative_class = substr($class, $len);
|
||||
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
|
||||
|
||||
if (file_exists($file)) {
|
||||
require $file;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// =============================================================================
|
||||
// HELPER FUNCTION: roi_get_navbar_setting()
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Obtiene un valor de configuración del navbar desde la BD
|
||||
*
|
||||
* @param string $group Nombre del grupo (ej: 'media', 'visibility')
|
||||
* @param string $attribute Nombre del atributo (ej: 'show_brand', 'logo_url')
|
||||
* @param mixed $default Valor por defecto si no existe
|
||||
* @return mixed Valor del atributo
|
||||
*/
|
||||
function roi_get_navbar_setting(string $group, string $attribute, $default = null) {
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->prefix . 'roi_theme_component_settings';
|
||||
$value = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT attribute_value FROM {$table}
|
||||
WHERE component_name = 'navbar'
|
||||
AND group_name = %s
|
||||
AND attribute_name = %s",
|
||||
$group,
|
||||
$attribute
|
||||
));
|
||||
|
||||
if ($value === null) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
// Convertir booleanos
|
||||
if ($value === '1') return true;
|
||||
if ($value === '0') return false;
|
||||
|
||||
// Intentar decodificar JSON
|
||||
$decoded = json_decode($value, true);
|
||||
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// HELPER FUNCTION: roi_render_component()
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Renderiza un componente por su nombre
|
||||
*
|
||||
* @param string $componentName Nombre del componente
|
||||
* @return string HTML del componente renderizado
|
||||
*/
|
||||
function roi_render_component(string $componentName): string {
|
||||
global $wpdb;
|
||||
|
||||
// DEBUG: Trace component rendering
|
||||
error_log("ROI Theme DEBUG: roi_render_component called with: {$componentName}");
|
||||
|
||||
try {
|
||||
// Obtener datos del componente desde BD normalizada
|
||||
$table = $wpdb->prefix . 'roi_theme_component_settings';
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT group_name, attribute_name, attribute_value
|
||||
FROM {$table}
|
||||
WHERE component_name = %s
|
||||
ORDER BY group_name, attribute_name",
|
||||
$componentName
|
||||
));
|
||||
|
||||
if (empty($rows)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Reconstruir estructura de datos agrupada
|
||||
$data = [];
|
||||
foreach ($rows as $row) {
|
||||
if (!isset($data[$row->group_name])) {
|
||||
$data[$row->group_name] = [];
|
||||
}
|
||||
// Decodificar valor
|
||||
$value = $row->attribute_value;
|
||||
|
||||
// Convertir booleanos almacenados como '1' o '0'
|
||||
if ($value === '1' || $value === '0') {
|
||||
$value = ($value === '1');
|
||||
} else {
|
||||
// Intentar decodificar JSON
|
||||
$decoded = json_decode($value, true);
|
||||
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
|
||||
$value = $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
$data[$row->group_name][$row->attribute_name] = $value;
|
||||
}
|
||||
|
||||
// Crear Value Objects requeridos
|
||||
$name = new \ROITheme\Shared\Domain\ValueObjects\ComponentName($componentName);
|
||||
$configuration = new \ROITheme\Shared\Domain\ValueObjects\ComponentConfiguration($data);
|
||||
$visibility = \ROITheme\Shared\Domain\ValueObjects\ComponentVisibility::allDevices(); // Default: visible en todas partes
|
||||
|
||||
// Crear instancia del componente
|
||||
$component = new \ROITheme\Shared\Domain\Entities\Component(
|
||||
$name,
|
||||
$configuration,
|
||||
$visibility
|
||||
);
|
||||
|
||||
// Obtener renderer específico para el componente
|
||||
$renderer = null;
|
||||
|
||||
// Crear instancia del CSSGeneratorService (reutilizable para todos los renderers que lo necesiten)
|
||||
$cssGenerator = new \ROITheme\Shared\Infrastructure\Services\CSSGeneratorService();
|
||||
|
||||
switch ($componentName) {
|
||||
// Componentes nuevos (namespace PascalCase correcto)
|
||||
case 'top-notification-bar':
|
||||
$renderer = new \ROITheme\Public\TopNotificationBar\Infrastructure\Ui\TopNotificationBarRenderer($cssGenerator);
|
||||
break;
|
||||
case 'navbar':
|
||||
$renderer = new \ROITheme\Public\Navbar\Infrastructure\Ui\NavbarRenderer($cssGenerator);
|
||||
break;
|
||||
case 'cta-lets-talk':
|
||||
$renderer = new \ROITheme\Public\CtaLetsTalk\Infrastructure\Ui\CtaLetsTalkRenderer($cssGenerator);
|
||||
break;
|
||||
case 'hero':
|
||||
error_log("ROI Theme DEBUG: Creating HeroRenderer");
|
||||
$renderer = new \ROITheme\Public\Hero\Infrastructure\Ui\HeroRenderer($cssGenerator);
|
||||
error_log("ROI Theme DEBUG: HeroRenderer created successfully");
|
||||
break;
|
||||
// Componentes legacy (namespace minúsculas - pendiente migración)
|
||||
case 'hero-section':
|
||||
$renderer = new \ROITheme\Public\herosection\infrastructure\ui\HeroSectionRenderer();
|
||||
break;
|
||||
case 'featured-image':
|
||||
$renderer = new \ROITheme\Public\FeaturedImage\Infrastructure\Ui\FeaturedImageRenderer($cssGenerator);
|
||||
break;
|
||||
case 'table-of-contents':
|
||||
$renderer = new \ROITheme\Public\TableOfContents\Infrastructure\Ui\TableOfContentsRenderer($cssGenerator);
|
||||
break;
|
||||
case 'cta-box-sidebar':
|
||||
$renderer = new \ROITheme\Public\CtaBoxSidebar\Infrastructure\Ui\CtaBoxSidebarRenderer($cssGenerator);
|
||||
break;
|
||||
case 'social-share':
|
||||
$renderer = new \ROITheme\Public\SocialShare\Infrastructure\Ui\SocialShareRenderer($cssGenerator);
|
||||
break;
|
||||
case 'cta-post':
|
||||
$renderer = new \ROITheme\Public\CtaPost\Infrastructure\Ui\CtaPostRenderer($cssGenerator);
|
||||
break;
|
||||
case 'related-post':
|
||||
$renderer = new \ROITheme\Public\RelatedPost\Infrastructure\Ui\RelatedPostRenderer($cssGenerator);
|
||||
break;
|
||||
case 'contact-form':
|
||||
$renderer = new \ROITheme\Public\ContactForm\Infrastructure\Ui\ContactFormRenderer($cssGenerator);
|
||||
break;
|
||||
case 'footer':
|
||||
$renderer = new \ROITheme\Public\Footer\Infrastructure\Ui\FooterRenderer($cssGenerator);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$renderer) {
|
||||
error_log("ROI Theme DEBUG: No renderer for {$componentName}");
|
||||
return '';
|
||||
}
|
||||
|
||||
error_log("ROI Theme DEBUG: Calling render() for {$componentName}");
|
||||
$output = $renderer->render($component);
|
||||
error_log("ROI Theme DEBUG: render() returned " . strlen($output) . " chars for {$componentName}");
|
||||
return $output;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Always log errors for debugging
|
||||
error_log('ROI Theme ERROR: Exception rendering component ' . $componentName . ': ' . $e->getMessage());
|
||||
error_log('ROI Theme ERROR: Stack trace: ' . $e->getTraceAsString());
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// CARGAR ARCHIVOS DE INC/
|
||||
// =============================================================================
|
||||
|
||||
// CTA A/B Testing System
|
||||
$cta_ab_testing = get_template_directory() . '/Inc/cta-ab-testing.php';
|
||||
if (file_exists($cta_ab_testing)) {
|
||||
require_once $cta_ab_testing;
|
||||
}
|
||||
|
||||
// CTA Customizer Settings
|
||||
$cta_customizer = get_template_directory() . '/Inc/customizer-cta.php';
|
||||
if (file_exists($cta_customizer)) {
|
||||
require_once $cta_customizer;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ESTILOS BASE PARA TOP NOTIFICATION BAR
|
||||
// =============================================================================
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// NOTA: Los estilos de TOC y CTA Box Sidebar se generan dinámicamente
|
||||
// desde la base de datos a través de sus respectivos Renderers.
|
||||
// NO hardcodear CSS aquí - viola la arquitectura Clean Architecture.
|
||||
// =============================================================================
|
||||
Reference in New Issue
Block a user