addInfo("Validando llamadas a roi_render_component() para: {$componentName}"); // 1. Obtener componentes registrados en functions-addon.php $registeredComponents = $this->getRegisteredComponents($themePath); $result->addInfo("Componentes registrados: " . count($registeredComponents)); // 2. Buscar todas las llamadas en templates $templateFiles = $this->getTemplateFiles($themePath); $allCalls = []; $invalidCalls = []; $unregisteredCalls = []; foreach ($templateFiles as $file) { $calls = $this->findRenderCalls($file); foreach ($calls as $call) { $allCalls[] = [ 'file' => basename($file), 'line' => $call['line'], 'component' => $call['component'] ]; // Verificar si usa underscore en lugar de guión if (strpos($call['component'], '_') !== false) { $invalidCalls[] = $call + ['file' => basename($file)]; } // Verificar si está registrado if (!in_array($call['component'], $registeredComponents)) { // Solo marcar como no registrado si no tiene underscore // (los de underscore ya se marcan como inválidos) if (strpos($call['component'], '_') === false) { $unregisteredCalls[] = $call + ['file' => basename($file)]; } } } } // 3. Verificar específicamente el componente que se está validando $componentFound = false; $componentCallsCorrect = true; foreach ($allCalls as $call) { // Buscar variantes del componente (con guión o underscore) $kebabName = $componentName; $snakeName = str_replace('-', '_', $componentName); if ($call['component'] === $kebabName) { $componentFound = true; $result->addInfo("✓ Componente '{$componentName}' llamado correctamente en {$call['file']}:{$call['line']}"); } elseif ($call['component'] === $snakeName) { $componentFound = true; $componentCallsCorrect = false; $result->addError( "Llamada incorrecta en {$call['file']}:{$call['line']}: " . "usa '{$snakeName}' (underscore) en lugar de '{$kebabName}' (kebab-case)" ); } } // 4. Reportar errores generales de formato foreach ($invalidCalls as $call) { // Solo reportar si no es el componente actual (ya se reportó arriba) $snakeName = str_replace('-', '_', $componentName); if ($call['component'] !== $snakeName) { $suggestedName = str_replace('_', '-', $call['component']); $result->addWarning( "Llamada con underscore en {$call['file']}:{$call['line']}: " . "'{$call['component']}' debería ser '{$suggestedName}'" ); } } // 5. Reportar componentes no registrados foreach ($unregisteredCalls as $call) { $result->addWarning( "Componente no registrado en {$call['file']}:{$call['line']}: '{$call['component']}'" ); } // 6. Advertir si el componente no se llama en ningún template if (!$componentFound) { $result->addWarning( "El componente '{$componentName}' no se llama en ningún template. " . "Verifica que esté incluido en single.php, header.php, footer.php u otro template." ); } // Estadísticas $result->setStat('Templates escaneados', count($templateFiles)); $result->setStat('Llamadas totales encontradas', count($allCalls)); $result->setStat('Componentes registrados', count($registeredComponents)); if (!empty($invalidCalls)) { $result->setStat('Llamadas con underscore (error)', count($invalidCalls)); } return $result; } /** * Obtiene la lista de componentes registrados en functions-addon.php */ private function getRegisteredComponents(string $themePath): array { $functionsFile = $themePath . '/functions-addon.php'; $components = []; if (!file_exists($functionsFile)) { return $components; } $content = file_get_contents($functionsFile); // Buscar patrones: case 'nombre-componente': if (preg_match_all("/case\s+'([a-z0-9-]+)':/", $content, $matches)) { $components = $matches[1]; } return array_unique($components); } /** * Obtiene los archivos de template PHP del tema */ private function getTemplateFiles(string $themePath): array { $templates = []; // Archivos principales de template $mainTemplates = [ 'header.php', 'footer.php', 'single.php', 'page.php', 'index.php', 'archive.php', 'search.php', 'sidebar.php', '404.php', 'front-page.php', 'home.php', ]; foreach ($mainTemplates as $template) { $path = $themePath . '/' . $template; if (file_exists($path)) { $templates[] = $path; } } // Buscar en template-parts/ $templatePartsDir = $themePath . '/template-parts'; if (is_dir($templatePartsDir)) { $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($templatePartsDir) ); foreach ($iterator as $file) { if ($file->isFile() && $file->getExtension() === 'php') { $templates[] = $file->getPathname(); } } } // Buscar templates personalizados (page-*.php, single-*.php) $customTemplates = glob($themePath . '/{page-*.php,single-*.php}', GLOB_BRACE); if ($customTemplates) { $templates = array_merge($templates, $customTemplates); } return $templates; } /** * Busca llamadas a roi_render_component() en un archivo */ private function findRenderCalls(string $filePath): array { $calls = []; $content = file_get_contents($filePath); $lines = explode("\n", $content); foreach ($lines as $lineNum => $line) { // Buscar: roi_render_component('nombre') o roi_render_component("nombre") if (preg_match_all("/roi_render_component\s*\(\s*['\"]([^'\"]+)['\"]\s*\)/", $line, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { $calls[] = [ 'line' => $lineNum + 1, 'component' => $match[1] ]; } } } return $calls; } }