getData(); if (!$this->isEnabled($data)) { return ''; } if (!PageVisibilityHelper::shouldShow(self::COMPONENT_NAME)) { return ''; } if (!$this->hasPostThumbnail()) { return ''; } $html = $this->buildHTML($data); // Si is_critical=true, CSS ya fue inyectado en
por CriticalCSSService $isCritical = $data['visibility']['is_critical'] ?? false; if ($isCritical) { return $html; // Solo HTML, sin CSS inline } // CSS inline para componentes no críticos $css = $this->generateCSS($data); return sprintf("\n%s", $css, $html); } public function supports(string $componentType): bool { return $componentType === self::COMPONENT_NAME; } private function isEnabled(array $data): bool { return ($data['visibility']['is_enabled'] ?? false) === true; } private function hasPostThumbnail(): bool { if (!is_singular() || !has_post_thumbnail()) { return false; } // Verificar que el archivo físico exista, no solo el attachment ID $thumbnailId = get_post_thumbnail_id(); if (!$thumbnailId) { return false; } $filePath = get_attached_file($thumbnailId); if (empty($filePath) || !file_exists($filePath)) { return false; } return true; } /** * Generar CSS usando CSSGeneratorService * * Este método es público para que CriticalCSSService pueda * generar CSS crítico antes de wp_head sin duplicar lógica. * * @param array $data Datos del componente * @return string CSS generado */ public function generateCSS(array $data): string { $spacing = $data['spacing'] ?? []; $effects = $data['visual_effects'] ?? []; $visibility = $data['visibility'] ?? []; $marginTop = $spacing['margin_top'] ?? '1rem'; $marginBottom = $spacing['margin_bottom'] ?? '2rem'; // Aspect ratio para prevenir CLS - reserva espacio antes de que imagen cargue $aspectRatio = $spacing['aspect_ratio'] ?? '16/9'; $borderRadius = $effects['border_radius'] ?? '12px'; $boxShadow = $effects['box_shadow'] ?? '0 8px 24px rgba(0, 0, 0, 0.1)'; $hoverEffect = $effects['hover_effect'] ?? true; $hoverScale = $effects['hover_scale'] ?? '1.02'; $transitionDuration = $effects['transition_duration'] ?? '0.3s'; $showOnDesktop = $visibility['show_on_desktop'] ?? true; $showOnMobile = $visibility['show_on_mobile'] ?? true; $cssRules = []; // Container styles con aspect-ratio para prevenir CLS $cssRules[] = $this->cssGenerator->generate('.featured-image-container', [ 'border-radius' => $borderRadius, 'overflow' => 'hidden', 'box-shadow' => $boxShadow, 'margin-top' => $marginTop, 'margin-bottom' => $marginBottom, 'transition' => "transform {$transitionDuration} ease, box-shadow {$transitionDuration} ease", 'aspect-ratio' => $aspectRatio, 'position' => 'relative', 'background-color' => '#f0f0f0', ]); // Image styles - object-fit para llenar el contenedor con aspect-ratio $cssRules[] = $this->cssGenerator->generate('.featured-image-container img', [ 'width' => '100%', 'height' => '100%', 'object-fit' => 'cover', 'display' => 'block', 'transition' => "transform {$transitionDuration} ease", 'position' => 'absolute', 'top' => '0', 'left' => '0', ]); // Hover effect if ($hoverEffect) { $cssRules[] = $this->cssGenerator->generate('.featured-image-container:hover', [ 'box-shadow' => '0 12px 32px rgba(0, 0, 0, 0.15)', ]); $cssRules[] = $this->cssGenerator->generate('.featured-image-container:hover img', [ 'transform' => "scale({$hoverScale})", ]); } // Link styles (remove default link styling) $cssRules[] = $this->cssGenerator->generate('.featured-image-container a', [ 'display' => 'block', 'line-height' => '0', ]); // Responsive visibility if (!$showOnMobile) { $cssRules[] = "@media (max-width: 767.98px) { .featured-image-container { display: none !important; } }"; } if (!$showOnDesktop) { $cssRules[] = "@media (min-width: 768px) { .featured-image-container { display: none !important; } }"; } return implode("\n", $cssRules); } private function buildHTML(array $data): string { $content = $data['content'] ?? []; $imageSize = $content['image_size'] ?? 'roi-featured-large'; $lazyLoading = $content['lazy_loading'] ?? false; // LCP: no lazy por defecto $linkToMedia = $content['link_to_media'] ?? false; $imgAttr = [ 'class' => 'img-fluid featured-image', 'alt' => get_the_title(), 'fetchpriority' => 'high', // LCP optimization ]; if ($lazyLoading) { $imgAttr['loading'] = 'lazy'; unset($imgAttr['fetchpriority']); // No fetchpriority si es lazy } $thumbnail = get_the_post_thumbnail(null, $imageSize, $imgAttr); if (empty($thumbnail)) { return ''; } $html = '