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

@@ -7,7 +7,7 @@
* NOTA: Versión reducida con solo optimizaciones seguras después de
* resolver problemas de memory exhaustion en Issue #22.
*
* @package Apus_Theme
* @package ROI_Theme
* @since 1.0.0
*/
@@ -24,7 +24,7 @@ if ( ! defined( 'ABSPATH' ) ) {
*
* @since 1.0.0
*/
function apus_disable_emojis() {
function roi_disable_emojis() {
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
@@ -34,9 +34,9 @@ function apus_disable_emojis() {
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
// Remove from TinyMCE.
add_filter( 'tiny_mce_plugins', 'apus_disable_emojis_tinymce' );
add_filter( 'tiny_mce_plugins', 'roi_disable_emojis_tinymce' );
}
add_action( 'init', 'apus_disable_emojis' );
add_action( 'init', 'roi_disable_emojis' );
/**
* Filter function used to remove emoji plugin from TinyMCE
@@ -45,7 +45,7 @@ add_action( 'init', 'apus_disable_emojis' );
* @param array $plugins An array of default TinyMCE plugins.
* @return array Modified array of TinyMCE plugins without emoji plugin.
*/
function apus_disable_emojis_tinymce( $plugins ) {
function roi_disable_emojis_tinymce( $plugins ) {
if ( is_array( $plugins ) ) {
return array_diff( $plugins, array( 'wpemoji' ) );
}
@@ -61,7 +61,7 @@ function apus_disable_emojis_tinymce( $plugins ) {
*
* @since 1.0.0
*/
function apus_disable_oembed() {
function roi_disable_oembed() {
// Remove oEmbed discovery links.
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
@@ -69,12 +69,12 @@ function apus_disable_oembed() {
remove_action( 'wp_head', 'wp_oembed_add_host_js' );
// Remove all embeds rewrite rules.
add_filter( 'rewrite_rules_array', 'apus_disable_oembed_rewrites' );
add_filter( 'rewrite_rules_array', 'roi_disable_oembed_rewrites' );
// Remove filter of the oEmbed result before any HTTP requests are made.
remove_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result', 10 );
}
add_action( 'init', 'apus_disable_oembed', 9999 );
add_action( 'init', 'roi_disable_oembed', 9999 );
/**
* Remove all rewrite rules related to embeds
@@ -83,7 +83,7 @@ add_action( 'init', 'apus_disable_oembed', 9999 );
* @param array $rules WordPress rewrite rules.
* @return array Modified rewrite rules.
*/
function apus_disable_oembed_rewrites( $rules ) {
function roi_disable_oembed_rewrites( $rules ) {
foreach ( $rules as $rule => $rewrite ) {
if ( false !== strpos( $rewrite, 'embed=true' ) ) {
unset( $rules[ $rule ] );
@@ -100,10 +100,10 @@ function apus_disable_oembed_rewrites( $rules ) {
*
* @since 1.0.0
*/
function apus_dequeue_embed_script() {
function roi_dequeue_embed_script() {
wp_deregister_script( 'wp-embed' );
}
add_action( 'wp_footer', 'apus_dequeue_embed_script' );
add_action( 'wp_footer', 'roi_dequeue_embed_script' );
/**
* Disable WordPress Feeds
@@ -113,10 +113,10 @@ add_action( 'wp_footer', 'apus_dequeue_embed_script' );
*
* @since 1.0.0
*/
function apus_disable_feeds() {
function roi_disable_feeds() {
wp_die(
esc_html__( 'No feed available, please visit our homepage!', 'apus' ),
esc_html__( 'Feed Not Available', 'apus' ),
esc_html__( 'No feed available, please visit our homepage!', 'roi' ),
esc_html__( 'Feed Not Available', 'roi' ),
array(
'response' => 404,
'back_link' => true,
@@ -129,21 +129,21 @@ function apus_disable_feeds() {
*
* @since 1.0.0
*/
function apus_disable_feed_links() {
function roi_disable_feed_links() {
// Remove feed links from header.
remove_action( 'wp_head', 'feed_links', 2 );
remove_action( 'wp_head', 'feed_links_extra', 3 );
// Redirect feed URLs to homepage.
add_action( 'do_feed', 'apus_disable_feeds', 1 );
add_action( 'do_feed_rdf', 'apus_disable_feeds', 1 );
add_action( 'do_feed_rss', 'apus_disable_feeds', 1 );
add_action( 'do_feed_rss2', 'apus_disable_feeds', 1 );
add_action( 'do_feed_atom', 'apus_disable_feeds', 1 );
add_action( 'do_feed_rss2_comments', 'apus_disable_feeds', 1 );
add_action( 'do_feed_atom_comments', 'apus_disable_feeds', 1 );
add_action( 'do_feed', 'roi_disable_feeds', 1 );
add_action( 'do_feed_rdf', 'roi_disable_feeds', 1 );
add_action( 'do_feed_rss', 'roi_disable_feeds', 1 );
add_action( 'do_feed_rss2', 'roi_disable_feeds', 1 );
add_action( 'do_feed_atom', 'roi_disable_feeds', 1 );
add_action( 'do_feed_rss2_comments', 'roi_disable_feeds', 1 );
add_action( 'do_feed_atom_comments', 'roi_disable_feeds', 1 );
}
add_action( 'init', 'apus_disable_feed_links' );
add_action( 'init', 'roi_disable_feed_links' );
/**
* Disable RSD and Windows Live Writer Manifest
@@ -153,14 +153,14 @@ add_action( 'init', 'apus_disable_feed_links' );
*
* @since 1.0.0
*/
function apus_disable_rsd_wlw() {
function roi_disable_rsd_wlw() {
// Remove RSD link.
remove_action( 'wp_head', 'rsd_link' );
// Remove Windows Live Writer manifest link.
remove_action( 'wp_head', 'wlwmanifest_link' );
}
add_action( 'init', 'apus_disable_rsd_wlw' );
add_action( 'init', 'roi_disable_rsd_wlw' );
/**
* Disable Dashicons for non-logged users
@@ -170,12 +170,12 @@ add_action( 'init', 'apus_disable_rsd_wlw' );
*
* @since 1.0.0
*/
function apus_disable_dashicons() {
function roi_disable_dashicons() {
if ( ! is_user_logged_in() ) {
wp_deregister_style( 'dashicons' );
}
}
add_action( 'wp_enqueue_scripts', 'apus_disable_dashicons' );
add_action( 'wp_enqueue_scripts', 'roi_disable_dashicons' );
/**
* Disable Block Library CSS
@@ -186,7 +186,7 @@ add_action( 'wp_enqueue_scripts', 'apus_disable_dashicons' );
*
* @since 1.0.0
*/
function apus_disable_block_library_css() {
function roi_disable_block_library_css() {
// Remove default block library styles.
wp_dequeue_style( 'wp-block-library' );
wp_dequeue_style( 'wp-block-library-theme' );
@@ -197,7 +197,7 @@ function apus_disable_block_library_css() {
// Remove classic theme styles (if not using classic editor).
wp_dequeue_style( 'classic-theme-styles' );
}
add_action( 'wp_enqueue_scripts', 'apus_disable_block_library_css', 100 );
add_action( 'wp_enqueue_scripts', 'roi_disable_block_library_css', 100 );
/**
* Remove WordPress version from head and feeds
@@ -206,10 +206,10 @@ add_action( 'wp_enqueue_scripts', 'apus_disable_block_library_css', 100 );
*
* @since 1.0.0
*/
function apus_remove_wp_version() {
function roi_remove_wp_version() {
return '';
}
add_filter( 'the_generator', 'apus_remove_wp_version' );
add_filter( 'the_generator', 'roi_remove_wp_version' );
/**
* Disable XML-RPC
@@ -220,10 +220,10 @@ add_filter( 'the_generator', 'apus_remove_wp_version' );
* @since 1.0.0
* @return bool
*/
function apus_disable_xmlrpc() {
function roi_disable_xmlrpc() {
return false;
}
add_filter( 'xmlrpc_enabled', 'apus_disable_xmlrpc' );
add_filter( 'xmlrpc_enabled', 'roi_disable_xmlrpc' );
/**
* Remove jQuery Migrate
@@ -234,7 +234,7 @@ add_filter( 'xmlrpc_enabled', 'apus_disable_xmlrpc' );
* @since 1.0.0
* @param WP_Scripts $scripts WP_Scripts object.
*/
function apus_remove_jquery_migrate( $scripts ) {
function roi_remove_jquery_migrate( $scripts ) {
if ( ! is_admin() && isset( $scripts->registered['jquery'] ) ) {
$script = $scripts->registered['jquery'];
@@ -244,7 +244,7 @@ function apus_remove_jquery_migrate( $scripts ) {
}
}
}
add_action( 'wp_default_scripts', 'apus_remove_jquery_migrate' );
add_action( 'wp_default_scripts', 'roi_remove_jquery_migrate' );
/**
* Optimize WordPress Database Queries
@@ -253,12 +253,12 @@ add_action( 'wp_default_scripts', 'apus_remove_jquery_migrate' );
*
* @since 1.0.0
*/
function apus_optimize_queries() {
function roi_optimize_queries() {
// Remove unnecessary post meta from queries
remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10 );
remove_action( 'wp_head', 'wp_shortlink_wp_head', 10 );
}
add_action( 'init', 'apus_optimize_queries' );
add_action( 'init', 'roi_optimize_queries' );
/**
* Disable WordPress Admin Bar for Non-Admins
@@ -267,12 +267,12 @@ add_action( 'init', 'apus_optimize_queries' );
*
* @since 1.0.0
*/
function apus_disable_admin_bar() {
function roi_disable_admin_bar() {
if ( ! current_user_can( 'administrator' ) && ! is_admin() ) {
show_admin_bar( false );
}
}
add_action( 'after_setup_theme', 'apus_disable_admin_bar' );
add_action( 'after_setup_theme', 'roi_disable_admin_bar' );
/**
* ============================================================================
@@ -291,7 +291,7 @@ add_action( 'after_setup_theme', 'apus_disable_admin_bar' );
* @param string $relation_type The relation type (dns-prefetch, preconnect, etc.).
* @return array Modified array of resource URLs.
*/
function apus_add_resource_hints( $urls, $relation_type ) {
function roi_add_resource_hints( $urls, $relation_type ) {
// DNS Prefetch para recursos externos que no son críticos
if ( 'dns-prefetch' === $relation_type ) {
// CDN de Bootstrap Icons (ya usado en enqueue-scripts.php)
@@ -318,7 +318,7 @@ function apus_add_resource_hints( $urls, $relation_type ) {
return $urls;
}
add_filter( 'wp_resource_hints', 'apus_add_resource_hints', 10, 2 );
add_filter( 'wp_resource_hints', 'roi_add_resource_hints', 10, 2 );
/**
* Preload de recursos críticos para mejorar LCP
@@ -328,7 +328,7 @@ add_filter( 'wp_resource_hints', 'apus_add_resource_hints', 10, 2 );
*
* @since 1.0.0
*/
function apus_preload_critical_resources() {
function roi_preload_critical_resources() {
// Preload de fuentes críticas
$fonts = array(
'inter-var.woff2',
@@ -357,7 +357,7 @@ function apus_preload_critical_resources() {
esc_url( $fonts_css )
);
}
add_action( 'wp_head', 'apus_preload_critical_resources', 2 );
add_action( 'wp_head', 'roi_preload_critical_resources', 2 );
/**
* ============================================================================
@@ -376,7 +376,7 @@ add_action( 'wp_head', 'apus_preload_critical_resources', 2 );
* @param string $handle The script handle.
* @return string Modified script tag.
*/
function apus_add_script_attributes( $tag, $handle ) {
function roi_add_script_attributes( $tag, $handle ) {
// Scripts que deben tener async (no dependen de otros ni del DOM)
$async_scripts = array(
// Google Analytics u otros scripts de tracking
@@ -396,7 +396,7 @@ function apus_add_script_attributes( $tag, $handle ) {
return $tag;
}
add_filter( 'script_loader_tag', 'apus_add_script_attributes', 10, 2 );
add_filter( 'script_loader_tag', 'roi_add_script_attributes', 10, 2 );
/**
* Optimizar el Heartbeat API de WordPress
@@ -406,13 +406,13 @@ add_filter( 'script_loader_tag', 'apus_add_script_attributes', 10, 2 );
*
* @since 1.0.0
*/
function apus_optimize_heartbeat() {
function roi_optimize_heartbeat() {
// Desactivar completamente en el frontend
if ( ! is_admin() ) {
wp_deregister_script( 'heartbeat' );
}
}
add_action( 'init', 'apus_optimize_heartbeat', 1 );
add_action( 'init', 'roi_optimize_heartbeat', 1 );
/**
* Modificar configuración del Heartbeat en admin
@@ -421,12 +421,12 @@ add_action( 'init', 'apus_optimize_heartbeat', 1 );
* @param array $settings Heartbeat settings.
* @return array Modified settings.
*/
function apus_modify_heartbeat_settings( $settings ) {
function roi_modify_heartbeat_settings( $settings ) {
// Cambiar intervalo de 15 segundos (default) a 60 segundos
$settings['interval'] = 60;
return $settings;
}
add_filter( 'heartbeat_settings', 'apus_modify_heartbeat_settings' );
add_filter( 'heartbeat_settings', 'roi_modify_heartbeat_settings' );
/**
* ============================================================================
@@ -449,7 +449,7 @@ add_filter( 'heartbeat_settings', 'apus_modify_heartbeat_settings' );
* @since 1.0.0
* @param WP_Query $query The WP_Query instance.
*/
function apus_optimize_main_query( $query ) {
function roi_optimize_main_query( $query ) {
// Solo en queries principales en el frontend
if ( is_admin() || ! $query->is_main_query() ) {
return;
@@ -467,7 +467,7 @@ function apus_optimize_main_query( $query ) {
}
}
}
add_action( 'pre_get_posts', 'apus_optimize_main_query' );
add_action( 'pre_get_posts', 'roi_optimize_main_query' );
/**
* Deshabilitar self-pingbacks
@@ -479,7 +479,7 @@ add_action( 'pre_get_posts', 'apus_optimize_main_query' );
* @param array $links An array of post links to ping.
* @return array Modified array without self-pings.
*/
function apus_disable_self_pingbacks( &$links ) {
function roi_disable_self_pingbacks( &$links ) {
$home = get_option( 'home' );
foreach ( $links as $l => $link ) {
if ( 0 === strpos( $link, $home ) ) {
@@ -487,7 +487,7 @@ function apus_disable_self_pingbacks( &$links ) {
}
}
}
add_action( 'pre_ping', 'apus_disable_self_pingbacks' );
add_action( 'pre_ping', 'roi_disable_self_pingbacks' );
/**
* ============================================================================
@@ -505,13 +505,13 @@ add_action( 'pre_ping', 'apus_disable_self_pingbacks' );
* @param string $src The source URL.
* @return string Modified source URL.
*/
function apus_add_font_display_swap( $src ) {
function roi_add_font_display_swap( $src ) {
if ( strpos( $src, 'fonts.googleapis.com' ) !== false ) {
$src = add_query_arg( 'display', 'swap', $src );
}
return $src;
}
add_filter( 'style_loader_src', 'apus_add_font_display_swap' );
add_filter( 'style_loader_src', 'roi_add_font_display_swap' );
/**
* Agregar width y height a imágenes para prevenir CLS
@@ -521,10 +521,10 @@ add_filter( 'style_loader_src', 'apus_add_font_display_swap' );
* @since 1.0.0
* @return bool
*/
function apus_enable_image_dimensions() {
function roi_enable_image_dimensions() {
return true;
}
add_filter( 'wp_lazy_loading_enabled', 'apus_enable_image_dimensions' );
add_filter( 'wp_lazy_loading_enabled', 'roi_enable_image_dimensions' );
/**
* Optimizar buffer de salida HTML
@@ -533,7 +533,7 @@ add_filter( 'wp_lazy_loading_enabled', 'apus_enable_image_dimensions' );
*
* @since 1.0.0
*/
function apus_enable_gzip_compression() {
function roi_enable_gzip_compression() {
// Solo en frontend
if ( is_admin() ) {
return;
@@ -552,7 +552,7 @@ function apus_enable_gzip_compression() {
}
}
}
add_action( 'template_redirect', 'apus_enable_gzip_compression', 0 );
add_action( 'template_redirect', 'roi_enable_gzip_compression', 0 );
/**
* ============================================================================
@@ -567,24 +567,24 @@ add_action( 'template_redirect', 'apus_enable_gzip_compression', 0 );
*
* @since 1.0.0
*/
function apus_cleanup_expired_transients() {
function roi_cleanup_expired_transients() {
global $wpdb;
// Eliminar transients expirados (solo los del tema)
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s AND option_value < %d",
$wpdb->esc_like( '_transient_timeout_apus_' ) . '%',
$wpdb->esc_like( '_transient_timeout_roi_' ) . '%',
time()
)
);
}
// Ejecutar limpieza semanalmente
add_action( 'apus_weekly_cleanup', 'apus_cleanup_expired_transients' );
add_action( 'roi_weekly_cleanup', 'roi_cleanup_expired_transients' );
// Registrar evento cron si no existe
if ( ! wp_next_scheduled( 'apus_weekly_cleanup' ) ) {
wp_schedule_event( time(), 'weekly', 'apus_weekly_cleanup' );
if ( ! wp_next_scheduled( 'roi_weekly_cleanup' ) ) {
wp_schedule_event( time(), 'weekly', 'roi_weekly_cleanup' );
}
/*