- Fix container width not applying: css-global-responsive.css now uses CSS variable --roi-container-width instead of hardcoded values - Add 8 Rail format options: slim-small (160x300), slim-medium (160x400), slim-large (160x500), skyscraper (160x600), slim-xlarge (160x700), wide-skyscraper (160x800), half-page (300x600), large-skyscraper (300x1050) - Change rail_top_offset from text input to select with preset values - Fix Rail Ads JavaScript positioning (moved after HTML, added retries) - ThemeSettingsRenderer now always outputs CSS variables for layout 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
619 lines
29 KiB
PHP
619 lines
29 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->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>';
|
|
|
|
$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;">';
|
|
|
|
// 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 rounded" style="background: #e9ecef; border: 1px dashed #6c757d;">';
|
|
$html .= ' <strong>FOOTER</strong>';
|
|
$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>';
|
|
|
|
$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 .= '</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 - Opciones de altura para anuncios verticales
|
|
$railFormat = $this->renderer->getFieldValue($cid, 'behavior', 'rail_format', 'skyscraper');
|
|
$html .= $this->buildSelect($cid . 'RailFormat', 'Formato',
|
|
$railFormat,
|
|
[
|
|
'slim-small' => 'Slim Small (160x300)',
|
|
'slim-medium' => 'Slim Medium (160x400)',
|
|
'slim-large' => 'Slim Large (160x500)',
|
|
'skyscraper' => 'Skyscraper (160x600)',
|
|
'slim-xlarge' => 'Slim XLarge (160x700)',
|
|
'wide-skyscraper' => 'Wide Skyscraper (160x800)',
|
|
'half-page' => 'Half Page (300x600)',
|
|
'large-skyscraper' => 'Large Skyscraper (300x1050)'
|
|
]
|
|
);
|
|
|
|
// 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;
|
|
}
|
|
|
|
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
|
|
);
|
|
}
|
|
}
|