Files
roi-theme/public
FrankZamora 677fbd4368 Fase-00: Estructura Clean Architecture Context-First creada
- Creada estructura shared/ con Domain, Application, Infrastructure
- Documentación completa de arquitectura (5 READMEs, ~6150 líneas)
- Archivos .gitkeep para preservar estructura en Git
- Contextos admin/ y public/ documentados

Estructura shared/:
- Domain/ (ValueObjects, Exceptions, Contracts)
- Application/ (Contracts, Services)
- Infrastructure/ (Services, Traits)

Documentación incluye:
- Principios de Clean Architecture
- Reglas de dependencia
- Ejemplos de código
- Guías de testing
- Mejores prácticas

Preparación completa para implementación en Fase-1.
2025-11-18 23:36:06 -06:00
..

Contexto Public - Renderizado Frontend de Componentes

Propósito

El contexto public/ contiene todo el código relacionado con el renderizado de componentes en el frontend. Cada componente tiene su propia carpeta con su Clean Architecture completa.

Filosofía: Context-First Architecture

Similar a admin/, el contexto public/ agrupa todo lo relacionado con la visualización pública de componentes. Cada componente es independiente y tiene sus propias capas de Clean Architecture.

Estructura (Fase-00)

En Fase-00 solo creamos la estructura base. Los componentes se crearán en fases posteriores:

public/
├── README.md (este archivo)
└── .gitkeep (preserva directorio en Git)

Estructura Futura (Post Fase-00)

public/
├── Navbar/                              # Componente Navbar
│   ├── Domain/
│   │   ├── NavbarData.php               # Entidad de lectura
│   │   └── NavbarDataProviderInterface.php
│   ├── Application/
│   │   ├── GetNavbarDataUseCase.php     # Caso de uso
│   │   └── DTO/
│   │       └── NavbarDataDTO.php
│   ├── Infrastructure/
│   │   ├── Persistence/
│   │   │   └── WordPressNavbarDataProvider.php
│   │   ├── UI/
│   │   │   ├── NavbarRenderer.php       # Renderizador
│   │   │   ├── views/
│   │   │   │   └── navbar.php           # Template
│   │   │   └── assets/
│   │   │       ├── css/
│   │   │       │   └── navbar.css
│   │   │       └── js/
│   │   │           └── navbar.js
│   │   └── Hooks/
│   │       └── NavbarHooks.php          # WordPress hooks
│   └── README.md
├── Footer/                              # Otro componente
│   └── (misma estructura)
└── (más componentes...)

Principios del Contexto Public

  1. Solo lectura: El frontend solo lee configuraciones, no las modifica
  2. Performance: Optimizado para carga rápida y caché
  3. Presentación: Se enfoca en renderizar HTML, CSS, JS
  4. Independencia: Cada componente es autónomo

Responsabilidades

El contexto public/ se encarga de:

Renderizado de componentes en el frontend Lectura de configuraciones de la base de datos Generación de HTML según templates Carga de assets (CSS, JS) del componente Enqueue de scripts y estilos Hooks de WordPress para frontend (wp_head, wp_footer, etc.)

NO se encarga de:

  • Administración de componentes (va en admin/)
  • Guardado de configuraciones
  • Lógica compartida (va en shared/)

Ejemplo de Flujo de Public

1. Usuario visita página web

Usuario (navegador)
    ↓
WordPress carga tema
    ↓
NavbarHooks.php (registra hook 'wp_body_open')
    ↓
Hook ejecutado
    ↓
NavbarRenderer.php (obtiene datos y renderiza)
    ↓
GetNavbarDataUseCase.php (obtiene configuración)
    ↓
WordPressNavbarDataProvider.php (lee de DB)
    ↓
navbar.php (template con HTML)
    ↓
HTML enviado al navegador

2. Código de ejemplo

// public/Navbar/Application/GetNavbarDataUseCase.php
namespace ROITheme\Public\Navbar\Application;

use ROITheme\Public\Navbar\Domain\NavbarDataProviderInterface;

final class GetNavbarDataUseCase
{
    public function __construct(
        private readonly NavbarDataProviderInterface $dataProvider
    ) {}

    public function execute(): array
    {
        $data = $this->dataProvider->get();

        // Transformar datos si es necesario
        return [
            'logo_url' => $data['logo_url'] ?? '',
            'menu_items' => $data['menu_items'] ?? [],
            'sticky' => $data['sticky'] ?? false,
        ];
    }
}
// public/Navbar/Infrastructure/UI/NavbarRenderer.php
namespace ROITheme\Public\Navbar\Infrastructure\UI;

use ROITheme\Public\Navbar\Application\GetNavbarDataUseCase;

final class NavbarRenderer
{
    public function __construct(
        private readonly GetNavbarDataUseCase $getNavbarData
    ) {}

    public function render(): void
    {
        $data = $this->getNavbarData->execute();

        // Encolar assets
        wp_enqueue_style(
            'roi-navbar',
            get_template_directory_uri() . '/public/Navbar/Infrastructure/UI/assets/css/navbar.css',
            [],
            '1.0.0'
        );

        wp_enqueue_script(
            'roi-navbar',
            get_template_directory_uri() . '/public/Navbar/Infrastructure/UI/assets/js/navbar.js',
            ['jquery'],
            '1.0.0',
            true
        );

        // Renderizar template
        require __DIR__ . '/views/navbar.php';
    }
}
// public/Navbar/Infrastructure/Hooks/NavbarHooks.php
namespace ROITheme\Public\Navbar\Infrastructure\Hooks;

