fix(js): implement google official css for unfilled adsense slots
Remove eager loading, revert to Intersection Observer with 600px
rootMargin. Use google css: ins[data-ad-status=unfilled]{display:none}
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,10 +18,15 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuracion por defecto, sobrescrita por window.roiAdsenseConfig
|
* Configuracion por defecto, sobrescrita por window.roiAdsenseConfig
|
||||||
|
*
|
||||||
|
* rootMargin: 600px precarga slots 600px antes de entrar al viewport.
|
||||||
|
* Esto da tiempo suficiente para que AdSense cargue el anuncio antes
|
||||||
|
* de que el usuario llegue al slot, evitando layout shift.
|
||||||
|
* Basado en best practices: https://support.google.com/adsense/answer/10762946
|
||||||
*/
|
*/
|
||||||
var DEFAULT_CONFIG = {
|
var DEFAULT_CONFIG = {
|
||||||
lazyEnabled: true,
|
lazyEnabled: true,
|
||||||
rootMargin: '200px 0px',
|
rootMargin: '600px 0px',
|
||||||
fillTimeout: 5000,
|
fillTimeout: 5000,
|
||||||
debug: false
|
debug: false
|
||||||
};
|
};
|
||||||
@@ -593,33 +598,19 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
|
||||||
// EAGER LOADING (ACTIVACION INMEDIATA)
|
|
||||||
// =========================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activa todos los slots inmediatamente sin esperar viewport.
|
|
||||||
* Los slots inician colapsados (CSS) y solo se expanden si reciben anuncio.
|
|
||||||
* Esto evita layout shift porque el usuario nunca ve espacios vacios.
|
|
||||||
*/
|
|
||||||
function activateAllSlotsEagerly() {
|
|
||||||
var slots = document.querySelectorAll('.roi-ad-slot[data-ad-lazy="true"]');
|
|
||||||
debugLog('Activando ' + slots.length + ' slots de manera eager');
|
|
||||||
|
|
||||||
slots.forEach(function(slot, index) {
|
|
||||||
// Pequeño delay escalonado para no saturar AdSense
|
|
||||||
setTimeout(function() {
|
|
||||||
activateSlot(slot);
|
|
||||||
}, index * 100); // 100ms entre cada slot
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// INICIALIZACION
|
// INICIALIZACION
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inicializa el sistema
|
* Inicializa el sistema
|
||||||
|
*
|
||||||
|
* ESTRATEGIA v2.2 (basada en documentacion oficial de Google):
|
||||||
|
* - Los slots NO estan ocultos inicialmente (Google puede no ejecutar requests para slots ocultos)
|
||||||
|
* - Usamos Intersection Observer con rootMargin grande (600px) para precargar
|
||||||
|
* - Google automaticamente oculta slots unfilled via CSS: ins[data-ad-status="unfilled"]
|
||||||
|
* - Nuestro CSS colapsa el contenedor .roi-ad-slot cuando el ins tiene unfilled
|
||||||
|
* - Esto funciona MEJOR que eager loading porque no satura AdSense con requests simultaneos
|
||||||
*/
|
*/
|
||||||
function init() {
|
function init() {
|
||||||
// Siempre configurar listener para ads dinamicos
|
// Siempre configurar listener para ads dinamicos
|
||||||
@@ -632,8 +623,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
debugLog('Inicializando AdSense Lazy Loader v2.1 (Eager Mode)');
|
debugLog('Inicializando AdSense Lazy Loader v2.2 (IO + Google Official CSS)');
|
||||||
debugLog('Config: lazyEnabled=' + CONFIG.lazyEnabled + ', fillTimeout=' + CONFIG.fillTimeout);
|
debugLog('Config: lazyEnabled=' + CONFIG.lazyEnabled + ', rootMargin=' + CONFIG.rootMargin + ', fillTimeout=' + CONFIG.fillTimeout);
|
||||||
|
|
||||||
// Decidir modo de operacion
|
// Decidir modo de operacion
|
||||||
if (!CONFIG.lazyEnabled) {
|
if (!CONFIG.lazyEnabled) {
|
||||||
@@ -642,20 +633,26 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NUEVA ESTRATEGIA: Eager loading
|
// Verificar soporte para Intersection Observer
|
||||||
// En lugar de esperar a que los slots entren al viewport (lo cual causa
|
if (!hasIntersectionObserverSupport()) {
|
||||||
// layout shift cuando se ocultan slots vacios), activamos todos los slots
|
debugLog('Sin soporte IO, usando modo legacy', 'warn');
|
||||||
// inmediatamente. Los slots inician colapsados via CSS y solo se expanden
|
initLegacyMode();
|
||||||
// cuando AdSense confirma que tienen anuncio (filled).
|
return;
|
||||||
// Esto elimina completamente el layout shift.
|
}
|
||||||
debugLog('Usando modo eager: activar todos los slots inmediatamente');
|
|
||||||
|
|
||||||
// Esperar a que el DOM este listo
|
// Inicializar Intersection Observer
|
||||||
|
if (!initIntersectionObserver()) {
|
||||||
|
debugLog('Fallo inicializando IO, usando modo legacy', 'warn');
|
||||||
|
initLegacyMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Esperar a que el DOM este listo y observar slots
|
||||||
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
||||||
activateAllSlotsEagerly();
|
observeAllSlots();
|
||||||
} else {
|
} else {
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
activateAllSlotsEagerly();
|
observeAllSlots();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,56 +66,59 @@ final class AdsensePlacementRenderer
|
|||||||
// 4. Generar CSS (usando CSSGeneratorService)
|
// 4. Generar CSS (usando CSSGeneratorService)
|
||||||
$lazyEnabled = ($settings['behavior']['lazy_loading_enabled'] ?? true) === true;
|
$lazyEnabled = ($settings['behavior']['lazy_loading_enabled'] ?? true) === true;
|
||||||
|
|
||||||
// Estrategia para evitar layout shift:
|
// Estrategia basada en documentación oficial de Google AdSense:
|
||||||
// - Los slots inician colapsados (max-height:0) sin ocupar espacio visual
|
// https://support.google.com/adsense/answer/10762946
|
||||||
// - Usamos max-height en vez de height para que IO pueda detectarlos
|
//
|
||||||
// - Se pre-cargan con rootMargin grande (1000px) antes de ser visibles
|
// IMPORTANTE: NO ocultar slots inicialmente porque AdSense puede no
|
||||||
// - Solo se expanden cuando AdSense confirma que hay anuncio (filled)
|
// ejecutar la solicitud de anuncios para slots ocultos.
|
||||||
// - Si no hay anuncio (unfilled), permanecen colapsados
|
//
|
||||||
// - Esto evita que el usuario vea espacios que luego desaparecen
|
// La solución correcta es:
|
||||||
if ($lazyEnabled) {
|
// 1. Mostrar slots con min-height para reservar espacio (evita CLS)
|
||||||
|
// 2. Usar CSS oficial de Google para ocultar slots unfilled:
|
||||||
|
// ins.adsbygoogle[data-ad-status="unfilled"] { display: none !important; }
|
||||||
|
// 3. El contenedor colapsa automáticamente cuando el ins se oculta
|
||||||
|
|
||||||
|
// CSS base para todos los slots
|
||||||
$css = $this->cssGenerator->generate(
|
$css = $this->cssGenerator->generate(
|
||||||
".roi-ad-slot",
|
".roi-ad-slot",
|
||||||
[
|
[
|
||||||
'max_height' => '0',
|
|
||||||
'overflow' => 'hidden',
|
|
||||||
'opacity' => '0',
|
|
||||||
'width' => '100%',
|
'width' => '100%',
|
||||||
'min_width' => '300px',
|
'min_width' => '300px',
|
||||||
'text_align' => 'center',
|
|
||||||
'margin' => '0',
|
|
||||||
'padding' => '0',
|
|
||||||
'transition' => 'max-height 0.3s ease, opacity 0.3s ease, margin 0.3s ease',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
// Slots con anuncio confirmado: se expanden y muestran
|
|
||||||
$css .= $this->cssGenerator->generate('.roi-ad-slot.roi-ad-filled', [
|
|
||||||
'max_height' => '600px',
|
|
||||||
'opacity' => '1',
|
|
||||||
'overflow' => 'visible',
|
|
||||||
'margin_top' => '1.5rem',
|
'margin_top' => '1.5rem',
|
||||||
'margin_bottom' => '1.5rem',
|
'margin_bottom' => '1.5rem',
|
||||||
]);
|
'text_align' => 'center',
|
||||||
// Slots vacios: permanecen colapsados sin ocupar espacio
|
'min_height' => '100px', // Reservar espacio mínimo para evitar CLS
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Solución oficial de Google para ocultar slots sin anuncios
|
||||||
|
// Ref: https://support.google.com/adsense/answer/10762946
|
||||||
|
$css .= $this->cssGenerator->generate(
|
||||||
|
"ins.adsbygoogle[data-ad-status='unfilled']",
|
||||||
|
[
|
||||||
|
'display' => 'none !important',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Cuando el ins está oculto, colapsar el contenedor también
|
||||||
|
// Usamos :has() para detectar cuando el ins hijo está unfilled
|
||||||
|
// Nota: :has() tiene buen soporte en navegadores modernos (2023+)
|
||||||
|
$css .= $this->cssGenerator->generate(
|
||||||
|
".roi-ad-slot:has(ins.adsbygoogle[data-ad-status='unfilled'])",
|
||||||
|
[
|
||||||
|
'min_height' => '0',
|
||||||
|
'margin' => '0',
|
||||||
|
'padding' => '0',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fallback para navegadores sin soporte :has() - usar clase JS
|
||||||
$css .= $this->cssGenerator->generate('.roi-ad-slot.roi-ad-empty', [
|
$css .= $this->cssGenerator->generate('.roi-ad-slot.roi-ad-empty', [
|
||||||
'max_height' => '0',
|
'min_height' => '0',
|
||||||
'opacity' => '0',
|
|
||||||
'margin' => '0',
|
'margin' => '0',
|
||||||
'padding' => '0',
|
'padding' => '0',
|
||||||
|
'display' => 'none',
|
||||||
]);
|
]);
|
||||||
} else {
|
|
||||||
// Modo legacy: slots siempre visibles
|
|
||||||
$css = $this->cssGenerator->generate(
|
|
||||||
".roi-ad-slot",
|
|
||||||
[
|
|
||||||
'width' => '100%',
|
|
||||||
'min_width' => '300px',
|
|
||||||
'margin_top' => '1.5rem',
|
|
||||||
'margin_bottom' => '1.5rem',
|
|
||||||
'text_align' => 'center',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Generar HTML del anuncio
|
// 5. Generar HTML del anuncio
|
||||||
$html = $this->buildAdHTML(
|
$html = $this->buildAdHTML(
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ if (!defined('ABSPATH')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Definir constante de versión del tema
|
// Definir constante de versión del tema
|
||||||
define('ROI_VERSION', '1.0.26');
|
define('ROI_VERSION', '1.0.27');
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// 1. CARGAR AUTOLOADER MANUAL
|
// 1. CARGAR AUTOLOADER MANUAL
|
||||||
|
|||||||
Reference in New Issue
Block a user