Fase 1: Estructura Base y DI Container - Clean Architecture

COMPLETADO: Fase 1 de la migración a Clean Architecture + POO

## Estructura de Carpetas
- ✓ Estructura completa de 4 capas (Domain, Application, Infrastructure, Presentation)
- ✓ Carpetas de Use Cases (SaveComponent, GetComponent, DeleteComponent, SyncSchema)
- ✓ Estructura de tests (Unit, Integration, E2E)
- ✓ Carpetas de schemas y templates

## Composer y Autoloading
- ✓ PSR-4 autoloading configurado para ROITheme namespace
- ✓ Autoloader optimizado regenerado

## DI Container
- ✓ DIContainer implementado con patrón Singleton
- ✓ Métodos set(), get(), has() para gestión de servicios
- ✓ Getters específicos para ComponentRepository, ValidationService, CacheService
- ✓ Placeholders que serán implementados en Fase 5
- ✓ Prevención de clonación y deserialización

## Interfaces
- ✓ ComponentRepositoryInterface (Domain)
- ✓ ValidationServiceInterface (Application)
- ✓ CacheServiceInterface (Application)
- ✓ Component entity placeholder (Domain)

## Bootstrap
- ✓ functions.php actualizado con carga de Composer autoloader
- ✓ Inicialización del DIContainer
- ✓ Helper function roi_container() disponible globalmente

## Tests
- ✓ 10 tests unitarios para DIContainer (100% cobertura)
- ✓ Total: 13 tests unitarios, 28 assertions
- ✓ Suite de tests pasando correctamente

## Validación
- ✓ Script de validación automatizado (48/48 checks pasados)
- ✓ 100% de validaciones exitosas

La arquitectura base está lista para la Fase 2.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
FrankZamora
2025-11-17 13:48:24 -06:00
parent b782ebceee
commit de5fff4f5c
149 changed files with 3187 additions and 9554 deletions

View File

@@ -5,7 +5,7 @@
* Caja de llamada a la acción naranja en el sidebar
* Abre el modal de contacto al hacer clic
*
* @package APUs_Theme
* @package ROI_Theme
* @since 1.0.0
*/
?>

View File

@@ -5,7 +5,7 @@
* Este template renderiza el Call-to-Action con A/B Testing.
* La variante (A o B) se determina automáticamente por usuario.
*
* @package APUS_Theme
* @package ROI_Theme
* @since 1.0.0
*/
@@ -20,10 +20,10 @@ if (!is_single()) {
}
// Verificar si el CTA está habilitado
$enable_cta = get_theme_mod('apus_enable_cta', true);
$enable_cta = get_theme_mod('roi_enable_cta', true);
if (!$enable_cta) {
return;
}
// Usar la función del sistema de A/B testing
apus_display_cta();
roi_display_cta();

View File

