refactor: move Analytics from ThemeSettings to AdsensePlacement
- Remove Analytics and AdSense tabs from theme-settings component - Add Analytics group to adsense-placement component - Add roi_enqueue_analytics_script() for GA4/UA support - Clean up ThemeSettings to only handle custom code (CSS/JS) - Update FormBuilders and FieldMappers accordingly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -17,10 +17,14 @@ final class AdsensePlacementFieldMapper implements FieldMapperInterface
|
|||||||
return [
|
return [
|
||||||
// VISIBILITY
|
// VISIBILITY
|
||||||
'adsense-placementEnabled' => ['group' => 'visibility', 'attribute' => 'is_enabled'],
|
'adsense-placementEnabled' => ['group' => 'visibility', 'attribute' => 'is_enabled'],
|
||||||
'adsense-placementDisableAutoAds' => ['group' => 'visibility', 'attribute' => 'disable_auto_ads'],
|
|
||||||
'adsense-placementShowOnMobile' => ['group' => 'visibility', 'attribute' => 'show_on_mobile'],
|
'adsense-placementShowOnMobile' => ['group' => 'visibility', 'attribute' => 'show_on_mobile'],
|
||||||
'adsense-placementShowOnDesktop' => ['group' => 'visibility', 'attribute' => 'show_on_desktop'],
|
'adsense-placementShowOnDesktop' => ['group' => 'visibility', 'attribute' => 'show_on_desktop'],
|
||||||
|
|
||||||
|
// ANALYTICS (Google Analytics)
|
||||||
|
'adsense-placementAnalyticsEnabled' => ['group' => 'analytics', 'attribute' => 'analytics_enabled'],
|
||||||
|
'adsense-placementGaTrackingId' => ['group' => 'analytics', 'attribute' => 'ga_tracking_id'],
|
||||||
|
'adsense-placementGaAnonymizeIp' => ['group' => 'analytics', 'attribute' => 'ga_anonymize_ip'],
|
||||||
|
|
||||||
// CONTENT (Credentials)
|
// CONTENT (Credentials)
|
||||||
'adsense-placementPublisherId' => ['group' => 'content', 'attribute' => 'publisher_id'],
|
'adsense-placementPublisherId' => ['group' => 'content', 'attribute' => 'publisher_id'],
|
||||||
'adsense-placementSlotDisplay' => ['group' => 'content', 'attribute' => 'slot_display'],
|
'adsense-placementSlotDisplay' => ['group' => 'content', 'attribute' => 'slot_display'],
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace ROITheme\Admin\AdsensePlacement\Infrastructure\Ui;
|
|||||||
use ROITheme\Admin\Infrastructure\Ui\AdminDashboardRenderer;
|
use ROITheme\Admin\Infrastructure\Ui\AdminDashboardRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FormBuilder para AdSense Placement
|
* FormBuilder para AdSense Placement y Google Analytics
|
||||||
*/
|
*/
|
||||||
final class AdsensePlacementFormBuilder
|
final class AdsensePlacementFormBuilder
|
||||||
{
|
{
|
||||||
@@ -24,10 +24,10 @@ final class AdsensePlacementFormBuilder
|
|||||||
$html .= ' <div>';
|
$html .= ' <div>';
|
||||||
$html .= ' <h3 class="h4 mb-1 fw-bold">';
|
$html .= ' <h3 class="h4 mb-1 fw-bold">';
|
||||||
$html .= ' <i class="bi bi-megaphone me-2" style="color: #FF8600;"></i>';
|
$html .= ' <i class="bi bi-megaphone me-2" style="color: #FF8600;"></i>';
|
||||||
$html .= ' Control de Anuncios AdSense';
|
$html .= ' AdSense y Analytics';
|
||||||
$html .= ' </h3>';
|
$html .= ' </h3>';
|
||||||
$html .= ' <p class="mb-0 small" style="opacity: 0.85;">';
|
$html .= ' <p class="mb-0 small" style="opacity: 0.85;">';
|
||||||
$html .= ' Configura ubicaciones manuales de anuncios para evitar Auto Ads';
|
$html .= ' Configura Google AdSense y Google Analytics';
|
||||||
$html .= ' </p>';
|
$html .= ' </p>';
|
||||||
$html .= ' </div>';
|
$html .= ' </div>';
|
||||||
$html .= ' </div>';
|
$html .= ' </div>';
|
||||||
@@ -39,6 +39,7 @@ final class AdsensePlacementFormBuilder
|
|||||||
// COLUMNA IZQUIERDA
|
// COLUMNA IZQUIERDA
|
||||||
$html .= ' <div class="col-lg-6">';
|
$html .= ' <div class="col-lg-6">';
|
||||||
$html .= $this->buildVisibilityGroup($componentId);
|
$html .= $this->buildVisibilityGroup($componentId);
|
||||||
|
$html .= $this->buildAnalyticsGroup($componentId);
|
||||||
$html .= $this->buildCredentialsGroup($componentId);
|
$html .= $this->buildCredentialsGroup($componentId);
|
||||||
$html .= $this->buildPostLocationsGroup($componentId);
|
$html .= $this->buildPostLocationsGroup($componentId);
|
||||||
$html .= ' </div>';
|
$html .= ' </div>';
|
||||||
@@ -61,16 +62,12 @@ final class AdsensePlacementFormBuilder
|
|||||||
$html .= ' <div class="card-body">';
|
$html .= ' <div class="card-body">';
|
||||||
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
||||||
$html .= ' <i class="bi bi-toggle-on me-2" style="color: #FF8600;"></i>';
|
$html .= ' <i class="bi bi-toggle-on me-2" style="color: #FF8600;"></i>';
|
||||||
$html .= ' Activacion y Visibilidad';
|
$html .= ' Activacion AdSense';
|
||||||
$html .= ' </h5>';
|
$html .= ' </h5>';
|
||||||
|
|
||||||
// Switch: Enabled
|
// Switch: Enabled
|
||||||
$enabled = $this->renderer->getFieldValue($cid, 'visibility', 'is_enabled', false);
|
$enabled = $this->renderer->getFieldValue($cid, 'visibility', 'is_enabled', false);
|
||||||
$html .= $this->buildSwitch($cid . 'Enabled', 'Activar Placement Manual', $enabled, 'bi-power');
|
$html .= $this->buildSwitch($cid . 'Enabled', 'Activar AdSense', $enabled, 'bi-power');
|
||||||
|
|
||||||
// Switch: Disable Auto Ads
|
|
||||||
$disableAuto = $this->renderer->getFieldValue($cid, 'visibility', 'disable_auto_ads', true);
|
|
||||||
$html .= $this->buildSwitch($cid . 'DisableAutoAds', 'Deshabilitar Auto Ads de Google', $disableAuto, 'bi-shield-x');
|
|
||||||
|
|
||||||
// Switch: Show on Mobile
|
// Switch: Show on Mobile
|
||||||
$showMobile = $this->renderer->getFieldValue($cid, 'visibility', 'show_on_mobile', true);
|
$showMobile = $this->renderer->getFieldValue($cid, 'visibility', 'show_on_mobile', true);
|
||||||
@@ -86,6 +83,39 @@ final class AdsensePlacementFormBuilder
|
|||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildAnalyticsGroup(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-graph-up me-2" style="color: #FF8600;"></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 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 class="alert alert-warning small mb-0 mt-2">';
|
||||||
|
$html .= ' <i class="bi bi-exclamation-triangle me-1"></i>';
|
||||||
|
$html .= ' Recomendado activar para cumplir con GDPR/RGPD';
|
||||||
|
$html .= ' </div>';
|
||||||
|
|
||||||
|
$html .= ' </div>';
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
private function buildCredentialsGroup(string $cid): string
|
private function buildCredentialsGroup(string $cid): string
|
||||||
{
|
{
|
||||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
||||||
|
|||||||
@@ -24,14 +24,6 @@ final class ThemeSettingsFieldMapper implements FieldMapperInterface
|
|||||||
public function getFieldMapping(): array
|
public function getFieldMapping(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
// Analytics
|
|
||||||
'themeSettingsGaTrackingId' => ['group' => 'analytics', 'attribute' => 'ga_tracking_id'],
|
|
||||||
'themeSettingsGaAnonymizeIp' => ['group' => 'analytics', 'attribute' => 'ga_anonymize_ip'],
|
|
||||||
|
|
||||||
// AdSense
|
|
||||||
'themeSettingsAdsensePublisherId' => ['group' => 'adsense', 'attribute' => 'adsense_publisher_id'],
|
|
||||||
'themeSettingsAdsenseAutoAds' => ['group' => 'adsense', 'attribute' => 'adsense_auto_ads'],
|
|
||||||
|
|
||||||
// Custom Code
|
// Custom Code
|
||||||
'themeSettingsCustomCss' => ['group' => 'custom_code', 'attribute' => 'custom_css'],
|
'themeSettingsCustomCss' => ['group' => 'custom_code', 'attribute' => 'custom_css'],
|
||||||
'themeSettingsCustomJsHeader' => ['group' => 'custom_code', 'attribute' => 'custom_js_header'],
|
'themeSettingsCustomJsHeader' => ['group' => 'custom_code', 'attribute' => 'custom_js_header'],
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ use ROITheme\Admin\Infrastructure\Ui\AdminDashboardRenderer;
|
|||||||
* FormBuilder para Theme Settings
|
* FormBuilder para Theme Settings
|
||||||
*
|
*
|
||||||
* RESPONSABILIDAD: Generar formulario de configuraciones globales del tema
|
* RESPONSABILIDAD: Generar formulario de configuraciones globales del tema
|
||||||
* (analytics, adsense, codigo personalizado)
|
* (codigo personalizado - CSS y JavaScript)
|
||||||
*
|
*
|
||||||
* NOTA: Logo/branding se gestiona desde el componente navbar
|
* NOTA: Analytics y AdSense se gestionan desde el componente adsense-placement
|
||||||
*
|
*
|
||||||
* @package ROITheme\Admin\ThemeSettings\Infrastructure\Ui
|
* @package ROITheme\Admin\ThemeSettings\Infrastructure\Ui
|
||||||
*/
|
*/
|
||||||
@@ -29,14 +29,8 @@ final class ThemeSettingsFormBuilder
|
|||||||
|
|
||||||
$html .= '<div class="row g-3">';
|
$html .= '<div class="row g-3">';
|
||||||
|
|
||||||
// Columna izquierda - Analytics + AdSense
|
// Columna unica - Custom Code
|
||||||
$html .= '<div class="col-lg-6">';
|
$html .= '<div class="col-lg-8 mx-auto">';
|
||||||
$html .= $this->buildAnalyticsGroup($componentId);
|
|
||||||
$html .= $this->buildAdSenseGroup($componentId);
|
|
||||||
$html .= '</div>';
|
|
||||||
|
|
||||||
// Columna derecha - Custom Code
|
|
||||||
$html .= '<div class="col-lg-6">';
|
|
||||||
$html .= $this->buildCustomCodeGroup($componentId);
|
$html .= $this->buildCustomCodeGroup($componentId);
|
||||||
$html .= '</div>';
|
$html .= '</div>';
|
||||||
|
|
||||||
@@ -56,7 +50,7 @@ final class ThemeSettingsFormBuilder
|
|||||||
$html .= ' Configuraciones Globales del Tema';
|
$html .= ' Configuraciones Globales del Tema';
|
||||||
$html .= ' </h3>';
|
$html .= ' </h3>';
|
||||||
$html .= ' <p class="mb-0 small" style="opacity: 0.85;">';
|
$html .= ' <p class="mb-0 small" style="opacity: 0.85;">';
|
||||||
$html .= ' Analytics, AdSense y Codigo Personalizado';
|
$html .= ' Codigo Personalizado (CSS y JavaScript)';
|
||||||
$html .= ' </p>';
|
$html .= ' </p>';
|
||||||
$html .= ' </div>';
|
$html .= ' </div>';
|
||||||
$html .= ' <button type="button" class="btn btn-sm btn-outline-light btn-reset-defaults" data-component="theme-settings">';
|
$html .= ' <button type="button" class="btn btn-sm btn-outline-light btn-reset-defaults" data-component="theme-settings">';
|
||||||
@@ -69,62 +63,6 @@ final class ThemeSettingsFormBuilder
|
|||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildAnalyticsGroup(string $componentId): 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-graph-up me-2" style="color: #FF8600;"></i>';
|
|
||||||
$html .= ' Analytics';
|
|
||||||
$html .= ' </h5>';
|
|
||||||
|
|
||||||
$gaTrackingId = $this->renderer->getFieldValue($componentId, 'analytics', 'ga_tracking_id', '');
|
|
||||||
$html .= $this->buildTextInput('themeSettingsGaTrackingId', 'Google Analytics ID', 'bi-bar-chart', $gaTrackingId);
|
|
||||||
|
|
||||||
$html .= ' <div class="form-text small mb-2">Formato: G-XXXXXXXXXX o UA-XXXXXXXX-X</div>';
|
|
||||||
|
|
||||||
$gaAnonymizeIp = $this->renderer->getFieldValue($componentId, 'analytics', 'ga_anonymize_ip', true);
|
|
||||||
$html .= $this->buildSwitch('themeSettingsGaAnonymizeIp', 'Anonimizar IP (GDPR)', 'bi-shield-check', $gaAnonymizeIp);
|
|
||||||
|
|
||||||
$html .= ' <div class="alert alert-warning small mb-0 mt-2">';
|
|
||||||
$html .= ' <i class="bi bi-exclamation-triangle me-1"></i>';
|
|
||||||
$html .= ' Recomendado activar para cumplir con GDPR/RGPD';
|
|
||||||
$html .= ' </div>';
|
|
||||||
|
|
||||||
$html .= ' </div>';
|
|
||||||
$html .= '</div>';
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildAdSenseGroup(string $componentId): 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-badge-ad me-2" style="color: #FF8600;"></i>';
|
|
||||||
$html .= ' Google AdSense';
|
|
||||||
$html .= ' </h5>';
|
|
||||||
|
|
||||||
$publisherId = $this->renderer->getFieldValue($componentId, 'adsense', 'adsense_publisher_id', '');
|
|
||||||
$html .= $this->buildTextInput('themeSettingsAdsensePublisherId', 'Publisher ID', 'bi-key', $publisherId);
|
|
||||||
|
|
||||||
$html .= ' <div class="form-text small mb-2">Formato: ca-pub-1234567890123456</div>';
|
|
||||||
|
|
||||||
$autoAds = $this->renderer->getFieldValue($componentId, 'adsense', 'adsense_auto_ads', false);
|
|
||||||
$html .= $this->buildSwitch('themeSettingsAdsenseAutoAds', 'Activar Auto Ads', 'bi-magic', $autoAds);
|
|
||||||
|
|
||||||
$html .= ' <div class="alert alert-info small mb-0 mt-2">';
|
|
||||||
$html .= ' <i class="bi bi-info-circle me-1"></i>';
|
|
||||||
$html .= ' Auto Ads permite que Google coloque anuncios automaticamente en las mejores ubicaciones.';
|
|
||||||
$html .= ' </div>';
|
|
||||||
|
|
||||||
$html .= ' </div>';
|
|
||||||
$html .= '</div>';
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildCustomCodeGroup(string $componentId): string
|
private function buildCustomCodeGroup(string $componentId): string
|
||||||
{
|
{
|
||||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
||||||
@@ -154,37 +92,6 @@ final class ThemeSettingsFormBuilder
|
|||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper methods
|
|
||||||
private function buildSwitch(string $id, string $label, string $icon, $value): string
|
|
||||||
{
|
|
||||||
$checked = $value === true || $value === '1' || $value === 1 ? 'checked' : '';
|
|
||||||
|
|
||||||
$html = ' <div class="form-check form-switch mb-2">';
|
|
||||||
$html .= ' <input class="form-check-input" type="checkbox" id="' . esc_attr($id) . '" ' . $checked . '>';
|
|
||||||
$html .= ' <label class="form-check-label small" for="' . esc_attr($id) . '">';
|
|
||||||
$html .= ' <i class="bi ' . esc_attr($icon) . ' me-1" style="color: #FF8600;"></i>';
|
|
||||||
$html .= ' ' . esc_html($label);
|
|
||||||
$html .= ' </label>';
|
|
||||||
$html .= ' </div>';
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildTextInput(string $id, string $label, string $icon, mixed $value): string
|
|
||||||
{
|
|
||||||
$value = $this->normalizeStringValue($value);
|
|
||||||
|
|
||||||
$html = ' <div class="mb-3">';
|
|
||||||
$html .= ' <label for="' . esc_attr($id) . '" class="form-label small mb-1 fw-semibold">';
|
|
||||||
$html .= ' <i class="bi ' . esc_attr($icon) . ' me-1" style="color: #FF8600;"></i>';
|
|
||||||
$html .= ' ' . esc_html($label);
|
|
||||||
$html .= ' </label>';
|
|
||||||
$html .= ' <input type="text" class="form-control form-control-sm" id="' . esc_attr($id) . '" value="' . esc_attr($value) . '">';
|
|
||||||
$html .= ' </div>';
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildTextareaCode(string $id, string $label, string $icon, mixed $value, string $helpText = ''): string
|
private function buildTextareaCode(string $id, string $label, string $icon, mixed $value, string $helpText = ''): string
|
||||||
{
|
{
|
||||||
$value = $this->normalizeStringValue($value);
|
$value = $this->normalizeStringValue($value);
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* AdSense Placement - Helper Functions
|
* AdSense Placement & Google Analytics - Helper Functions
|
||||||
*
|
*
|
||||||
* Funciones para usar en templates:
|
* Funciones para usar en templates:
|
||||||
* - roi_render_ad_slot('post-top')
|
* - roi_render_ad_slot('post-top')
|
||||||
* - roi_render_rail_ads() - Para los margenes laterales del viewport
|
* - roi_render_rail_ads() - Para los margenes laterales del viewport
|
||||||
|
*
|
||||||
|
* Funciones auto-registradas en wp_head:
|
||||||
|
* - roi_enqueue_adsense_script() - Script principal de AdSense
|
||||||
|
* - roi_enqueue_analytics_script() - Script de Google Analytics
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('ABSPATH')) {
|
if (!defined('ABSPATH')) {
|
||||||
@@ -231,3 +235,106 @@ function roi_inject_content_ads(string $content): string
|
|||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Carga el script de Google Analytics (GA4 o Universal Analytics)
|
||||||
|
*/
|
||||||
|
function roi_enqueue_analytics_script(): void
|
||||||
|
{
|
||||||
|
global $container;
|
||||||
|
|
||||||
|
if ($container === null || is_admin()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$repository = $container->getComponentSettingsRepository();
|
||||||
|
$settings = $repository->getComponentSettings('adsense-placement');
|
||||||
|
|
||||||
|
// Verificar si Analytics esta habilitado
|
||||||
|
if (!($settings['analytics']['analytics_enabled'] ?? false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$trackingId = trim($settings['analytics']['ga_tracking_id'] ?? '');
|
||||||
|
if (empty($trackingId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar si GA ya esta cargado por otro plugin
|
||||||
|
if (roi_is_analytics_loaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$anonymizeIp = ($settings['analytics']['ga_anonymize_ip'] ?? true) === true;
|
||||||
|
|
||||||
|
// Detectar tipo de ID (GA4 vs Universal Analytics)
|
||||||
|
if (strpos($trackingId, 'G-') === 0) {
|
||||||
|
roi_render_ga4_script($trackingId, $anonymizeIp);
|
||||||
|
} elseif (strpos($trackingId, 'UA-') === 0) {
|
||||||
|
roi_render_universal_analytics_script($trackingId, $anonymizeIp);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||||
|
error_log('ROI Analytics: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action('wp_head', 'roi_enqueue_analytics_script', 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica si Google Analytics ya esta cargado por otro plugin
|
||||||
|
*/
|
||||||
|
function roi_is_analytics_loaded(): bool
|
||||||
|
{
|
||||||
|
// Verificar si MonsterInsights esta activo
|
||||||
|
if (class_exists('MonsterInsights_Lite') || class_exists('MonsterInsights')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar si Site Kit de Google esta activo
|
||||||
|
if (class_exists('Google\Site_Kit\Plugin')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renderiza script de Google Analytics 4
|
||||||
|
*/
|
||||||
|
function roi_render_ga4_script(string $trackingId, bool $anonymizeIp): void
|
||||||
|
{
|
||||||
|
$config = $anonymizeIp ? "{ 'anonymize_ip': true }" : '{}';
|
||||||
|
|
||||||
|
echo '<!-- Google Analytics 4 (ROI Theme) -->' . "\n";
|
||||||
|
echo '<script async src="https://www.googletagmanager.com/gtag/js?id=' . esc_attr($trackingId) . '"></script>' . "\n";
|
||||||
|
echo '<script>' . "\n";
|
||||||
|
echo 'window.dataLayer = window.dataLayer || [];' . "\n";
|
||||||
|
echo 'function gtag(){dataLayer.push(arguments);}' . "\n";
|
||||||
|
echo 'gtag("js", new Date());' . "\n";
|
||||||
|
echo 'gtag("config", "' . esc_js($trackingId) . '", ' . $config . ');' . "\n";
|
||||||
|
echo '</script>' . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renderiza script de Universal Analytics (legacy)
|
||||||
|
*/
|
||||||
|
function roi_render_universal_analytics_script(string $trackingId, bool $anonymizeIp): void
|
||||||
|
{
|
||||||
|
$anonymizeConfig = $anonymizeIp ? 'ga("set", "anonymizeIp", true);' : '';
|
||||||
|
|
||||||
|
echo '<!-- Universal Analytics (ROI Theme) -->' . "\n";
|
||||||
|
echo '<script>' . "\n";
|
||||||
|
echo '(function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){' . "\n";
|
||||||
|
echo '(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),' . "\n";
|
||||||
|
echo 'm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)' . "\n";
|
||||||
|
echo '})(window,document,"script","https://www.google-analytics.com/analytics.js","ga");' . "\n";
|
||||||
|
echo 'ga("create", "' . esc_js($trackingId) . '", "auto");' . "\n";
|
||||||
|
if (!empty($anonymizeConfig)) {
|
||||||
|
echo $anonymizeConfig . "\n";
|
||||||
|
}
|
||||||
|
echo 'ga("send", "pageview");' . "\n";
|
||||||
|
echo '</script>' . "\n";
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,14 +13,10 @@ use ROITheme\Shared\Domain\Entities\Component;
|
|||||||
* A diferencia de otros componentes, no renderiza HTML visual
|
* A diferencia de otros componentes, no renderiza HTML visual
|
||||||
* sino que genera codigo para inyectar en wp_head y wp_footer.
|
* sino que genera codigo para inyectar en wp_head y wp_footer.
|
||||||
*
|
*
|
||||||
* NOTA: Este es un componente especial que NO requiere:
|
* NOTA: Este es un componente especial que solo maneja codigo personalizado.
|
||||||
* - CSSGeneratorInterface (no genera CSS, solo inyecta CSS del usuario)
|
* Analytics y AdSense se gestionan desde el componente adsense-placement.
|
||||||
* - Grupo visibility (siempre esta activo, configuraciones globales)
|
|
||||||
* - Metodo getVisibilityClasses (no es un componente visual)
|
|
||||||
*
|
*
|
||||||
* Responsabilidades:
|
* Responsabilidades:
|
||||||
* - Generar script de Google Analytics
|
|
||||||
* - Generar script de Google AdSense Auto Ads
|
|
||||||
* - Generar CSS personalizado
|
* - Generar CSS personalizado
|
||||||
* - Generar JavaScript para header
|
* - Generar JavaScript para header
|
||||||
* - Generar JavaScript para footer
|
* - Generar JavaScript para footer
|
||||||
@@ -54,8 +50,6 @@ final class ThemeSettingsRenderer implements RendererInterface
|
|||||||
* Genera contenido para wp_head
|
* Genera contenido para wp_head
|
||||||
*
|
*
|
||||||
* Incluye:
|
* Incluye:
|
||||||
* - Google Analytics script (si configurado)
|
|
||||||
* - Google AdSense Auto Ads script (si configurado)
|
|
||||||
* - Custom CSS (si configurado)
|
* - Custom CSS (si configurado)
|
||||||
* - Custom JS Header (si configurado)
|
* - Custom JS Header (si configurado)
|
||||||
*
|
*
|
||||||
@@ -64,25 +58,8 @@ final class ThemeSettingsRenderer implements RendererInterface
|
|||||||
*/
|
*/
|
||||||
public function renderHeadContent(array $data): string
|
public function renderHeadContent(array $data): string
|
||||||
{
|
{
|
||||||
// Validar visibilidad general
|
|
||||||
if (!$this->isEnabled($data)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$output = '';
|
$output = '';
|
||||||
|
|
||||||
// Google Analytics
|
|
||||||
$gaOutput = $this->renderGoogleAnalytics($data);
|
|
||||||
if (!empty($gaOutput)) {
|
|
||||||
$output .= $gaOutput . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Google AdSense Auto Ads
|
|
||||||
$adsenseOutput = $this->renderAdSenseAutoAds($data);
|
|
||||||
if (!empty($adsenseOutput)) {
|
|
||||||
$output .= $adsenseOutput . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom CSS
|
// Custom CSS
|
||||||
$cssOutput = $this->renderCustomCSS($data);
|
$cssOutput = $this->renderCustomCSS($data);
|
||||||
if (!empty($cssOutput)) {
|
if (!empty($cssOutput)) {
|
||||||
@@ -109,170 +86,9 @@ final class ThemeSettingsRenderer implements RendererInterface
|
|||||||
*/
|
*/
|
||||||
public function renderFooterContent(array $data): string
|
public function renderFooterContent(array $data): string
|
||||||
{
|
{
|
||||||
// Validar visibilidad general
|
|
||||||
if (!$this->isEnabled($data)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->renderCustomJSFooter($data);
|
return $this->renderCustomJSFooter($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifica si el componente esta habilitado
|
|
||||||
*
|
|
||||||
* NOTA: Theme Settings es un componente de configuracion global
|
|
||||||
* que siempre esta activo. No tiene grupo visibility.
|
|
||||||
* Si el usuario no quiere GA o CSS custom, simplemente deja
|
|
||||||
* los campos vacios.
|
|
||||||
*
|
|
||||||
* @param array $data Datos del componente (no usado)
|
|
||||||
* @return bool Siempre true
|
|
||||||
*/
|
|
||||||
private function isEnabled(array $data): bool
|
|
||||||
{
|
|
||||||
// Theme Settings siempre esta activo (configuraciones globales)
|
|
||||||
// Los campos individuales se validan en sus metodos respectivos
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Genera el script de Google Analytics
|
|
||||||
*
|
|
||||||
* @param array $data Datos del componente
|
|
||||||
* @return string Script de GA o vacio si no configurado
|
|
||||||
*/
|
|
||||||
private function renderGoogleAnalytics(array $data): string
|
|
||||||
{
|
|
||||||
$trackingId = trim($data['analytics']['ga_tracking_id'] ?? '');
|
|
||||||
|
|
||||||
if (empty($trackingId)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verificar si GA ya esta cargado por otro plugin
|
|
||||||
if ($this->isGoogleAnalyticsLoaded()) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$anonymizeIp = ($data['analytics']['ga_anonymize_ip'] ?? true) === true;
|
|
||||||
|
|
||||||
// Detectar tipo de ID (GA4 vs Universal Analytics)
|
|
||||||
if (strpos($trackingId, 'G-') === 0) {
|
|
||||||
// Google Analytics 4
|
|
||||||
return $this->renderGA4Script($trackingId, $anonymizeIp);
|
|
||||||
} elseif (strpos($trackingId, 'UA-') === 0) {
|
|
||||||
// Universal Analytics (legacy)
|
|
||||||
return $this->renderUniversalAnalyticsScript($trackingId, $anonymizeIp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Genera script de Google Analytics 4
|
|
||||||
*
|
|
||||||
* @param string $trackingId ID de GA4 (G-XXXXXXXXXX)
|
|
||||||
* @param bool $anonymizeIp Si anonimizar IP
|
|
||||||
* @return string Script HTML
|
|
||||||
*/
|
|
||||||
private function renderGA4Script(string $trackingId, bool $anonymizeIp): string
|
|
||||||
{
|
|
||||||
$config = $anonymizeIp ? "{ 'anonymize_ip': true }" : '{}';
|
|
||||||
|
|
||||||
return sprintf(
|
|
||||||
'<!-- Google Analytics 4 (ROI Theme) -->
|
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=%1$s"></script>
|
|
||||||
<script>
|
|
||||||
window.dataLayer = window.dataLayer || [];
|
|
||||||
function gtag(){dataLayer.push(arguments);}
|
|
||||||
gtag("js", new Date());
|
|
||||||
gtag("config", "%1$s", %2$s);
|
|
||||||
</script>',
|
|
||||||
esc_attr($trackingId),
|
|
||||||
$config
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Genera script de Universal Analytics (legacy)
|
|
||||||
*
|
|
||||||
* @param string $trackingId ID de UA (UA-XXXXXXXX-X)
|
|
||||||
* @param bool $anonymizeIp Si anonimizar IP
|
|
||||||
* @return string Script HTML
|
|
||||||
*/
|
|
||||||
private function renderUniversalAnalyticsScript(string $trackingId, bool $anonymizeIp): string
|
|
||||||
{
|
|
||||||
$anonymizeConfig = $anonymizeIp ? "ga('set', 'anonymizeIp', true);" : '';
|
|
||||||
|
|
||||||
return sprintf(
|
|
||||||
'<!-- Universal Analytics (ROI Theme) -->
|
|
||||||
<script>
|
|
||||||
(function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){
|
|
||||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
|
||||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
|
||||||
})(window,document,"script","https://www.google-analytics.com/analytics.js","ga");
|
|
||||||
ga("create", "%s", "auto");
|
|
||||||
%s
|
|
||||||
ga("send", "pageview");
|
|
||||||
</script>',
|
|
||||||
esc_attr($trackingId),
|
|
||||||
$anonymizeConfig
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifica si Google Analytics ya esta cargado
|
|
||||||
*
|
|
||||||
* @return bool True si ya esta cargado por otro plugin
|
|
||||||
*/
|
|
||||||
private function isGoogleAnalyticsLoaded(): bool
|
|
||||||
{
|
|
||||||
// Verificar plugins comunes de GA
|
|
||||||
if (function_exists('gtag')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verificar si MonsterInsights esta activo
|
|
||||||
if (class_exists('MonsterInsights_Lite') || class_exists('MonsterInsights')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verificar si Site Kit de Google esta activo
|
|
||||||
if (class_exists('Google\Site_Kit\Plugin')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Genera el script de Google AdSense Auto Ads
|
|
||||||
*
|
|
||||||
* @param array $data Datos del componente
|
|
||||||
* @return string Script de AdSense o vacio si no configurado
|
|
||||||
*/
|
|
||||||
private function renderAdSenseAutoAds(array $data): string
|
|
||||||
{
|
|
||||||
$publisherId = trim($data['adsense']['adsense_publisher_id'] ?? '');
|
|
||||||
$autoAdsEnabled = ($data['adsense']['adsense_auto_ads'] ?? false) === true;
|
|
||||||
|
|
||||||
// Solo mostrar si tiene publisher ID y auto ads esta activado
|
|
||||||
if (empty($publisherId) || !$autoAdsEnabled) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validar formato del publisher ID (ca-pub-XXXXXXXXXX)
|
|
||||||
if (!preg_match('/^ca-pub-\d+$/', $publisherId)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf(
|
|
||||||
'<!-- Google AdSense Auto Ads (ROI Theme) -->
|
|
||||||
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=%s" crossorigin="anonymous"></script>',
|
|
||||||
esc_attr($publisherId)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Genera el CSS personalizado
|
* Genera el CSS personalizado
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,27 +1,20 @@
|
|||||||
{
|
{
|
||||||
"component_name": "adsense-placement",
|
"component_name": "adsense-placement",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"description": "Control manual de ubicacion de anuncios AdSense",
|
"description": "Control de AdSense y Google Analytics",
|
||||||
"groups": {
|
"groups": {
|
||||||
"visibility": {
|
"visibility": {
|
||||||
"label": "Visibilidad",
|
"label": "Visibilidad AdSense",
|
||||||
"priority": 10,
|
"priority": 10,
|
||||||
"fields": {
|
"fields": {
|
||||||
"is_enabled": {
|
"is_enabled": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"label": "Activar Placement Manual",
|
"label": "Activar AdSense",
|
||||||
"default": false,
|
"default": false,
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "Activa el control manual de ubicacion de anuncios"
|
"description": "Activa el control manual de ubicacion de anuncios"
|
||||||
},
|
},
|
||||||
"disable_auto_ads": {
|
|
||||||
"type": "boolean",
|
|
||||||
"label": "Deshabilitar Auto Ads",
|
|
||||||
"default": true,
|
|
||||||
"editable": true,
|
|
||||||
"description": "Desactiva Auto Ads de Google cuando el placement manual esta activo"
|
|
||||||
},
|
|
||||||
"show_on_desktop": {
|
"show_on_desktop": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"label": "Mostrar en escritorio",
|
"label": "Mostrar en escritorio",
|
||||||
@@ -38,6 +31,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"analytics": {
|
||||||
|
"label": "Google Analytics",
|
||||||
|
"priority": 15,
|
||||||
|
"fields": {
|
||||||
|
"analytics_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Activar Analytics",
|
||||||
|
"default": false,
|
||||||
|
"editable": true,
|
||||||
|
"description": "Activa Google Analytics en el sitio"
|
||||||
|
},
|
||||||
|
"ga_tracking_id": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Google Analytics ID",
|
||||||
|
"default": "",
|
||||||
|
"editable": true,
|
||||||
|
"description": "ID de seguimiento (G-XXXXXXXXXX o UA-XXXXXXXX-X)"
|
||||||
|
},
|
||||||
|
"ga_anonymize_ip": {
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Anonimizar IP (GDPR)",
|
||||||
|
"default": true,
|
||||||
|
"editable": true,
|
||||||
|
"description": "Recomendado para cumplir con GDPR/RGPD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"label": "Credenciales AdSense",
|
"label": "Credenciales AdSense",
|
||||||
"priority": 20,
|
"priority": 20,
|
||||||
|
|||||||
@@ -1,51 +1,11 @@
|
|||||||
{
|
{
|
||||||
"component_name": "theme-settings",
|
"component_name": "theme-settings",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"description": "Configuraciones globales del tema: analytics, adsense y codigo personalizado",
|
"description": "Configuraciones globales del tema: codigo personalizado",
|
||||||
"groups": {
|
"groups": {
|
||||||
"analytics": {
|
|
||||||
"label": "Analytics",
|
|
||||||
"priority": 10,
|
|
||||||
"fields": {
|
|
||||||
"ga_tracking_id": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Google Analytics ID",
|
|
||||||
"default": "",
|
|
||||||
"editable": true,
|
|
||||||
"description": "ID de seguimiento de Google Analytics (ej: G-XXXXXXXXXX o UA-XXXXXXXX-X)"
|
|
||||||
},
|
|
||||||
"ga_anonymize_ip": {
|
|
||||||
"type": "boolean",
|
|
||||||
"label": "Anonimizar IP",
|
|
||||||
"default": true,
|
|
||||||
"editable": true,
|
|
||||||
"description": "Anonimiza las direcciones IP de los visitantes (recomendado para GDPR)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"adsense": {
|
|
||||||
"label": "Google AdSense",
|
|
||||||
"priority": 20,
|
|
||||||
"fields": {
|
|
||||||
"adsense_publisher_id": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Publisher ID",
|
|
||||||
"default": "",
|
|
||||||
"editable": true,
|
|
||||||
"description": "ID de publicador de AdSense (ej: ca-pub-1234567890123456)"
|
|
||||||
},
|
|
||||||
"adsense_auto_ads": {
|
|
||||||
"type": "boolean",
|
|
||||||
"label": "Activar Auto Ads",
|
|
||||||
"default": false,
|
|
||||||
"editable": true,
|
|
||||||
"description": "Permite que Google coloque anuncios automaticamente en las mejores ubicaciones"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"custom_code": {
|
"custom_code": {
|
||||||
"label": "Codigo Personalizado",
|
"label": "Codigo Personalizado",
|
||||||
"priority": 30,
|
"priority": 10,
|
||||||
"fields": {
|
"fields": {
|
||||||
"custom_css": {
|
"custom_css": {
|
||||||
"type": "textarea",
|
"type": "textarea",
|
||||||
|
|||||||
Reference in New Issue
Block a user