fix(adsense): Anchor ocultos por defecto + más tamaños Vignette

Anchor Ads:
- Ocultos por defecto via CSS (opacity: 0, visibility: hidden)
- Solo se muestran cuando AdSense llena el slot (clase .ad-loaded)
- Ya no aparece espacio en blanco si no hay anuncio

Vignette Ads:
- Agregados tamaños: 728x90, 970x250, 970x90, 468x60, 320x100
- Nueva opción "auto" (recomendado) para formato automático
- Renderer actualizado para manejar todos los tamaños

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
FrankZamora
2025-11-28 21:25:54 -06:00
parent 1f0ce58b22
commit 13beaf7b06
3 changed files with 57 additions and 28 deletions

View File

@@ -639,10 +639,20 @@ final class AdsensePlacementFormBuilder
// Tamano y opacidad // Tamano y opacidad
$html .= '<div class="row g-2 mt-2">'; $html .= '<div class="row g-2 mt-2">';
$html .= ' <div class="col-6">'; $html .= ' <div class="col-6">';
$size = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_size', '300x250'); $size = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_size', 'auto');
$html .= $this->buildSelect($cid . 'VignetteSize', 'Tamano', $html .= $this->buildSelect($cid . 'VignetteSize', 'Tamano',
(string)$size, (string)$size,
['300x250' => '300x250', '336x280' => '336x280', 'responsive' => 'Responsive'] [
'auto' => 'Auto (recomendado)',
'300x250' => '300x250 (Rectangle)',
'336x280' => '336x280 (Large Rectangle)',
'728x90' => '728x90 (Leaderboard)',
'970x250' => '970x250 (Billboard)',
'970x90' => '970x90 (Large Leaderboard)',
'468x60' => '468x60 (Banner)',
'320x100' => '320x100 (Large Mobile)',
'responsive' => 'Responsive (fluid)',
]
); );
$html .= ' </div>'; $html .= ' </div>';
$html .= ' <div class="col-6">'; $html .= ' <div class="col-6">';

View File

