- Agregar KPIs con tendencias vs período anterior (↑↓% comparativo) - Implementar secciones de recomendaciones: Contenido a Crear, CTR 0%, Quick Wins, Contenido Estrella, Contenido en Decadencia - Convertir listados a tablas con columnas separadas para mejor legibilidad - Agregar botones Editar + Ver en todas las tablas de posts - Ocultar secciones vacías dinámicamente (Búsquedas Sin Resultados) - Relajar criterios Quick Wins: pos 2-15, CTR ≥2%, búsquedas ≥2 - Incluir distribución de clicks por posición con barras de progreso - Agregar exportación a Markdown para análisis con IA Archivos nuevos: - admin/class-analytics-dashboard.php (UI del dashboard) - admin/class-metrics-repository.php (queries de métricas) - admin/assets/dashboard.css (estilos Bootstrap 5) - admin/assets/dashboard.js (interactividad y export) - sql/create-indices.sql (índices para optimización) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
234 lines
8.8 KiB
JavaScript
234 lines
8.8 KiB
JavaScript
/**
|
|
* ROI APU Search - Analytics Dashboard Scripts
|
|
*
|
|
* @package ROI_APU_Search
|
|
* @since 1.2.0
|
|
*/
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
/**
|
|
* Initialize Bootstrap tooltips
|
|
*/
|
|
function initTooltips() {
|
|
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
|
if (tooltipTriggerList.length > 0 && typeof bootstrap !== 'undefined') {
|
|
[...tooltipTriggerList].map(el => new bootstrap.Tooltip(el));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Copy markdown to clipboard
|
|
* Implementation in FASE 9
|
|
*/
|
|
function copyMarkdown() {
|
|
const markdown = generateMarkdown();
|
|
|
|
navigator.clipboard.writeText(markdown).then(function() {
|
|
showSuccessMessage('Copiado: El resumen está en tu portapapeles.');
|
|
}).catch(function(err) {
|
|
console.error('Error al copiar:', err);
|
|
showErrorMessage('Error al copiar al portapapeles.');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generate comprehensive markdown report from dashboard data (v2)
|
|
*/
|
|
function generateMarkdown() {
|
|
const data = window.roiApuDashboardData;
|
|
if (!data) {
|
|
return '# Error: No hay datos disponibles';
|
|
}
|
|
|
|
let md = '';
|
|
|
|
// Header
|
|
md += '# Reporte Analytics - Buscador APUs\n\n';
|
|
md += `**Período**: Últimos ${data.period} días\n`;
|
|
md += `**Generado**: ${data.generated}\n`;
|
|
md += `**Sitio**: ${data.siteUrl}\n\n`;
|
|
|
|
// KPIs Table
|
|
md += '## Métricas Clave\n\n';
|
|
md += '| Métrica | Valor |\n';
|
|
md += '|---------|-------|\n';
|
|
md += `| Búsquedas totales | ${data.kpis.totalBusquedas} |\n`;
|
|
md += `| CTR (Click-Through Rate) | ${data.kpis.ctr} |\n`;
|
|
md += `| Búsquedas sin resultados | ${data.kpis.sinResultados} |\n`;
|
|
md += `| Posición promedio clicks | ${data.kpis.posProm} |\n\n`;
|
|
|
|
// Click Distribution
|
|
if (data.clickDistribution && data.clickDistribution.length > 0) {
|
|
md += '## Distribución de Clicks por Posición\n\n';
|
|
md += '| Posición | Clicks | Porcentaje |\n';
|
|
md += '|----------|--------|------------|\n';
|
|
data.clickDistribution.forEach(function(dist) {
|
|
md += `| ${dist.posicion} | ${dist.clicks} | ${dist.porcentaje}% |\n`;
|
|
});
|
|
md += '\n';
|
|
}
|
|
|
|
md += '---\n\n';
|
|
md += '## RECOMENDACIONES ACCIONABLES\n\n';
|
|
|
|
// 🔴 Urgent: Zero Results
|
|
if (data.zeroResults && data.zeroResults.length > 0) {
|
|
md += '### 🔴 ACCIÓN URGENTE: Contenido a Crear\n\n';
|
|
md += 'Los usuarios buscan esto pero NO encuentran resultados:\n\n';
|
|
md += '| Término | Frecuencia |\n';
|
|
md += '|---------|------------|\n';
|
|
data.zeroResults.forEach(function(term) {
|
|
md += `| ${term.term} | ${term.frecuencia} veces |\n`;
|
|
});
|
|
md += '\n**Acción**: Crear APUs o contenido para estos términos.\n\n';
|
|
}
|
|
|
|
// 🟡 CTR 0% Section
|
|
if (data.ctrZero && data.ctrZero.length > 0) {
|
|
md += '### 🟡 REVISAR: Títulos con CTR 0%\n\n';
|
|
md += 'Estos términos tienen resultados pero nadie hace click:\n\n';
|
|
md += '| Término | Búsquedas | Resultados |\n';
|
|
md += '|---------|-----------|------------|\n';
|
|
data.ctrZero.forEach(function(term) {
|
|
md += `| ${term.term} | ${term.busquedas} | ${term.resultados} |\n`;
|
|
});
|
|
md += '\n**Acción**: Mejorar títulos y descripciones de los APUs mostrados.\n\n';
|
|
}
|
|
|
|
// 🎯 Quick Wins
|
|
if (data.quickWins && data.quickWins.length > 0) {
|
|
md += '### 🎯 QUICK WINS: Oportunidades Fáciles\n\n';
|
|
md += 'Términos en posición 4-10 con buen CTR (una pequeña mejora = top 3):\n\n';
|
|
md += '| Término | Búsquedas | CTR | Pos. Actual |\n';
|
|
md += '|---------|-----------|-----|-------------|\n';
|
|
data.quickWins.forEach(function(term) {
|
|
md += `| ${term.term} | ${term.busquedas} | ${term.ctr}% | ${term.posProm} |\n`;
|
|
});
|
|
md += '\n**Acción**: Optimizar estos APUs para subir al top 3.\n\n';
|
|
}
|
|
|
|
// 📉 Decay Content
|
|
if (data.decayContent && data.decayContent.length > 0) {
|
|
md += '### 📉 ATENCIÓN: Contenido en Decadencia\n\n';
|
|
md += 'Posts que perdieron >20% clicks vs período anterior:\n\n';
|
|
md += '| Título | Cambio | Clicks (antes → ahora) |\n';
|
|
md += '|--------|--------|------------------------|\n';
|
|
data.decayContent.forEach(function(post) {
|
|
md += `| [${post.title}](${post.url}) | ${post.cambioPct}% | ${post.clicksAnterior} → ${post.clicksActual} |\n`;
|
|
});
|
|
md += '\n**Acción**: Revisar si el contenido está desactualizado.\n\n';
|
|
}
|
|
|
|
// 🟢 Star Content
|
|
if (data.contenidoEstrella && data.contenidoEstrella.length > 0) {
|
|
md += '### 🟢 MANTENER: Tu Contenido Estrella\n\n';
|
|
md += 'Posts con más clicks - mantén este contenido actualizado:\n\n';
|
|
md += '| Título | Clicks | Pos. Prom. |\n';
|
|
md += '|--------|--------|------------|\n';
|
|
data.contenidoEstrella.forEach(function(post) {
|
|
md += `| [${post.title}](${post.url}) | ${post.clicks} | ${post.posProm} |\n`;
|
|
});
|
|
md += '\n**Acción**: Mantener actualizado y considerar contenido relacionado.\n\n';
|
|
}
|
|
|
|
// Infraposicionados Section
|
|
if (data.infraposicionados && data.infraposicionados.length > 0) {
|
|
md += '### 🔼 OPORTUNIDAD: Posts Infraposicionados\n\n';
|
|
md += 'Estos posts reciben clicks pero aparecen muy abajo:\n\n';
|
|
md += '| Título | Clicks | Pos. Prom. |\n';
|
|
md += '|--------|--------|------------|\n';
|
|
data.infraposicionados.forEach(function(post) {
|
|
md += `| ${post.title} | ${post.clicks} | ${post.posProm} |\n`;
|
|
});
|
|
md += '\n**Acción**: Mejorar scoring o relevancia de estos APUs.\n\n';
|
|
}
|
|
|
|
md += '---\n\n';
|
|
|
|
// Summary stats
|
|
md += '## Resumen de Datos\n\n';
|
|
md += `- **Términos únicos buscados**: ${data.totals.searches}\n`;
|
|
md += `- **Posts con clicks**: ${data.totals.clicks}\n`;
|
|
md += `- **Términos sin resultados**: ${data.totals.zeroResults}\n\n`;
|
|
|
|
// Questions for analysis
|
|
md += '## Preguntas para Análisis con IA\n\n';
|
|
md += '1. ¿Qué contenido debería crear primero basándome en las búsquedas sin resultados?\n';
|
|
md += '2. ¿Por qué algunos términos tienen resultados pero CTR 0%? ¿Qué puedo mejorar?\n';
|
|
md += '3. ¿Cómo optimizo los Quick Wins para llegar al top 3?\n';
|
|
md += '4. ¿Qué patrones veo en mi contenido estrella que debería replicar?\n';
|
|
md += '5. ¿Hay contenido en decadencia que debería actualizar urgentemente?\n\n';
|
|
|
|
// Footer
|
|
md += '---\n';
|
|
md += '*Generado por ROI APU Search Dashboard v2*\n';
|
|
md += '*Comparte este reporte con Claude para obtener recomendaciones detalladas.*\n';
|
|
|
|
return md;
|
|
}
|
|
|
|
/**
|
|
* Show success message
|
|
*/
|
|
function showSuccessMessage(message) {
|
|
const container = document.getElementById('alertContainer');
|
|
if (!container) return;
|
|
|
|
container.innerHTML = `
|
|
<div class="admin-notice notice-success mb-3" role="alert">
|
|
<i class="bi bi-check-circle me-2"></i>
|
|
<strong>${message}</strong>
|
|
</div>
|
|
`;
|
|
|
|
// Auto-hide after 3 seconds
|
|
setTimeout(function() {
|
|
container.innerHTML = '';
|
|
}, 3000);
|
|
}
|
|
|
|
/**
|
|
* Show error message
|
|
*/
|
|
function showErrorMessage(message) {
|
|
const container = document.getElementById('alertContainer');
|
|
if (!container) return;
|
|
|
|
container.innerHTML = `
|
|
<div class="admin-notice notice-error mb-3" role="alert">
|
|
<i class="bi bi-exclamation-circle me-2"></i>
|
|
<strong>${message}</strong>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* Initialize dashboard
|
|
*/
|
|
function init() {
|
|
initTooltips();
|
|
|
|
// Bind export button
|
|
const exportBtn = document.getElementById('btn-export-md');
|
|
if (exportBtn) {
|
|
exportBtn.addEventListener('click', copyMarkdown);
|
|
}
|
|
}
|
|
|
|
// Initialize when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
|
|
// Expose functions globally for debugging
|
|
window.roiApuDashboard = {
|
|
copyMarkdown: copyMarkdown,
|
|
initTooltips: initTooltips
|
|
};
|
|
|
|
})();
|