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:
FrankZamora
2025-11-28 21:00:00 -06:00
parent 4d5cc1a58c
commit b96a13427e
6 changed files with 1313 additions and 5 deletions

View File

@@ -5,10 +5,20 @@
* Funciones para usar en templates:
* - roi_render_ad_slot('post-top')
* - roi_render_rail_ads() - Para los margenes laterales del viewport
* - roi_render_anchor_ads() - Anuncios fijos top/bottom
* - roi_render_vignette_ad() - Anuncio pantalla completa
*
* Funciones auto-registradas en wp_head:
* - roi_enqueue_adsense_script() - Script principal de AdSense
* - roi_enqueue_analytics_script() - Script de Google Analytics
*
* Funciones auto-registradas en wp_footer:
* - roi_render_rail_ads() (priority 50)
* - roi_render_anchor_ads() (priority 51)
* - roi_render_vignette_ad() (priority 52)
*
* Funciones auto-registradas en wp_enqueue_scripts:
* - roi_enqueue_anchor_vignette_scripts() - Script JS para Anchor/Vignette
*/
if (!defined('ABSPATH')) {
@@ -374,3 +384,156 @@ function roi_render_universal_analytics_script(string $trackingId, bool $anonymi
echo 'ga("send", "pageview");' . "\n";
echo '</script>' . "\n";
}
/**
* Renderiza Anchor Ads (anuncios fijos top/bottom)
*
* NOTA DIP: El renderer se obtiene del DIContainer, NO se instancia directamente.
*/
function roi_render_anchor_ads(): string
{
global $container;
if ($container === null) {
return '';
}
try {
$repository = $container->getComponentSettingsRepository();
$settings = $repository->getComponentSettings('adsense-placement');
if (empty($settings)) {
return '';
}
// Verificar si ocultar para usuarios logueados
if (roi_should_hide_for_logged_in($settings)) {
return '';
}
// Verificar exclusiones
if (roi_is_ad_excluded($settings)) {
return '';
}
// Obtener renderer desde DIContainer (DIP compliant)
$renderer = $container->getAdsensePlacementRenderer();
return $renderer->renderAnchorAds($settings);
} catch (\Throwable $e) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('ROI Anchor Ads: ' . $e->getMessage());
}
return '';
}
}
/**
* Renderiza Vignette Ad (pantalla completa)
*
* NOTA DIP: El renderer se obtiene del DIContainer, NO se instancia directamente.
*/
function roi_render_vignette_ad(): string
{
global $container;
if ($container === null) {
return '';
}
try {
$repository = $container->getComponentSettingsRepository();
$settings = $repository->getComponentSettings('adsense-placement');
if (empty($settings)) {
return '';
}
// Verificar si ocultar para usuarios logueados
if (roi_should_hide_for_logged_in($settings)) {
return '';
}
// Verificar exclusiones
if (roi_is_ad_excluded($settings)) {
return '';
}
// Obtener renderer desde DIContainer (DIP compliant)
$renderer = $container->getAdsensePlacementRenderer();
return $renderer->renderVignetteAd($settings);
} catch (\Throwable $e) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('ROI Vignette Ad: ' . $e->getMessage());
}
return '';
}
}
/**
* Hook para inyectar Anchor Ads en el footer
*/
add_action('wp_footer', function() {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo roi_render_anchor_ads();
}, 51);
/**
* Hook para inyectar Vignette Ad en el footer
*/
add_action('wp_footer', function() {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo roi_render_vignette_ad();
}, 52);
/**
* Encola el script JavaScript para Anchor y Vignette Ads
*/
function roi_enqueue_anchor_vignette_scripts(): void
{
global $container;
if ($container === null || is_admin()) {
return;
}
try {
$repository = $container->getComponentSettingsRepository();
$settings = $repository->getComponentSettings('adsense-placement');
if (!($settings['visibility']['is_enabled'] ?? false)) {
return;
}
// Verificar si Anchor o Vignette estan habilitados
$anchorEnabled = $settings['anchor_ads']['anchor_enabled'] ?? false;
$vignetteEnabled = $settings['vignette_ads']['vignette_enabled'] ?? false;
if (!$anchorEnabled && !$vignetteEnabled) {
return;
}
// Verificar si ocultar para usuarios logueados
if (roi_should_hide_for_logged_in($settings)) {
return;
}
// Encolar script
wp_enqueue_script(
'roi-anchor-vignette',
get_template_directory_uri() . '/Public/AdsensePlacement/Infrastructure/Ui/Assets/anchor-vignette.js',
[],
'1.0.0',
true // En footer
);
} catch (\Throwable $e) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('ROI Anchor/Vignette Scripts: ' . $e->getMessage());
}
}
}
add_action('wp_enqueue_scripts', 'roi_enqueue_anchor_vignette_scripts');