@@ -4,7 +4,7 @@
*
* Hero section con degradado azul para single posts
*
* @package Apus_Theme
* @package ROI_Theme
*/
if (!is_single()) {
@@ -45,7 +45,7 @@ if (!is_single()) {
<?php the_author(); ?>
</span>
<?php
$reading_time = apus_get_reading_time();
$reading_time = roi_get_reading_time();
if ($reading_time) :
?>
<span class="hero-meta-separator">|</span>

View File

@@ -4,7 +4,7 @@
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*
* @package Apus_Theme
* @package ROI_Theme
* @since 1.0.0
*/
?>
@@ -12,7 +12,7 @@
<section class="no-results not-found">
<header class="page-header">
<h1 class="page-title"><?php esc_html_e( 'Nothing Found', 'apus-theme' ); ?></h1>
<h1 class="page-title"><?php esc_html_e( 'Nothing Found', 'roi-theme' ); ?></h1>
</header><!-- .page-header -->
<div class="page-content">
@@ -23,7 +23,7 @@
printf(
'<p>' . wp_kses(
/* translators: 1: link to WP admin new post page. */
__( 'Ready to publish your first post? <a href="%1$s">Get started here</a>.', 'apus-theme' ),
__( 'Ready to publish your first post? <a href="%1$s">Get started here</a>.', 'roi-theme' ),
array(
'a' => array(
'href' => array(),
@@ -37,7 +37,7 @@
?>
<!-- Search returned no results -->
<p><?php esc_html_e( 'Sorry, but nothing matched your search terms. Please try again with some different keywords.', 'apus-theme' ); ?></p>
<p><?php esc_html_e( 'Sorry, but nothing matched your search terms. Please try again with some different keywords.', 'roi-theme' ); ?></p>
<?php
get_search_form();
@@ -45,7 +45,7 @@
?>
<!-- Generic no content message -->
<p><?php esc_html_e( 'It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching can help.', 'apus-theme' ); ?></p>
<p><?php esc_html_e( 'It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching can help.', 'roi-theme' ); ?></p>
<?php
get_search_form();

View File

@@ -3,9 +3,9 @@
* Template Part: Table of Contents (TOC)
*
* Genera automáticamente TOC desde los H2 del post
* Usa JavaScript custom para ScrollSpy
* HTML exacto del template original
*
* @package APUs_Theme
* @package ROI_Theme
* @since 1.0.0
*/
@@ -14,52 +14,29 @@ if (!is_single()) {
return;
}
/**
* Función: Generar TOC desde el contenido del post
*
* Busca todos los H2 que tengan ID
* Retorna HTML de la tabla de contenidos
*/
function apu_generate_toc($content) {
// Buscar todos los H2 con ID en el contenido
// Regex: <h2[^>]*id=["']([^"']*) ["'][^>]*>(.*?)</h2>
preg_match_all('/<h2[^>]*id=["\']([^"\']*)["\'][^>]*>(.*?)<\/h2>/i', $content, $matches);
// Si no hay H2 con ID, no mostrar TOC
if (empty($matches[1])) {
return '';
}
// Iniciar construcción del TOC
$toc = '<div class="toc-container">';
$toc .= '<h4 class="toc-title">Tabla de Contenido</h4>';
$toc .= '<ol class="list-unstyled toc-list">';
// Iterar sobre cada H2 encontrado
foreach ($matches[1] as $index => $id) {
// Limpiar el título (eliminar tags HTML internos)
$title = strip_tags($matches[2][$index]);
// Crear el elemento de la lista
$toc .= sprintf(
'<li><a href="#%s" class="toc-link">%s</a></li>',
esc_attr($id),
esc_html($title)
);
}
$toc .= '</ol>';
$toc .= '</div>';
return $toc;
}
// Obtener el contenido del post actual
global $post;
$post_content = $post->post_content;
// Aplicar filtros de WordPress al contenido (shortcodes, etc.)
// Aplicar filtros de WordPress al contenido
$post_content = apply_filters('the_content', $post_content);
// Generar y mostrar el TOC
echo apu_generate_toc($post_content);
// Buscar todos los H2 con ID en el contenido
preg_match_all('/<h2[^>]*id=["\']([^"\']*)["\'][^>]*>(.*?)<\/h2>/i', $post_content, $matches);
// Si no hay H2 con ID, no mostrar TOC
if (empty($matches[1])) {
return;
}
// Generar el TOC con el HTML del template
?>
<div class="toc-container">
<h4>Tabla de Contenido</h4>
<ol class="list-unstyled toc-list">
<?php foreach ($matches[1] as $index => $id) : ?>
<?php $title = strip_tags($matches[2][$index]); ?>
<li><a href="#<?php echo esc_attr($id); ?>"><?php echo esc_html($title); ?></a></li>
<?php endforeach; ?>
</ol>
</div>

View File

@@ -4,7 +4,7 @@
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*
* @package Apus_Theme
* @package ROI_Theme
* @since 1.0.0
*/
?>
@@ -36,7 +36,7 @@
// Posted by author
printf(
'<span class="byline"> %s <span class="author vcard"><a class="url fn n" href="%s">%s</a></span></span>',
esc_html__( 'by', 'apus-theme' ),
esc_html__( 'by', 'roi-theme' ),
esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
esc_html( get_the_author() )
);
@@ -45,9 +45,9 @@
if ( ! post_password_required() && ( comments_open() || get_comments_number() ) ) :
echo '<span class="comments-link">';
comments_popup_link(
esc_html__( 'Leave a comment', 'apus-theme' ),
esc_html__( '1 Comment', 'apus-theme' ),
esc_html__( '% Comments', 'apus-theme' )
esc_html__( 'Leave a comment', 'roi-theme' ),
esc_html__( '1 Comment', 'roi-theme' ),
esc_html__( '% Comments', 'roi-theme' )
);
echo '</span>';
endif;
@@ -63,11 +63,11 @@
<div class="post-thumbnail">
<?php
if ( is_singular() ) :
the_post_thumbnail( 'apus-featured-large', array( 'alt' => the_title_attribute( array( 'echo' => false ) ) ) );
the_post_thumbnail( 'roi-featured-large', array( 'alt' => the_title_attribute( array( 'echo' => false ) ) ) );
else :
?>
<a href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
<?php the_post_thumbnail( 'apus-featured-medium', array( 'alt' => the_title_attribute( array( 'echo' => false ) ) ) ); ?>
<?php the_post_thumbnail( 'roi-featured-medium', array( 'alt' => the_title_attribute( array( 'echo' => false ) ) ) ); ?>
</a>
<?php
endif;
@@ -84,7 +84,7 @@
sprintf(
wp_kses(
/* translators: %s: Name of current post. Only visible to screen readers */
__( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'apus-theme' ),
__( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'roi-theme' ),
array(
'span' => array(
'class' => array(),
@@ -98,7 +98,7 @@
// Display pagination for multi-page posts
wp_link_pages(
array(
'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'apus-theme' ),
'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'roi-theme' ),
'after' => '</div>',
)
);
@@ -112,21 +112,21 @@
<footer class="entry-footer">
<?php
// Display categories
$categories_list = get_the_category_list( esc_html__( ', ', 'apus-theme' ) );
$categories_list = get_the_category_list( esc_html__( ', ', 'roi-theme' ) );
if ( $categories_list ) :
printf(
'<span class="cat-links">%s %s</span>',
esc_html__( 'Categories:', 'apus-theme' ),
esc_html__( 'Categories:', 'roi-theme' ),
$categories_list // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
);
endif;
// Display tags
$tags_list = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'apus-theme' ) );
$tags_list = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'roi-theme' ) );
if ( $tags_list ) :
printf(
'<span class="tags-links">%s %s</span>',
esc_html__( 'Tags:', 'apus-theme' ),
esc_html__( 'Tags:', 'roi-theme' ),
$tags_list // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
);
endif;
@@ -136,7 +136,7 @@
sprintf(
wp_kses(
/* translators: %s: Name of current post. Only visible to screen readers */
__( 'Edit <span class="screen-reader-text">%s</span>', 'apus-theme' ),
__( 'Edit <span class="screen-reader-text">%s</span>', 'roi-theme' ),
array(
'span' => array(
'class' => array(),

View File

@@ -4,7 +4,7 @@
*
* Aparece debajo del TOC en single posts
*
* @package Apus_Theme
* @package ROI_Theme
*/
if (!is_single()) {

View File

@@ -4,7 +4,7 @@
*
* Modal activado por botón "Let's Talk" y CTA Box Sidebar
*
* @package Apus_Theme
* @package ROI_Theme
* @since 1.0.0
*/
?>
@@ -16,40 +16,40 @@
<div class="modal-header">
<h5 class="modal-title" id="contactModalLabel">
<i class="bi bi-envelope-fill me-2" style="color: #FF8600;"></i>
<?php esc_html_e( '¿Tienes alguna pregunta?', 'apus-theme' ); ?>
<?php esc_html_e( '¿Tienes alguna pregunta?', 'roi-theme' ); ?>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="<?php esc_attr_e( 'Cerrar', 'apus-theme' ); ?>"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="<?php esc_attr_e( 'Cerrar', 'roi-theme' ); ?>"></button>
</div>
<div class="modal-body">
<p class="mb-4">
<?php esc_html_e( 'Completa el formulario y nuestro equipo te responderá en menos de 24 horas.', 'apus-theme' ); ?>
<?php esc_html_e( 'Completa el formulario y nuestro equipo te responderá en menos de 24 horas.', 'roi-theme' ); ?>
</p>
<form id="modalContactForm">
<div class="row g-3">
<div class="col-md-6">
<label for="modalFullName" class="form-label"><?php esc_html_e( 'Nombre completo', 'apus-theme' ); ?> *</label>
<label for="modalFullName" class="form-label"><?php esc_html_e( 'Nombre completo', 'roi-theme' ); ?> *</label>
<input type="text" class="form-control" id="modalFullName" name="fullName" required>
</div>
<div class="col-md-6">
<label for="modalCompany" class="form-label"><?php esc_html_e( 'Empresa', 'apus-theme' ); ?></label>
<label for="modalCompany" class="form-label"><?php esc_html_e( 'Empresa', 'roi-theme' ); ?></label>
<input type="text" class="form-control" id="modalCompany" name="company">
</div>
<div class="col-md-6">
<label for="modalWhatsapp" class="form-label"><?php esc_html_e( 'WhatsApp', 'apus-theme' ); ?> *</label>
<label for="modalWhatsapp" class="form-label"><?php esc_html_e( 'WhatsApp', 'roi-theme' ); ?> *</label>
<input type="tel" class="form-control" id="modalWhatsapp" name="whatsapp" required>
</div>
<div class="col-md-6">
<label for="modalEmail" class="form-label"><?php esc_html_e( 'Correo electrónico', 'apus-theme' ); ?> *</label>
<label for="modalEmail" class="form-label"><?php esc_html_e( 'Correo electrónico', 'roi-theme' ); ?> *</label>
<input type="email" class="form-control" id="modalEmail" name="email" required>
</div>
<div class="col-12">
<label for="modalComments" class="form-label"><?php esc_html_e( '¿En qué podemos ayudarte?', 'apus-theme' ); ?></label>
<label for="modalComments" class="form-label"><?php esc_html_e( '¿En qué podemos ayudarte?', 'roi-theme' ); ?></label>
<textarea class="form-control" id="modalComments" name="comments" rows="4"></textarea>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-send-fill me-2"></i><?php esc_html_e( 'Enviar Mensaje', 'apus-theme' ); ?>
<i class="bi bi-send-fill me-2"></i><?php esc_html_e( 'Enviar Mensaje', 'roi-theme' ); ?>
</button>
</div>
<div id="modalFormMessage" class="col-12 mt-2 alert" style="display: none;"></div>

View File

@@ -0,0 +1,20 @@
<?php
/**
* Top Notification Bar Component
*
* Barra de notificaciones superior del sitio
*
* @package ROI_Theme
* @since 2.0.0
*/
?>
<div class="top-notification-bar">
<div class="container">
<div class="d-flex align-items-center justify-content-center">
<i class="bi bi-megaphone-fill me-2"></i>
<span><strong>Nuevo:</strong> Accede a más de 200,000 Análisis de Precios Unitarios actualizados para 2025.</span>
<a href="#" class="ms-2 text-white text-decoration-underline">Ver Catálogo</a>
</div>
</div>
</div>