use ROITheme\Public\Navbar\Infrastructure\UI\NavbarRenderer;

final class NavbarHooks
{
    public function __construct(
        private readonly NavbarRenderer $renderer
    ) {}

    public function register(): void
    {
        add_action('wp_body_open', [$this->renderer, 'render']);
    }
}
// public/Navbar/Infrastructure/UI/views/navbar.php
<?php
/**
 * Template del Navbar
 *
 * @var array $data Datos del navbar
 */
?>
<nav class="roi-navbar <?= $data['sticky'] ? 'sticky' : '' ?>">
    <div class="container">
        <a href="<?= home_url() ?>">
            <img src="<?= esc_url($data['logo_url']) ?>" alt="Logo">
        </a>
        <ul class="menu">
            <?php foreach ($data['menu_items'] as $item): ?>
                <li>
                    <a href="<?= esc_url($item['url']) ?>">
                        <?= esc_html($item['label']) ?>
                    </a>
                </li>
            <?php endforeach; ?>
        </ul>
    </div>
</nav>

Relación con Otros Contextos

admin/               → Guarda configuraciones
    ↓
Base de Datos        → Almacena settings
    ↓ lee
public/              → Renderiza componentes
    ↓
Navegador del Usuario

Clave: public/ solo LECTURA, nunca escritura.

Optimización y Caché

1. Usar Transients de WordPress

public function get(): array
{
    $cached = get_transient('roi_navbar_data');

    if ($cached !== false) {
        return $cached;
    }

    $data = $this->fetchFromDatabase();
    set_transient('roi_navbar_data', $data, HOUR_IN_SECONDS);

    return $data;
}

2. Conditional Asset Loading

if ($data['sticky']) {
    wp_enqueue_script('roi-navbar-sticky');
}

3. Lazy Loading de Componentes

add_action('wp_body_open', function() {
    if (is_front_page()) {
        // Solo cargar en homepage
        $renderer->render();
    }
});

Reglas de Dependencia

PUEDE depender de:

  • shared/Domain/ (Value Objects, Exceptions)
  • shared/Application/ (Contracts, Services)
  • shared/Infrastructure/ (Implementaciones de servicios)
  • WordPress frontend functions (wp_enqueue_style, wp_head, etc.)

NO PUEDE depender de:

  • admin/ (contexto independiente)
  • Funciones de administración de WordPress

Testing

Tests Unitarios

// tests/Unit/Public/Navbar/Application/GetNavbarDataUseCaseTest.php
public function test_returns_navbar_data()
{
    $dataProvider = $this->createMock(NavbarDataProviderInterface::class);
    $dataProvider->method('get')->willReturn(['logo_url' => 'test.png']);

    $useCase = new GetNavbarDataUseCase($dataProvider);
    $data = $useCase->execute();

    $this->assertEquals('test.png', $data['logo_url']);
}

Tests de Integración

// tests/Integration/Public/Navbar/Infrastructure/WordPressNavbarDataProviderTest.php
public function test_retrieves_navbar_settings_from_db()
{
    update_option('roi_navbar_settings', ['logo_url' => 'test.png']);

    $provider = new WordPressNavbarDataProvider();
    $data = $provider->get();

    $this->assertEquals('test.png', $data['logo_url']);
}

Tests E2E (Playwright)

// tests/E2E/Public/NavbarRenderingTest.php
public function test_navbar_renders_on_homepage()
{
    $this->visit('/');
    $this->see('.roi-navbar');
    $this->see('Logo');
}

Tests de Performance

// tests/Performance/Public/NavbarPerformanceTest.php
public function test_navbar_renders_in_less_than_100ms()
{
    $start = microtime(true);

    $renderer = new NavbarRenderer($this->getNavbarDataUseCase);
    ob_start();
    $renderer->render();
    ob_end_clean();

    $duration = (microtime(true) - $start) * 1000;

    $this->assertLessThan(100, $duration);
}

Cuándo Agregar Código Aquí

Agrega código a public/ cuando:

  • Renderizas un componente en el frontend
  • Necesitas mostrar datos al usuario final
  • Cargas assets (CSS, JS) para el frontend
  • Registras hooks de frontend (wp_head, wp_footer, etc.)
  • Optimizas performance de renderizado

No agregues aquí:

  • Formularios de admin (van en admin/)
  • Guardado de configuraciones
  • Lógica compartida (va en shared/)

Assets y Performance

Organización de Assets

public/Navbar/Infrastructure/UI/assets/
├── css/
│   ├── navbar.css        # Estilos del componente
│   └── navbar.min.css    # Versión minificada
├── js/
│   ├── navbar.js         # JavaScript del componente
│   └── navbar.min.js     # Versión minificada
└── images/
    └── default-logo.png  # Imágenes del componente

Minificación y Concatenación

En producción, usar versiones minificadas:

$suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
wp_enqueue_style('roi-navbar', "...navbar{$suffix}.css");

Estado Actual (Fase-00)

En Fase-00, public/ solo tiene la estructura base. Los componentes se crearán en las siguientes fases:

  • Fase-1: Estructura base e infraestructura
  • Fase-2: Migración de base de datos
  • Fase-3: Implementación de componentes públicos
  • Fase-4+: Componentes adicionales y optimización

Próximos Pasos

  1. Crear primer componente en Fase-3 (ej: Navbar)
  2. Implementar Domain layer (entidades de lectura)
  3. Implementar Application layer (casos de uso de lectura)
  4. Implementar Infrastructure layer (renderizado, hooks)
  5. Crear templates y assets
  6. Optimizar con caché
  7. Crear tests de performance
  8. Repetir para cada componente