Fix TypeError: buildSelect() Argument #3 ($value) must be of type string. The getFieldValue() method can return boolean for certain DB values, causing type mismatch with strict typed buildSelect() method. Added (string) casts to all buildSelect() calls in Vignette Ads section: - vignetteTrigger - size - opacity - reshowTime - maxSession 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
818 lines
40 KiB
PHP
818 lines
40 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Admin\AdsensePlacement\Infrastructure\Ui;
|
|
|
|
use ROITheme\Admin\Infrastructure\Ui\AdminDashboardRenderer;
|
|
|
|
/**
|
|
* FormBuilder para AdSense Placement y Google Analytics
|
|
*
|
|
* Panel reorganizado con:
|
|
* - Diagrama visual de ubicaciones
|
|
* - Secciones colapsables
|
|
* - In-content ads configurables (1-8 random)
|
|
*/
|
|
final class AdsensePlacementFormBuilder
|
|
{
|
|
public function __construct(
|
|
private AdminDashboardRenderer $renderer
|
|
) {}
|
|
|
|
public function buildForm(string $componentId): string
|
|
{
|
|
$html = '';
|
|
|
|
// HEADER CON GRADIENTE
|
|
$html .= '<div class="rounded p-4 mb-4 shadow text-white" style="background: linear-gradient(135deg, #0E2337 0%, #1e3a5f 100%); border-left: 4px solid #FF8600;">';
|
|
$html .= ' <div class="d-flex align-items-center justify-content-between flex-wrap gap-3">';
|
|
$html .= ' <div>';
|
|
$html .= ' <h3 class="h4 mb-1 fw-bold">';
|
|
$html .= ' <i class="bi bi-megaphone me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' AdSense y Analytics';
|
|
$html .= ' </h3>';
|
|
$html .= ' <p class="mb-0 small" style="opacity: 0.85;">';
|
|
$html .= ' Configura Google AdSense y Analytics con ubicaciones visuales';
|
|
$html .= ' </p>';
|
|
$html .= ' </div>';
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
// LAYOUT 2 COLUMNAS
|
|
$html .= '<div class="row g-3">';
|
|
|
|
// COLUMNA IZQUIERDA (7 cols)
|
|
$html .= ' <div class="col-lg-7">';
|
|
$html .= $this->buildVisibilityGroup($componentId);
|
|
$html .= $this->buildDiagramSection();
|
|
$html .= $this->buildPostLocationsGroup($componentId);
|
|
$html .= $this->buildInContentAdsGroup($componentId);
|
|
$html .= ' </div>';
|
|
|
|
// COLUMNA DERECHA (5 cols)
|
|
$html .= ' <div class="col-lg-5">';
|
|
$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>';
|
|
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildVisibilityGroup(string $cid): string
|
|
{
|
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #28a745;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-power me-2" style="color: #28a745;"></i>';
|
|
$html .= ' Activacion Global';
|
|
$html .= ' </h5>';
|
|
|
|
$html .= '<div class="row g-3">';
|
|
$html .= ' <div class="col-md-4">';
|
|
$enabled = $this->renderer->getFieldValue($cid, 'visibility', 'is_enabled', false);
|
|
$html .= $this->buildSwitch($cid . 'Enabled', 'Activar AdSense', $enabled, 'bi-power');
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-4">';
|
|
$showMobile = $this->renderer->getFieldValue($cid, 'visibility', 'show_on_mobile', true);
|
|
$html .= $this->buildSwitch($cid . 'ShowOnMobile', 'Mostrar en movil', $showMobile, 'bi-phone');
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-4">';
|
|
$showDesktop = $this->renderer->getFieldValue($cid, 'visibility', 'show_on_desktop', true);
|
|
$html .= $this->buildSwitch($cid . 'ShowOnDesktop', 'Mostrar en escritorio', $showDesktop, 'bi-display');
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
// Opcion para ocultar anuncios a usuarios logueados
|
|
$html .= '<div class="mt-3 p-2 rounded" style="background: #fff3cd;">';
|
|
$hideForLoggedIn = $this->renderer->getFieldValue($cid, 'visibility', 'hide_for_logged_in', false);
|
|
$html .= $this->buildSwitch($cid . 'HideForLoggedIn', 'Ocultar para usuarios logueados', $hideForLoggedIn, 'bi-person-lock');
|
|
$html .= '<small class="text-muted d-block" style="margin-top: -8px; margin-left: 40px;">No mostrar anuncios a usuarios con sesion iniciada en WordPress</small>';
|
|
$html .= '</div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Diagrama visual de ubicaciones de anuncios
|
|
*/
|
|
private function buildDiagramSection(): string
|
|
{
|
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #6f42c1;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-layout-text-window-reverse me-2" style="color: #6f42c1;"></i>';
|
|
$html .= ' Mapa de Ubicaciones';
|
|
$html .= ' </h5>';
|
|
|
|
// 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>';
|
|
$html .= '</div>';
|
|
|
|
// Hero / Featured Image
|
|
$html .= '<div class="text-center p-2 mb-1 rounded" style="background: #d1e7dd; border: 1px solid #198754;">';
|
|
$html .= ' <i class="bi bi-image"></i> Featured Image / Hero';
|
|
$html .= '</div>';
|
|
|
|
// Ad: Post Top
|
|
$html .= '<div class="text-center p-2 mb-1 rounded" style="background: #fff3cd; border: 2px solid #ffc107;">';
|
|
$html .= ' <i class="bi bi-megaphone"></i> <strong>📍 POST-TOP</strong> (Despues de imagen)';
|
|
$html .= '</div>';
|
|
|
|
// Content container
|
|
$html .= '<div class="p-2 mb-1 rounded" style="background: #fff; border: 1px solid #dee2e6;">';
|
|
$html .= ' <div class="mb-1 small text-muted text-center">📝 CONTENIDO DEL POST</div>';
|
|
$html .= ' <div class="p-1 rounded mb-1" style="background: #e7f1ff; font-size: 10px;">Parrafo 1...</div>';
|
|
$html .= ' <div class="p-1 rounded mb-1" style="background: #e7f1ff; font-size: 10px;">Parrafo 2...</div>';
|
|
$html .= ' <div class="p-1 rounded mb-1" style="background: #e7f1ff; font-size: 10px;">Parrafo 3...</div>';
|
|
|
|
// In-content ad
|
|
$html .= ' <div class="text-center p-1 mb-1 rounded" style="background: #fff3cd; border: 2px dashed #ffc107; font-size: 10px;">';
|
|
$html .= ' <i class="bi bi-megaphone"></i> <strong>📍 IN-CONTENT #1</strong>';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="p-1 rounded mb-1" style="background: #e7f1ff; font-size: 10px;">Parrafo 4...</div>';
|
|
$html .= ' <div class="p-1 rounded mb-1" style="background: #e7f1ff; font-size: 10px;">Parrafo 5...</div>';
|
|
$html .= ' <div class="p-1 rounded mb-1" style="background: #e7f1ff; font-size: 10px;">Parrafo 6...</div>';
|
|
|
|
// In-content ad 2
|
|
$html .= ' <div class="text-center p-1 mb-1 rounded" style="background: #fff3cd; border: 2px dashed #ffc107; font-size: 10px;">';
|
|
$html .= ' <i class="bi bi-megaphone"></i> <strong>📍 IN-CONTENT #2</strong> (random)';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="p-1 rounded" style="background: #e7f1ff; font-size: 10px;">Mas parrafos...</div>';
|
|
$html .= '</div>';
|
|
|
|
// Ad: Post Bottom
|
|
$html .= '<div class="text-center p-2 mb-1 rounded" style="background: #fff3cd; border: 2px solid #ffc107;">';
|
|
$html .= ' <i class="bi bi-megaphone"></i> <strong>📍 POST-BOTTOM</strong> (Despues del contenido)';
|
|
$html .= '</div>';
|
|
|
|
// Related Posts
|
|
$html .= '<div class="text-center p-2 mb-1 rounded" style="background: #cfe2ff; border: 1px solid #0d6efd;">';
|
|
$html .= ' <i class="bi bi-grid-3x2"></i> Related Posts';
|
|
$html .= '</div>';
|
|
|
|
// Ad: After Related
|
|
$html .= '<div class="text-center p-2 mb-1 rounded" style="background: #fff3cd; border: 2px solid #ffc107;">';
|
|
$html .= ' <i class="bi bi-megaphone"></i> <strong>📍 AFTER-RELATED</strong>';
|
|
$html .= '</div>';
|
|
|
|
// Footer
|
|
$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;">';
|
|
$html .= ' <strong>📍 RAIL IZQ</strong><br><small>(160x600)</small>';
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="p-2 rounded text-center" style="width: 45%; background: #f8d7da; border: 2px solid #dc3545; font-size: 10px;">';
|
|
$html .= ' <strong>📍 RAIL DER</strong><br><small>(160x600)</small>';
|
|
$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> <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>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildPostLocationsGroup(string $cid): string
|
|
{
|
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #ffc107;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-geo-alt me-2" style="color: #ffc107;"></i>';
|
|
$html .= ' Ubicaciones en Posts';
|
|
$html .= ' </h5>';
|
|
|
|
// === POST-TOP ===
|
|
$html .= '<div class="border rounded p-3 mb-3" style="background: #fffbeb;">';
|
|
$html .= '<div class="d-flex align-items-center gap-2 mb-2">';
|
|
$html .= ' <span class="badge bg-warning text-dark">POST-TOP</span>';
|
|
$html .= ' <small class="text-muted">Despues de la imagen destacada</small>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="row g-2">';
|
|
$html .= ' <div class="col-md-6">';
|
|
$postTopEnabled = $this->renderer->getFieldValue($cid, 'behavior', 'post_top_enabled', true);
|
|
$html .= $this->buildSwitch($cid . 'PostTopEnabled', 'Activar', $postTopEnabled);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-6">';
|
|
$html .= $this->buildSelect($cid . 'PostTopFormat', 'Formato',
|
|
$this->renderer->getFieldValue($cid, 'behavior', 'post_top_format', 'auto'),
|
|
[
|
|
'auto' => 'Auto (responsive)',
|
|
'in-article' => 'In-Article (fluid)',
|
|
'display' => 'Display (728x90)',
|
|
'display-large' => 'Display Large (970x250)'
|
|
]
|
|
);
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
$html .= '</div>';
|
|
|
|
// === POST-BOTTOM ===
|
|
$html .= '<div class="border rounded p-3 mb-3" style="background: #fffbeb;">';
|
|
$html .= '<div class="d-flex align-items-center gap-2 mb-2">';
|
|
$html .= ' <span class="badge bg-warning text-dark">POST-BOTTOM</span>';
|
|
$html .= ' <small class="text-muted">Despues del contenido, antes de Related</small>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="row g-2">';
|
|
$html .= ' <div class="col-md-6">';
|
|
$postBottomEnabled = $this->renderer->getFieldValue($cid, 'behavior', 'post_bottom_enabled', true);
|
|
$html .= $this->buildSwitch($cid . 'PostBottomEnabled', 'Activar', $postBottomEnabled);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-6">';
|
|
$html .= $this->buildSelect($cid . 'PostBottomFormat', 'Formato',
|
|
$this->renderer->getFieldValue($cid, 'behavior', 'post_bottom_format', 'auto'),
|
|
['auto' => 'Auto', 'in-article' => 'In-Article', 'display' => 'Display']
|
|
);
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
$html .= '</div>';
|
|
|
|
// === AFTER-RELATED ===
|
|
$html .= '<div class="border rounded p-3" style="background: #fffbeb;">';
|
|
$html .= '<div class="d-flex align-items-center gap-2 mb-2">';
|
|
$html .= ' <span class="badge bg-warning text-dark">AFTER-RELATED</span>';
|
|
$html .= ' <small class="text-muted">Despues de Related Posts</small>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="row g-2">';
|
|
$html .= ' <div class="col-md-6">';
|
|
$afterRelatedEnabled = $this->renderer->getFieldValue($cid, 'behavior', 'after_related_enabled', false);
|
|
$html .= $this->buildSwitch($cid . 'AfterRelatedEnabled', 'Activar', $afterRelatedEnabled);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-6">';
|
|
$html .= $this->buildSelect($cid . 'AfterRelatedFormat', 'Formato',
|
|
$this->renderer->getFieldValue($cid, 'behavior', 'after_related_format', 'autorelaxed'),
|
|
['autorelaxed' => 'Autorelaxed (feed)', 'auto' => 'Auto']
|
|
);
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Seccion especial para in-content ads con configuracion de 1-8 random
|
|
*/
|
|
private function buildInContentAdsGroup(string $cid): string
|
|
{
|
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #0d6efd;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-body-text me-2" style="color: #0d6efd;"></i>';
|
|
$html .= ' Anuncios Dentro del Contenido';
|
|
$html .= ' <span class="badge bg-primary ms-2">1-8 ads</span>';
|
|
$html .= ' </h5>';
|
|
|
|
$html .= '<div class="alert alert-info small mb-3">';
|
|
$html .= ' <i class="bi bi-lightbulb me-1"></i>';
|
|
$html .= ' <strong>Modo Random:</strong> Inserta entre 1 y 8 anuncios en posiciones aleatorias entre parrafos.';
|
|
$html .= ' Mejor UX al variar la posicion en cada visita.';
|
|
$html .= '</div>';
|
|
|
|
// Master switch
|
|
$postContentEnabled = $this->renderer->getFieldValue($cid, 'behavior', 'post_content_enabled', false);
|
|
$html .= '<div class="mb-3">';
|
|
$html .= $this->buildSwitch($cid . 'PostContentEnabled', 'Activar In-Content Ads', $postContentEnabled, 'bi-power');
|
|
$html .= '</div>';
|
|
|
|
// Configuracion de cantidad
|
|
$html .= '<div class="row g-2 mb-3">';
|
|
$html .= ' <div class="col-md-6">';
|
|
$minAdsValue = $this->renderer->getFieldValue($cid, 'behavior', 'post_content_min_ads', '1');
|
|
$html .= $this->buildSelect($cid . 'PostContentMinAds', 'Minimo de anuncios',
|
|
is_string($minAdsValue) ? $minAdsValue : '1',
|
|
['1' => '1 anuncio', '2' => '2 anuncios', '3' => '3 anuncios', '4' => '4 anuncios']
|
|
);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-6">';
|
|
$maxAdsValue = $this->renderer->getFieldValue($cid, 'behavior', 'post_content_max_ads', '3');
|
|
$html .= $this->buildSelect($cid . 'PostContentMaxAds', 'Maximo de anuncios',
|
|
is_string($maxAdsValue) ? $maxAdsValue : '3',
|
|
[
|
|
'1' => '1 anuncio', '2' => '2 anuncios', '3' => '3 anuncios', '4' => '4 anuncios',
|
|
'5' => '5 anuncios', '6' => '6 anuncios', '7' => '7 anuncios', '8' => '8 anuncios'
|
|
]
|
|
);
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
// Configuracion de posicionamiento
|
|
$html .= '<div class="row g-2 mb-3">';
|
|
$html .= ' <div class="col-md-6">';
|
|
$afterPara = $this->renderer->getFieldValue($cid, 'behavior', 'post_content_after_paragraphs', '3');
|
|
$html .= $this->buildTextInput($cid . 'PostContentAfterParagraphs', 'Primer ad despues del parrafo #', (string)$afterPara, '3');
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-6">';
|
|
$minBetweenValue = $this->renderer->getFieldValue($cid, 'behavior', 'post_content_min_paragraphs_between', '4');
|
|
$html .= $this->buildSelect($cid . 'PostContentMinParagraphsBetween', 'Parrafos entre ads',
|
|
is_string($minBetweenValue) ? $minBetweenValue : '4',
|
|
['2' => '2 parrafos', '3' => '3 parrafos', '4' => '4 parrafos', '5' => '5 parrafos', '6' => '6 parrafos']
|
|
);
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
// Modo y formato
|
|
$html .= '<div class="row g-2">';
|
|
$html .= ' <div class="col-md-6">';
|
|
$randomMode = $this->renderer->getFieldValue($cid, 'behavior', 'post_content_random_mode', true);
|
|
$html .= $this->buildSwitch($cid . 'PostContentRandomMode', 'Posiciones aleatorias', $randomMode, 'bi-shuffle');
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-6">';
|
|
$formatValue = $this->renderer->getFieldValue($cid, 'behavior', 'post_content_format', 'in-article');
|
|
$html .= $this->buildSelect($cid . 'PostContentFormat', 'Formato de ads',
|
|
is_string($formatValue) ? $formatValue : 'in-article',
|
|
['in-article' => 'In-Article (fluid)', 'auto' => 'Auto (responsive)']
|
|
);
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildCredentialsGroup(string $cid): string
|
|
{
|
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-key me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Credenciales AdSense';
|
|
$html .= ' </h5>';
|
|
|
|
// Publisher ID
|
|
$pubId = $this->renderer->getFieldValue($cid, 'content', 'publisher_id', 'ca-pub-8476420265998726');
|
|
$html .= $this->buildTextInput($cid . 'PublisherId', 'Publisher ID', $pubId, 'ca-pub-XXXXX');
|
|
|
|
$html .= '<hr class="my-3">';
|
|
$html .= '<p class="small text-muted mb-2"><i class="bi bi-info-circle me-1"></i> Slots por tipo de anuncio:</p>';
|
|
|
|
// Slots con descripciones claras
|
|
$html .= '<div class="mb-2">';
|
|
$slotAuto = $this->renderer->getFieldValue($cid, 'content', 'slot_auto', '8471732096');
|
|
$html .= $this->buildTextInput($cid . 'SlotAuto', '📱 Auto (responsive)', $slotAuto);
|
|
$html .= '<div class="form-text small" style="margin-top:-10px;">Para: Post-Top, Post-Bottom, globales</div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="mb-2">';
|
|
$slotInArticle = $this->renderer->getFieldValue($cid, 'content', 'slot_inarticle', '7285187368');
|
|
$html .= $this->buildTextInput($cid . 'SlotInarticle', '📝 In-Article (fluid)', $slotInArticle);
|
|
$html .= '<div class="form-text small" style="margin-top:-10px;">Para: In-Content (dentro del texto)</div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="mb-2">';
|
|
$slotDisplay = $this->renderer->getFieldValue($cid, 'content', 'slot_display', '2873062302');
|
|
$html .= $this->buildTextInput($cid . 'SlotDisplay', '🖥️ Display (fijo)', $slotDisplay);
|
|
$html .= '<div class="form-text small" style="margin-top:-10px;">Para: 728x90, 970x250 (opcional)</div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="mb-2">';
|
|
$slotRelaxed = $this->renderer->getFieldValue($cid, 'content', 'slot_autorelaxed', '9205569855');
|
|
$html .= $this->buildTextInput($cid . 'SlotAutorelaxed', '📋 Autorelaxed (feed)', $slotRelaxed);
|
|
$html .= '<div class="form-text small" style="margin-top:-10px;">Para: After-Related, archives</div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="mb-2">';
|
|
$slotSkyscraper = $this->renderer->getFieldValue($cid, 'content', 'slot_skyscraper', '');
|
|
$html .= $this->buildTextInput($cid . 'SlotSkyscraper', '🏢 Skyscraper (tall)', $slotSkyscraper);
|
|
$html .= '<div class="form-text small" style="margin-top:-10px;">Para: Rail Ads laterales (160x600)</div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildAnalyticsGroup(string $cid): string
|
|
{
|
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #4285f4;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-graph-up me-2" style="color: #4285f4;"></i>';
|
|
$html .= ' Google Analytics';
|
|
$html .= ' </h5>';
|
|
|
|
// Switch: Analytics Enabled
|
|
$analyticsEnabled = $this->renderer->getFieldValue($cid, 'analytics', 'analytics_enabled', false);
|
|
$html .= $this->buildSwitch($cid . 'AnalyticsEnabled', 'Activar Analytics', $analyticsEnabled, 'bi-power');
|
|
|
|
// Tracking ID
|
|
$gaTrackingId = $this->renderer->getFieldValue($cid, 'analytics', 'ga_tracking_id', '');
|
|
$html .= $this->buildTextInput($cid . 'GaTrackingId', 'Google Analytics ID', $gaTrackingId, 'G-XXXXXXXXXX');
|
|
$html .= '<div class="form-text small mb-2">Formato: G-XXXXXXXXXX (GA4) o UA-XXXXXXXX-X</div>';
|
|
|
|
// Anonymize IP
|
|
$gaAnonymizeIp = $this->renderer->getFieldValue($cid, 'analytics', 'ga_anonymize_ip', true);
|
|
$html .= $this->buildSwitch($cid . 'GaAnonymizeIp', 'Anonimizar IP (GDPR)', $gaAnonymizeIp, 'bi-shield-check');
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildRailAdsGroup(string $cid): string
|
|
{
|
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #dc3545;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-layout-sidebar me-2" style="color: #dc3545;"></i>';
|
|
$html .= ' Rail Ads (Laterales)';
|
|
$html .= ' <span class="badge bg-secondary ms-2">>1600px</span>';
|
|
$html .= ' </h5>';
|
|
$html .= ' <p class="small text-muted mb-3">Anuncios fijos en los margenes del viewport. Solo en pantallas muy anchas.</p>';
|
|
|
|
// Master switch
|
|
$railEnabled = $this->renderer->getFieldValue($cid, 'behavior', 'rail_ads_enabled', false);
|
|
$html .= $this->buildSwitch($cid . 'RailAdsEnabled', 'Activar Rail Ads', $railEnabled, 'bi-power');
|
|
|
|
// Left/Right toggles
|
|
$html .= '<div class="row g-2 mt-2">';
|
|
$html .= ' <div class="col-6">';
|
|
$leftEnabled = $this->renderer->getFieldValue($cid, 'behavior', 'rail_left_enabled', true);
|
|
$html .= $this->buildSwitch($cid . 'RailLeftEnabled', 'Rail izquierdo', $leftEnabled);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-6">';
|
|
$rightEnabled = $this->renderer->getFieldValue($cid, 'behavior', 'rail_right_enabled', true);
|
|
$html .= $this->buildSwitch($cid . 'RailRightEnabled', 'Rail derecho', $rightEnabled);
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
// Format select - Solo altura (el ancho es responsive)
|
|
$railFormat = $this->renderer->getFieldValue($cid, 'behavior', 'rail_format', 'h600');
|
|
$html .= $this->buildSelect($cid . 'RailFormat', 'Altura del Rail',
|
|
$railFormat,
|
|
[
|
|
'h250' => '250px (Compacto)',
|
|
'h300' => '300px (Pequeno)',
|
|
'h400' => '400px (Mediano)',
|
|
'h500' => '500px',
|
|
'h600' => '600px (Recomendado)',
|
|
'h700' => '700px',
|
|
'h800' => '800px (Grande)',
|
|
'h1050' => '1050px (Extra grande)'
|
|
]
|
|
);
|
|
$html .= '<small class="text-muted d-block mt-1 mb-2">El ancho se ajusta automaticamente al espacio disponible.</small>';
|
|
|
|
// Top offset - Select con opciones predefinidas
|
|
$topOffset = $this->renderer->getFieldValue($cid, 'behavior', 'rail_top_offset', '300');
|
|
$html .= $this->buildSelect($cid . 'RailTopOffset', 'Distancia desde arriba',
|
|
$topOffset,
|
|
[
|
|
'150' => '150px (Cerca del header)',
|
|
'200' => '200px',
|
|
'300' => '300px (Recomendado)',
|
|
'400' => '400px',
|
|
'500' => '500px',
|
|
'700' => '700px (Debajo del fold)'
|
|
]
|
|
);
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
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',
|
|
(string)$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',
|
|
(string)$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',
|
|
(string)$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)',
|
|
(string)$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',
|
|
(string)$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;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-slash-circle me-2" style="color: #6c757d;"></i>';
|
|
$html .= ' Exclusiones y Rendimiento';
|
|
$html .= ' </h5>';
|
|
|
|
// Accordion para exclusiones
|
|
$html .= '<div class="accordion accordion-flush" id="exclusionsAccordion">';
|
|
|
|
// Exclusiones
|
|
$html .= '<div class="accordion-item">';
|
|
$html .= ' <h2 class="accordion-header">';
|
|
$html .= ' <button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#exclusionsCollapse">';
|
|
$html .= ' <i class="bi bi-funnel me-2"></i> Filtros de exclusion';
|
|
$html .= ' </button>';
|
|
$html .= ' </h2>';
|
|
$html .= ' <div id="exclusionsCollapse" class="accordion-collapse collapse" data-bs-parent="#exclusionsAccordion">';
|
|
$html .= ' <div class="accordion-body">';
|
|
|
|
$excludeCats = $this->renderer->getFieldValue($cid, 'forms', 'exclude_categories', '');
|
|
$html .= $this->buildTextarea($cid . 'ExcludeCategories', 'Excluir categorias (IDs)', $excludeCats, 'Ej: 5,12,23');
|
|
|
|
$excludeTypes = $this->renderer->getFieldValue($cid, 'forms', 'exclude_post_types', '');
|
|
$html .= $this->buildTextarea($cid . 'ExcludePostTypes', 'Excluir tipos de post', $excludeTypes, 'Ej: page,attachment');
|
|
|
|
$excludeIds = $this->renderer->getFieldValue($cid, 'forms', 'exclude_post_ids', '');
|
|
$html .= $this->buildTextarea($cid . 'ExcludePostIds', 'Excluir posts (IDs)', $excludeIds, 'Ej: 100,205,310');
|
|
|
|
$minLength = $this->renderer->getFieldValue($cid, 'forms', 'min_content_length', '500');
|
|
$html .= $this->buildTextInput($cid . 'MinContentLength', 'Longitud minima de contenido', $minLength);
|
|
|
|
$html .= ' </div>';
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '</div>'; // end accordion
|
|
|
|
// Delay settings (siempre visibles)
|
|
$html .= '<hr class="my-3">';
|
|
$html .= '<p class="small text-muted mb-2"><i class="bi bi-speedometer2 me-1"></i> Rendimiento:</p>';
|
|
|
|
$delayEnabled = $this->renderer->getFieldValue($cid, 'forms', 'delay_enabled', true);
|
|
$html .= $this->buildSwitch($cid . 'DelayEnabled', 'Retrasar carga (mejor PageSpeed)', $delayEnabled, 'bi-hourglass-split');
|
|
|
|
$delayTimeout = $this->renderer->getFieldValue($cid, 'forms', 'delay_timeout', '5000');
|
|
$html .= $this->buildTextInput($cid . 'DelayTimeout', 'Timeout de delay (ms)', $delayTimeout);
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
// === HELPERS ===
|
|
|
|
private function buildSwitch(string $id, string $label, $value, string $icon = ''): string
|
|
{
|
|
$checked = checked($value, true, false);
|
|
$iconHtml = $icon ? '<i class="bi ' . $icon . ' me-1" style="color: #FF8600;"></i>' : '';
|
|
|
|
return sprintf(
|
|
'<div class="mb-2">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="%s" %s>
|
|
<label class="form-check-label small" for="%s">%s%s</label>
|
|
</div>
|
|
</div>',
|
|
esc_attr($id), $checked, esc_attr($id), $iconHtml, esc_html($label)
|
|
);
|
|
}
|
|
|
|
private function buildTextInput(string $id, string $label, string $value, string $placeholder = ''): string
|
|
{
|
|
return sprintf(
|
|
'<div class="mb-3">
|
|
<label for="%s" class="form-label small fw-semibold">%s</label>
|
|
<input type="text" class="form-control form-control-sm" id="%s" value="%s" placeholder="%s">
|
|
</div>',
|
|
esc_attr($id), esc_html($label), esc_attr($id), esc_attr($value), esc_attr($placeholder)
|
|
);
|
|
}
|
|
|
|
private function buildTextarea(string $id, string $label, string $value, string $placeholder = ''): string
|
|
{
|
|
return sprintf(
|
|
'<div class="mb-3">
|
|
<label for="%s" class="form-label small fw-semibold">%s</label>
|
|
<textarea class="form-control form-control-sm" id="%s" rows="2" placeholder="%s">%s</textarea>
|
|
</div>',
|
|
esc_attr($id), esc_html($label), esc_attr($id), esc_attr($placeholder), esc_textarea($value)
|
|
);
|
|
}
|
|
|
|
private function buildSelect(string $id, string $label, string $value, array $options): string
|
|
{
|
|
$optionsHtml = '';
|
|
foreach ($options as $optValue => $optLabel) {
|
|
$selected = selected($value, $optValue, false);
|
|
$optionsHtml .= sprintf(
|
|
'<option value="%s" %s>%s</option>',
|
|
esc_attr($optValue),
|
|
$selected,
|
|
esc_html($optLabel)
|
|
);
|
|
}
|
|
|
|
return sprintf(
|
|
'<div class="mb-2">
|
|
<label for="%s" class="form-label small fw-semibold">%s</label>
|
|
<select class="form-select form-select-sm" id="%s">%s</select>
|
|
</div>',
|
|
esc_attr($id), esc_html($label), esc_attr($id), $optionsHtml
|
|
);
|
|
}
|
|
}
|