@@ -593,7 +593,7 @@ final class AdsensePlacementRenderer
// === CSS via CSSGenerator === // === CSS via CSSGenerator ===
$cssRules = []; $cssRules = [];
// Base anchor styles // Base anchor styles - OCULTO POR DEFECTO hasta que AdSense llene el slot
$cssRules[] = $this->cssGenerator->generate('.roi-anchor-ad', [ $cssRules[] = $this->cssGenerator->generate('.roi-anchor-ad', [
'position' => 'fixed', 'position' => 'fixed',
'left' => '0', 'left' => '0',
@@ -606,6 +606,16 @@ final class AdsensePlacementRenderer
'display' => 'flex', 'display' => 'flex',
'align-items' => 'center', 'align-items' => 'center',
'justify-content' => 'center', 'justify-content' => 'center',
'opacity' => '0',
'visibility' => 'hidden',
'pointer-events' => 'none',
]);
// Mostrar anchor cuando AdSense llena el slot
$cssRules[] = $this->cssGenerator->generate('.roi-anchor-ad.ad-loaded', [
'opacity' => '1',
'visibility' => 'visible',
'pointer-events' => 'auto',
]); ]);
$cssRules[] = $this->cssGenerator->generate('.roi-anchor-ad-top', [ $cssRules[] = $this->cssGenerator->generate('.roi-anchor-ad-top', [
@@ -884,11 +894,13 @@ final class AdsensePlacementRenderer
$html = "<style id=\"roi-vignette-css\">{$css}</style>\n"; $html = "<style id=\"roi-vignette-css\">{$css}</style>\n";
// Determinar estilo de anuncio segun tamano // Determinar estilo de anuncio segun tamano
$adStyle = $size === 'responsive' if ($size === 'auto' || $size === 'responsive') {
? 'display:block;min-width:300px;min-height:250px' $adStyle = 'display:block;min-width:300px;min-height:250px';
: sprintf('display:inline-block;width:%dpx;height:%dpx', $adWidth, $adHeight); $adFormat = ' data-ad-format="auto" data-full-width-responsive="true"';
} else {
$adFormat = $size === 'responsive' ? ' data-ad-format="auto" data-full-width-responsive="true"' : ''; $adStyle = sprintf('display:inline-block;width:%dpx;height:%dpx', $adWidth, $adHeight);
$adFormat = '';
}
$closeDelayClass = $closeDelay > 0 ? ' delayed' : ''; $closeDelayClass = $closeDelay > 0 ? ' delayed' : '';
@@ -937,6 +949,12 @@ final class AdsensePlacementRenderer
return match($size) { return match($size) {
'300x250' => [300, 250], '300x250' => [300, 250],
'336x280' => [336, 280], '336x280' => [336, 280],
'728x90' => [728, 90],
'970x250' => [970, 250],
'970x90' => [970, 90],
'468x60' => [468, 60],
'320x100' => [320, 100],
'auto', 'responsive' => [0, 0], // Tamaños dinamicos
default => [300, 250], default => [300, 250],
}; };
} }

View File

@@ -87,28 +87,35 @@
// ===================================================== // =====================================================
/** /**
* Observa los slots de AdSense y oculta el contenedor si no se llena * Observa los slots de AdSense y MUESTRA el contenedor solo cuando se llena
* AdSense agrega data-ad-status="unfilled" cuando no hay anuncio * Los anchors estan OCULTOS por defecto via CSS
* AdSense agrega data-ad-status="filled" cuando hay anuncio
*/ */
function watchUnfilledAds(containers) { function watchAdStatus(containers) {
containers.forEach(function(container) { containers.forEach(function(container) {
var ins = container.querySelector('ins.adsbygoogle'); var ins = container.querySelector('ins.adsbygoogle');
if (!ins) return; if (!ins) return;
// Funcion para mostrar el anchor cuando el ad esta listo
function showIfFilled() {
var status = ins.getAttribute('data-ad-status');
if (status === 'filled') {
container.classList.add('ad-loaded');
return true;
}
return false;
}
// Verificar si ya tiene estado (por si ya cargo) // Verificar si ya tiene estado (por si ya cargo)
var status = ins.getAttribute('data-ad-status'); if (showIfFilled()) {
if (status === 'unfilled') {
container.classList.add('hidden');
return; return;
} }
// Usar MutationObserver para detectar cambios // Usar MutationObserver para detectar cuando AdSense llena el slot
var observer = new MutationObserver(function(mutations) { var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) { mutations.forEach(function(mutation) {
if (mutation.type === 'attributes' && mutation.attributeName === 'data-ad-status') { if (mutation.type === 'attributes' && mutation.attributeName === 'data-ad-status') {
var newStatus = ins.getAttribute('data-ad-status'); if (showIfFilled()) {
if (newStatus === 'unfilled') {
container.classList.add('hidden');
observer.disconnect(); observer.disconnect();
} }
} }
@@ -120,15 +127,9 @@
attributeFilter: ['data-ad-status'] attributeFilter: ['data-ad-status']
}); });
// Timeout de seguridad: si despues de 5s no hay contenido, ocultar // Timeout de seguridad: despues de 5s desconectar observer
// Si no se lleno, el anchor permanece oculto (comportamiento deseado)
setTimeout(function() { setTimeout(function() {
var adStatus = ins.getAttribute('data-ad-status');
// Si no tiene status o esta unfilled, y no tiene contenido real
if (!adStatus || adStatus === 'unfilled') {
if (ins.innerHTML.length < 100) {
container.classList.add('hidden');
}
}
observer.disconnect(); observer.disconnect();
}, 5000); }, 5000);
}); });
@@ -157,8 +158,8 @@
} }
}); });
// Ocultar anchors cuando AdSense no llena el slot // Mostrar anchors solo cuando AdSense llene el slot (ocultos por defecto via CSS)
watchUnfilledAds(anchors); watchAdStatus(anchors);
// Event delegation para botones // Event delegation para botones
document.addEventListener('click', function(e) { document.addEventListener('click', function(e) {