/** * CTA A/B Testing - Tracking & Analytics * * JavaScript para tracking de clicks en el CTA con Google Analytics 4. * Registra eventos de clicks, impresiones y conversiones para cada variante. * * @package ROI_Theme * @since 1.0.0 */ (function () { 'use strict'; // Configuración global (puede ser sobrescrita por roiCTA desde WordPress) const config = window.roiCTA || { variant: null, ga_enabled: false, ga_id: '', debug_mode: false, }; /** * Log de debug (solo si está habilitado) */ function debugLog(message, data) { if (config.debug_mode) { console.log('[CTA A/B Test]', message, data || ''); } } /** * Detectar si gtag está disponible */ function isGtagAvailable() { return typeof gtag === 'function'; } /** * Enviar evento a Google Analytics 4 */ function sendGAEvent(eventName, eventParams) { if (!config.ga_enabled && !isGtagAvailable()) { debugLog('GA no disponible, evento no enviado:', {eventName, eventParams}); return; } if (isGtagAvailable()) { gtag('event', eventName, eventParams); debugLog('Evento GA4 enviado:', {eventName, eventParams}); } } /** * Track de impresión del CTA * Se ejecuta cuando el CTA es visible en el viewport */ function trackCTAImpression(variant) { sendGAEvent('cta_impression', { event_category: 'CTA', event_label: 'Variant_' + variant, variant: variant, non_interaction: true, }); debugLog('Impresión del CTA registrada', {variant}); } /** * Track de click en el botón CTA */ function trackCTAClick(variant, buttonText, targetUrl) { sendGAEvent('cta_click', { event_category: 'CTA', event_label: 'Variant_' + variant, variant: variant, button_text: buttonText, target_url: targetUrl, value: variant === 'A' ? 1 : 2, // Valor para diferenciar variantes }); debugLog('Click del CTA registrado', { variant, buttonText, targetUrl, }); } /** * Obtener la variante del CTA desde el DOM */ function getCTAVariantFromDOM() { const ctaElement = document.querySelector('[data-cta-variant]'); if (ctaElement) { return ctaElement.getAttribute('data-cta-variant'); } return null; } /** * Observador de intersección para tracking de impresiones * Solo registra cuando el CTA es visible al menos el 50% */ function setupImpressionTracking() { const ctaElement = document.querySelector('.cta-section'); if (!ctaElement) { debugLog('CTA no encontrado en el DOM'); return; } // Verificar soporte de IntersectionObserver if (!('IntersectionObserver' in window)) { debugLog('IntersectionObserver no soportado'); // Registrar impresión inmediatamente como fallback const variant = getCTAVariantFromDOM(); if (variant) { trackCTAImpression(variant); } return; } let impressionTracked = false; const observer = new IntersectionObserver( function (entries) { entries.forEach(function (entry) { // Track solo la primera vez que es visible al 50% if (entry.isIntersecting && !impressionTracked && entry.intersectionRatio >= 0.5) { const variant = getCTAVariantFromDOM(); if (variant) { trackCTAImpression(variant); impressionTracked = true; } } }); }, { threshold: 0.5, // Visible al menos 50% rootMargin: '0px', } ); observer.observe(ctaElement); debugLog('IntersectionObserver configurado para el CTA'); } /** * Setup de tracking de clicks en botones CTA */ function setupClickTracking() { const ctaButtons = document.querySelectorAll('.cta-button[data-cta-variant]'); if (ctaButtons.length === 0) { debugLog('No se encontraron botones CTA para tracking'); return; } debugLog('Configurando tracking para ' + ctaButtons.length + ' botón(es) CTA'); ctaButtons.forEach(function (button) { button.addEventListener('click', function (e) { const variant = this.getAttribute('data-cta-variant'); const buttonText = this.textContent.trim(); const targetUrl = this.getAttribute('href'); trackCTAClick(variant, buttonText, targetUrl); // Si el enlace es válido, permitir navegación normal // Si no, prevenir default (útil para enlaces # o modal triggers) if (!targetUrl || targetUrl === '#' || targetUrl === 'javascript:void(0)') { e.preventDefault(); debugLog('Navegación prevenida (URL inválida o #)'); } }); }); debugLog('Click tracking configurado exitosamente'); } /** * Obtener variante desde cookie (si existe) * Esta función es útil para validar el comportamiento del A/B test */ function getCTAVariantFromCookie() { const name = 'roicta_variant='; const decodedCookie = decodeURIComponent(document.cookie); const cookieArray = decodedCookie.split(';'); for (let i = 0; i < cookieArray.length; i++) { let cookie = cookieArray[i].trim(); if (cookie.indexOf(name) === 0) { return cookie.substring(name.length, cookie.length); } } return null; } /** * Validar que la variante mostrada coincida con la cookie */ function validateVariantConsistency() { const domVariant = getCTAVariantFromDOM(); const cookieVariant = getCTAVariantFromCookie(); if (cookieVariant && domVariant && domVariant !== cookieVariant) { debugLog('⚠️ ADVERTENCIA: Inconsistencia de variante detectada!', { dom: domVariant, cookie: cookieVariant, }); } else if (domVariant) { debugLog('✓ Variante consistente:', domVariant); } } /** * Agregar clase de animación al CTA (opcional) */ function animateCTA() { const ctaElement = document.querySelector('.cta-section'); if (ctaElement) { ctaElement.classList.add('fade-in-up'); } } /** * Inicialización principal */ function init() { debugLog('Inicializando CTA A/B Testing Tracking', config); // Validar consistencia de variantes validateVariantConsistency(); // Setup tracking de impresiones setupImpressionTracking(); // Setup tracking de clicks setupClickTracking(); // Animar CTA (opcional) animateCTA(); debugLog('CTA A/B Testing Tracking inicializado correctamente'); } /** * Esperar a que el DOM esté listo */ if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { // DOM ya está listo init(); } /** * API pública (opcional, para debugging o extensiones) */ window.roiTATracking = { trackClick: trackCTAClick, trackImpression: trackCTAImpression, getVariant: getCTAVariantFromDOM, config: config, }; debugLog('API pública expuesta en window.roiTATracking'); })();