feat(adsense): implementar Anchor Ads y Vignette Ads
- Anchor Ads: anuncios fijos top/bottom con botones minimizar/cerrar - Vignette Ads: modal fullscreen con triggers configurables - Schema v1.3.0 con grupos anchor_ads y vignette_ads (18 campos) - FieldMapper actualizado para persistir settings en BD - JavaScript para interacción (colapso, cierre, localStorage) - Soporte para responsive y tamaños fijos en vignette IMPORTANTE: Ejecutar en servidor remoto: wp roi-theme sync-component adsense-placement 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -73,6 +73,28 @@ final class AdsensePlacementFieldMapper implements FieldMapperInterface
|
||||
'adsense-placementMinContentLength' => ['group' => 'forms', 'attribute' => 'min_content_length'],
|
||||
'adsense-placementDelayEnabled' => ['group' => 'forms', 'attribute' => 'delay_enabled'],
|
||||
'adsense-placementDelayTimeout' => ['group' => 'forms', 'attribute' => 'delay_timeout'],
|
||||
|
||||
// ANCHOR ADS
|
||||
'adsense-placementAnchorEnabled' => ['group' => 'anchor_ads', 'attribute' => 'anchor_enabled'],
|
||||
'adsense-placementAnchorPosition' => ['group' => 'anchor_ads', 'attribute' => 'anchor_position'],
|
||||
'adsense-placementAnchorHeight' => ['group' => 'anchor_ads', 'attribute' => 'anchor_height'],
|
||||
'adsense-placementAnchorCollapsibleEnabled' => ['group' => 'anchor_ads', 'attribute' => 'anchor_collapsible_enabled'],
|
||||
'adsense-placementAnchorShowOnMobile' => ['group' => 'anchor_ads', 'attribute' => 'anchor_show_on_mobile'],
|
||||
'adsense-placementAnchorShowOnWideScreens' => ['group' => 'anchor_ads', 'attribute' => 'anchor_show_on_wide_screens'],
|
||||
'adsense-placementAnchorRememberState' => ['group' => 'anchor_ads', 'attribute' => 'anchor_remember_state'],
|
||||
'adsense-placementAnchorRememberDuration' => ['group' => 'anchor_ads', 'attribute' => 'anchor_remember_duration'],
|
||||
|
||||
// VIGNETTE ADS
|
||||
'adsense-placementVignetteEnabled' => ['group' => 'vignette_ads', 'attribute' => 'vignette_enabled'],
|
||||
'adsense-placementVignetteTrigger' => ['group' => 'vignette_ads', 'attribute' => 'vignette_trigger'],
|
||||
'adsense-placementVignetteTriggerDelay' => ['group' => 'vignette_ads', 'attribute' => 'vignette_trigger_delay'],
|
||||
'adsense-placementVignetteSize' => ['group' => 'vignette_ads', 'attribute' => 'vignette_size'],
|
||||
'adsense-placementVignetteOverlayOpacity' => ['group' => 'vignette_ads', 'attribute' => 'vignette_overlay_opacity'],
|
||||
'adsense-placementVignetteShowOnMobile' => ['group' => 'vignette_ads', 'attribute' => 'vignette_show_on_mobile'],
|
||||
'adsense-placementVignetteShowOnDesktop' => ['group' => 'vignette_ads', 'attribute' => 'vignette_show_on_desktop'],
|
||||
'adsense-placementVignetteReshowEnabled' => ['group' => 'vignette_ads', 'attribute' => 'vignette_reshow_enabled'],
|
||||
'adsense-placementVignetteReshowTime' => ['group' => 'vignette_ads', 'attribute' => 'vignette_reshow_time'],
|
||||
'adsense-placementVignetteMaxPerSession' => ['group' => 'vignette_ads', 'attribute' => 'vignette_max_per_session'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ final class AdsensePlacementFormBuilder
|
||||
$html .= $this->buildCredentialsGroup($componentId);
|
||||
$html .= $this->buildAnalyticsGroup($componentId);
|
||||
$html .= $this->buildRailAdsGroup($componentId);
|
||||
$html .= $this->buildAnchorAdsGroup($componentId);
|
||||
$html .= $this->buildVignetteAdsGroup($componentId);
|
||||
$html .= $this->buildExclusionsGroup($componentId);
|
||||
$html .= ' </div>';
|
||||
|
||||
@@ -114,6 +116,11 @@ final class AdsensePlacementFormBuilder
|
||||
// Diagrama visual del layout
|
||||
$html .= '<div class="border rounded p-3" style="background: #f8f9fa; font-family: monospace; font-size: 11px;">';
|
||||
|
||||
// Anchor Top
|
||||
$html .= '<div class="text-center p-2 mb-1 rounded" style="background: #d1ecf1; border: 2px solid #17a2b8;">';
|
||||
$html .= ' <i class="bi bi-pin-angle"></i> <strong>ANCHOR TOP</strong> (fijo, collapsible)';
|
||||
$html .= '</div>';
|
||||
|
||||
// Header
|
||||
$html .= '<div class="text-center p-2 mb-1 rounded" style="background: #e9ecef; border: 1px dashed #6c757d;">';
|
||||
$html .= ' <strong>HEADER</strong>';
|
||||
@@ -169,10 +176,15 @@ final class AdsensePlacementFormBuilder
|
||||
$html .= '</div>';
|
||||
|
||||
// Footer
|
||||
$html .= '<div class="text-center p-2 rounded" style="background: #e9ecef; border: 1px dashed #6c757d;">';
|
||||
$html .= '<div class="text-center p-2 mb-1 rounded" style="background: #e9ecef; border: 1px dashed #6c757d;">';
|
||||
$html .= ' <strong>FOOTER</strong>';
|
||||
$html .= '</div>';
|
||||
|
||||
// Anchor Bottom
|
||||
$html .= '<div class="text-center p-2 rounded" style="background: #d1ecf1; border: 2px solid #17a2b8;">';
|
||||
$html .= ' <i class="bi bi-pin-angle"></i> <strong>ANCHOR BOTTOM</strong> (fijo, collapsible)';
|
||||
$html .= '</div>';
|
||||
|
||||
// Rail Ads (laterales)
|
||||
$html .= '<div class="mt-2 d-flex justify-content-between">';
|
||||
$html .= ' <div class="p-2 rounded text-center" style="width: 45%; background: #f8d7da; border: 2px solid #dc3545; font-size: 10px;">';
|
||||
@@ -183,11 +195,19 @@ final class AdsensePlacementFormBuilder
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
// Vignette Ad (modal)
|
||||
$html .= '<div class="mt-2 p-2 rounded text-center" style="background: #f3e5f5; border: 2px solid #9c27b0;">';
|
||||
$html .= ' <i class="bi bi-fullscreen"></i> <strong>VIGNETTE</strong> (modal pantalla completa)';
|
||||
$html .= ' <br><small class="text-muted">Aparece segun trigger configurado</small>';
|
||||
$html .= '</div>';
|
||||
|
||||
$html .= '</div>';
|
||||
|
||||
$html .= '<div class="mt-2 small text-muted">';
|
||||
$html .= ' <i class="bi bi-info-circle"></i> Los anuncios <span class="badge bg-warning text-dark">amarillos</span> son configurables abajo.';
|
||||
$html .= ' Los <span class="badge bg-danger">rojos</span> solo aparecen en pantallas >1600px.';
|
||||
$html .= ' <i class="bi bi-info-circle"></i> <span class="badge bg-warning text-dark">Amarillo</span> = Posts, ';
|
||||
$html .= ' <span class="badge bg-danger">Rojo</span> = Rails >1600px, ';
|
||||
$html .= ' <span class="badge" style="background:#17a2b8;color:white;">Cyan</span> = Anchors, ';
|
||||
$html .= ' <span class="badge" style="background:#9c27b0;color:white;">Morado</span> = Vignette';
|
||||
$html .= '</div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
@@ -506,6 +526,177 @@ final class AdsensePlacementFormBuilder
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seccion para Anchor Ads (anuncios fijos top/bottom)
|
||||
*/
|
||||
private function buildAnchorAdsGroup(string $cid): string
|
||||
{
|
||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #17a2b8;">';
|
||||
$html .= ' <div class="card-body">';
|
||||
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
||||
$html .= ' <i class="bi bi-pin-angle me-2" style="color: #17a2b8;"></i>';
|
||||
$html .= ' Anuncios Fijos (Anchor)';
|
||||
$html .= ' </h5>';
|
||||
$html .= ' <p class="small text-muted mb-3">Anuncios fijos en el borde superior o inferior de la pantalla.</p>';
|
||||
|
||||
// Master switch
|
||||
$anchorEnabled = $this->renderer->getFieldValue($cid, 'anchor_ads', 'anchor_enabled', false);
|
||||
$html .= $this->buildSwitch($cid . 'AnchorEnabled', 'Activar Anchor Ads', $anchorEnabled, 'bi-power');
|
||||
|
||||
// Posicion
|
||||
$anchorPosition = $this->renderer->getFieldValue($cid, 'anchor_ads', 'anchor_position', 'bottom');
|
||||
$html .= $this->buildSelect($cid . 'AnchorPosition', 'Posicion del anuncio',
|
||||
$anchorPosition,
|
||||
[
|
||||
'top' => 'Solo en la parte superior',
|
||||
'bottom' => 'Solo en la parte inferior',
|
||||
'both' => 'Superior e inferior'
|
||||
]
|
||||
);
|
||||
|
||||
// Altura
|
||||
$anchorHeight = $this->renderer->getFieldValue($cid, 'anchor_ads', 'anchor_height', '90');
|
||||
$html .= $this->buildSelect($cid . 'AnchorHeight', 'Altura del anchor',
|
||||
$anchorHeight,
|
||||
['50' => '50px', '90' => '90px', '100' => '100px', '120' => '120px']
|
||||
);
|
||||
|
||||
// Collapsible toggle
|
||||
$collapsible = $this->renderer->getFieldValue($cid, 'anchor_ads', 'anchor_collapsible_enabled', true);
|
||||
$html .= $this->buildSwitch($cid . 'AnchorCollapsibleEnabled', 'Permitir minimizar', $collapsible, 'bi-arrows-collapse');
|
||||
$html .= '<small class="text-muted d-block" style="margin-top: -8px; margin-left: 40px;">Usuario puede minimizar en lugar de cerrar</small>';
|
||||
|
||||
// Pantallas
|
||||
$html .= '<div class="row g-2 mt-2">';
|
||||
$html .= ' <div class="col-6">';
|
||||
$showMobile = $this->renderer->getFieldValue($cid, 'anchor_ads', 'anchor_show_on_mobile', true);
|
||||
$html .= $this->buildSwitch($cid . 'AnchorShowOnMobile', 'Mostrar en movil', $showMobile, 'bi-phone');
|
||||
$html .= ' </div>';
|
||||
$html .= ' <div class="col-6">';
|
||||
$showWide = $this->renderer->getFieldValue($cid, 'anchor_ads', 'anchor_show_on_wide_screens', false);
|
||||
$html .= $this->buildSwitch($cid . 'AnchorShowOnWideScreens', 'Pantallas anchas', $showWide, 'bi-display');
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
// Recordar estado
|
||||
$html .= '<div class="mt-3 p-2 rounded" style="background: #e7f1ff;">';
|
||||
$rememberState = $this->renderer->getFieldValue($cid, 'anchor_ads', 'anchor_remember_state', true);
|
||||
$html .= $this->buildSwitch($cid . 'AnchorRememberState', 'Recordar cierre/colapso', $rememberState, 'bi-clock-history');
|
||||
|
||||
$rememberDuration = $this->renderer->getFieldValue($cid, 'anchor_ads', 'anchor_remember_duration', 'session');
|
||||
$html .= $this->buildSelect($cid . 'AnchorRememberDuration', 'Duracion',
|
||||
$rememberDuration,
|
||||
[
|
||||
'session' => 'Solo esta sesion',
|
||||
'1hour' => '1 hora',
|
||||
'1day' => '1 dia',
|
||||
'1week' => '1 semana'
|
||||
]
|
||||
);
|
||||
$html .= '</div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seccion para Vignette Ads (pantalla completa)
|
||||
*/
|
||||
private function buildVignetteAdsGroup(string $cid): string
|
||||
{
|
||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #9c27b0;">';
|
||||
$html .= ' <div class="card-body">';
|
||||
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
||||
$html .= ' <i class="bi bi-fullscreen me-2" style="color: #9c27b0;"></i>';
|
||||
$html .= ' Anuncios de Vineta';
|
||||
$html .= ' <span class="badge bg-secondary ms-2">Pantalla Completa</span>';
|
||||
$html .= ' </h5>';
|
||||
$html .= ' <p class="small text-muted mb-3">Anuncios que ocupan toda la pantalla, aparecen segun el trigger configurado.</p>';
|
||||
|
||||
// Master switch
|
||||
$vignetteEnabled = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_enabled', false);
|
||||
$html .= $this->buildSwitch($cid . 'VignetteEnabled', 'Activar Vignette Ads', $vignetteEnabled, 'bi-power');
|
||||
|
||||
// Trigger
|
||||
$vignetteTrigger = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_trigger', 'pageview');
|
||||
$html .= $this->buildSelect($cid . 'VignetteTrigger', 'Cuando mostrar',
|
||||
$vignetteTrigger,
|
||||
[
|
||||
'pageview' => 'Al cargar la pagina',
|
||||
'scroll_50' => 'Al scrollear 50%',
|
||||
'scroll_75' => 'Al scrollear 75%',
|
||||
'exit_intent' => 'Al intentar salir',
|
||||
'time_delay' => 'Despues de X segundos'
|
||||
]
|
||||
);
|
||||
|
||||
// Delay inicial
|
||||
$triggerDelay = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_trigger_delay', '5');
|
||||
$html .= $this->buildTextInput($cid . 'VignetteTriggerDelay', 'Delay inicial (segundos)', (string)$triggerDelay, '5');
|
||||
|
||||
// Tamano y opacidad
|
||||
$html .= '<div class="row g-2 mt-2">';
|
||||
$html .= ' <div class="col-6">';
|
||||
$size = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_size', '300x250');
|
||||
$html .= $this->buildSelect($cid . 'VignetteSize', 'Tamano',
|
||||
$size,
|
||||
['300x250' => '300x250', '336x280' => '336x280', 'responsive' => 'Responsive']
|
||||
);
|
||||
$html .= ' </div>';
|
||||
$html .= ' <div class="col-6">';
|
||||
$opacity = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_overlay_opacity', '0.7');
|
||||
$html .= $this->buildSelect($cid . 'VignetteOverlayOpacity', 'Opacidad fondo',
|
||||
$opacity,
|
||||
['0.5' => '50%', '0.6' => '60%', '0.7' => '70%', '0.8' => '80%', '0.9' => '90%']
|
||||
);
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
// Pantallas
|
||||
$html .= '<div class="row g-2 mt-2">';
|
||||
$html .= ' <div class="col-6">';
|
||||
$showMobile = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_show_on_mobile', true);
|
||||
$html .= $this->buildSwitch($cid . 'VignetteShowOnMobile', 'Mostrar en movil', $showMobile, 'bi-phone');
|
||||
$html .= ' </div>';
|
||||
$html .= ' <div class="col-6">';
|
||||
$showDesktop = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_show_on_desktop', true);
|
||||
$html .= $this->buildSwitch($cid . 'VignetteShowOnDesktop', 'Mostrar en desktop', $showDesktop, 'bi-display');
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
// Reaparicion
|
||||
$html .= '<div class="mt-3 p-2 rounded" style="background: #f3e5f5;">';
|
||||
$html .= '<p class="small fw-semibold mb-2"><i class="bi bi-arrow-repeat me-1"></i> Reaparicion</p>';
|
||||
|
||||
$reshowEnabled = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_reshow_enabled', true);
|
||||
$html .= $this->buildSwitch($cid . 'VignetteReshowEnabled', 'Permitir reaparicion', $reshowEnabled);
|
||||
|
||||
$html .= '<div class="row g-2">';
|
||||
$html .= ' <div class="col-6">';
|
||||
$reshowTime = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_reshow_time', '5');
|
||||
$html .= $this->buildSelect($cid . 'VignetteReshowTime', 'Tiempo (min)',
|
||||
$reshowTime,
|
||||
['1' => '1 min', '2' => '2 min', '3' => '3 min', '4' => '4 min', '5' => '5 min', '10' => '10 min', '15' => '15 min', '30' => '30 min']
|
||||
);
|
||||
$html .= ' </div>';
|
||||
$html .= ' <div class="col-6">';
|
||||
$maxSession = $this->renderer->getFieldValue($cid, 'vignette_ads', 'vignette_max_per_session', '3');
|
||||
$html .= $this->buildSelect($cid . 'VignetteMaxPerSession', 'Max/sesion',
|
||||
$maxSession,
|
||||
['1' => '1', '2' => '2', '3' => '3', '5' => '5', 'unlimited' => 'Sin limite']
|
||||
);
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
$html .= '</div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function buildExclusionsGroup(string $cid): string
|
||||
{
|
||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #6c757d;">';
|
||||
|
||||
Reference in New Issue
Block a user