componentId = $componentId; $this->data = $data; } public function build(): string { $data = $this->data; $componentId = $this->componentId; $html = '
'; $html .= $this->buildTabsNavigation(); $html .= '
'; $html .= $this->buildVisibilityTab($data, $componentId); $html .= $this->buildCategoriesTab($data, $componentId); $html .= $this->buildTitleTab($data, $componentId); $html .= $this->buildStylesTab($data, $componentId); $html .= '
'; $html .= $this->buildFormScripts($componentId); return $html; } private function buildTabsNavigation(): string { return << HTML; } private function buildVisibilityTab(array $data, string $componentId): string { $html = '
'; $isEnabled = $data['visibility']['is_enabled'] ?? true; $html .= $this->buildToggle('is_enabled', 'Mostrar hero section', $isEnabled, $componentId, 'visibility'); $showOn = $data['visibility']['show_on_pages'] ?? 'posts'; $html .= $this->buildSelect('show_on_pages', 'Mostrar en', $showOn, ['all' => 'Todas las páginas', 'home' => 'Solo página de inicio', 'posts' => 'Solo posts individuales', 'pages' => 'Solo páginas', 'custom' => 'Tipos de post específicos'], $componentId, 'visibility'); $customPostTypes = $data['visibility']['custom_post_types'] ?? ''; $html .= $this->buildTextField('custom_post_types', 'Tipos de post personalizados', $customPostTypes, $componentId, 'visibility', 'Ej: post,page,producto', ['data-conditional-field' => 'show_on_pages', 'data-conditional-value' => 'custom']); $html .= '
'; return $html; } private function buildCategoriesTab(array $data, string $componentId): string { $html = '
'; $showCategories = $data['categories']['show_categories'] ?? true; $html .= $this->buildToggle('show_categories', 'Mostrar badges de categorías', $showCategories, $componentId, 'categories'); $categoriesSource = $data['categories']['categories_source'] ?? 'post_categories'; $html .= $this->buildSelect('categories_source', 'Fuente de categorías', $categoriesSource, ['post_categories' => 'Categorías del post', 'post_tags' => 'Etiquetas del post', 'custom_taxonomy' => 'Taxonomía personalizada', 'custom_list' => 'Lista personalizada'], $componentId, 'categories', ['data-conditional-field' => 'show_categories', 'data-conditional-value' => 'true']); $customTaxonomy = $data['categories']['custom_taxonomy_name'] ?? ''; $html .= $this->buildTextField('custom_taxonomy_name', 'Nombre de taxonomía personalizada', $customTaxonomy, $componentId, 'categories', 'Ej: project_category', ['data-conditional-field' => 'categories_source', 'data-conditional-value' => 'custom_taxonomy']); $customList = $data['categories']['custom_categories_list'] ?? ''; $html .= $this->buildTextArea('custom_categories_list', 'Lista personalizada de categorías', $customList, $componentId, 'categories', 'Análisis de Precios|#', 5, ['data-conditional-field' => 'categories_source', 'data-conditional-value' => 'custom_list']); $maxCategories = $data['categories']['max_categories'] ?? 5; $html .= $this->buildNumberField('max_categories', 'Máximo de categorías a mostrar', $maxCategories, $componentId, 'categories', 1, 20, ['data-conditional-field' => 'show_categories', 'data-conditional-value' => 'true']); $categoryIcon = $data['categories']['category_icon'] ?? 'bi-folder-fill'; $html .= $this->buildTextField('category_icon', 'Ícono de categoría', $categoryIcon, $componentId, 'categories', 'Ej: bi-folder-fill', ['data-conditional-field' => 'show_categories', 'data-conditional-value' => 'true']); $categoriesAlignment = $data['categories']['categories_alignment'] ?? 'center'; $html .= $this->buildSelect('categories_alignment', 'Alineación de categorías', $categoriesAlignment, ['left' => 'Izquierda', 'center' => 'Centro', 'right' => 'Derecha'], $componentId, 'categories', ['data-conditional-field' => 'show_categories', 'data-conditional-value' => 'true']); $html .= '
'; return $html; } private function buildTitleTab(array $data, string $componentId): string { $html = '
'; $titleSource = $data['title']['title_source'] ?? 'post_title'; $html .= $this->buildSelect('title_source', 'Fuente del título', $titleSource, ['post_title' => 'Título del post', 'custom_field' => 'Campo personalizado', 'custom_text' => 'Texto personalizado'], $componentId, 'title'); $customField = $data['title']['custom_field_name'] ?? ''; $html .= $this->buildTextField('custom_field_name', 'Nombre del campo personalizado', $customField, $componentId, 'title', 'Ej: hero_title', ['data-conditional-field' => 'title_source', 'data-conditional-value' => 'custom_field']); $customText = $data['title']['custom_text'] ?? ''; $html .= $this->buildTextArea('custom_text', 'Texto personalizado', $customText, $componentId, 'title', '', 3, ['data-conditional-field' => 'title_source', 'data-conditional-value' => 'custom_text']); $titleTag = $data['title']['title_tag'] ?? 'h1'; $html .= $this->buildSelect('title_tag', 'Etiqueta HTML del título', $titleTag, ['h1' => 'H1', 'h2' => 'H2', 'h3' => 'H3', 'div' => 'DIV'], $componentId, 'title'); $titleClasses = $data['title']['title_classes'] ?? 'display-5 fw-bold'; $html .= $this->buildTextField('title_classes', 'Clases CSS adicionales', $titleClasses, $componentId, 'title', 'Ej: display-5 fw-bold'); $titleAlignment = $data['title']['title_alignment'] ?? 'center'; $html .= $this->buildSelect('title_alignment', 'Alineación del título', $titleAlignment, ['left' => 'Izquierda', 'center' => 'Centro', 'right' => 'Derecha'], $componentId, 'title'); $enableGradient = $data['title']['enable_gradient'] ?? false; $html .= $this->buildToggle('enable_gradient', 'Activar gradiente en el texto', $enableGradient, $componentId, 'title'); $gradientStart = $data['title']['gradient_color_start'] ?? '#1e3a5f'; $html .= $this->buildColorField('gradient_color_start', 'Color inicial del gradiente', $gradientStart, $componentId, 'title', ['data-conditional-field' => 'enable_gradient', 'data-conditional-value' => 'true']); $gradientEnd = $data['title']['gradient_color_end'] ?? '#FF8600'; $html .= $this->buildColorField('gradient_color_end', 'Color final del gradiente', $gradientEnd, $componentId, 'title', ['data-conditional-field' => 'enable_gradient', 'data-conditional-value' => 'true']); $gradientDirection = $data['title']['gradient_direction'] ?? 'to-right'; $html .= $this->buildSelect('gradient_direction', 'Dirección del gradiente', $gradientDirection, ['to-right' => 'Izquierda a derecha', 'to-left' => 'Derecha a izquierda', 'to-bottom' => 'Arriba a abajo', 'to-top' => 'Abajo a arriba', 'diagonal' => 'Diagonal'], $componentId, 'title', ['data-conditional-field' => 'enable_gradient', 'data-conditional-value' => 'true']); $html .= '
'; return $html; } private function buildStylesTab(array $data, string $componentId): string { $html = '
'; $backgroundType = $data['styles']['background_type'] ?? 'gradient'; $html .= $this->buildSelect('background_type', 'Tipo de fondo', $backgroundType, ['color' => 'Color sólido', 'gradient' => 'Gradiente', 'image' => 'Imagen', 'none' => 'Sin fondo'], $componentId, 'styles'); $bgColor = $data['styles']['background_color'] ?? '#1e3a5f'; $html .= $this->buildColorField('background_color', 'Color de fondo', $bgColor, $componentId, 'styles', ['data-conditional-field' => 'background_type', 'data-conditional-value' => 'color']); $gradientStart = $data['styles']['gradient_start_color'] ?? '#1e3a5f'; $html .= $this->buildColorField('gradient_start_color', 'Color inicial del gradiente', $gradientStart, $componentId, 'styles', ['data-conditional-field' => 'background_type', 'data-conditional-value' => 'gradient']); $gradientEnd = $data['styles']['gradient_end_color'] ?? '#2c5282'; $html .= $this->buildColorField('gradient_end_color', 'Color final del gradiente', $gradientEnd, $componentId, 'styles', ['data-conditional-field' => 'background_type', 'data-conditional-value' => 'gradient']); $gradientAngle = $data['styles']['gradient_angle'] ?? 135; $html .= $this->buildNumberField('gradient_angle', 'Ángulo del gradiente (grados)', $gradientAngle, $componentId, 'styles', 0, 360, ['data-conditional-field' => 'background_type', 'data-conditional-value' => 'gradient']); $bgImage = $data['styles']['background_image_url'] ?? ''; $html .= $this->buildMediaField('background_image_url', 'Imagen de fondo', $bgImage, $componentId, 'styles', ['data-conditional-field' => 'background_type', 'data-conditional-value' => 'image']); $bgOverlay = $data['styles']['background_overlay'] ?? true; $html .= $this->buildToggle('background_overlay', 'Overlay oscuro sobre imagen', $bgOverlay, $componentId, 'styles', ['data-conditional-field' => 'background_type', 'data-conditional-value' => 'image']); $overlayOpacity = $data['styles']['overlay_opacity'] ?? 60; $html .= $this->buildNumberField('overlay_opacity', 'Opacidad del overlay (%)', $overlayOpacity, $componentId, 'styles', 0, 100, ['data-conditional-field' => 'background_overlay', 'data-conditional-value' => 'true']); $textColor = $data['styles']['text_color'] ?? '#FFFFFF'; $html .= $this->buildColorField('text_color', 'Color del texto', $textColor, $componentId, 'styles'); $padding = $data['styles']['padding_vertical'] ?? 'normal'; $html .= $this->buildSelect('padding_vertical', 'Padding vertical', $padding, ['compact' => 'Compacto (2rem)', 'normal' => 'Normal (3rem)', 'spacious' => 'Espacioso (4rem)', 'extra-spacious' => 'Extra espacioso (5rem)'], $componentId, 'styles'); $margin = $data['styles']['margin_bottom'] ?? 'normal'; $html .= $this->buildSelect('margin_bottom', 'Margen inferior', $margin, ['none' => 'Sin margen', 'small' => 'Pequeño (1rem)', 'normal' => 'Normal (1.5rem)', 'large' => 'Grande (2rem)'], $componentId, 'styles'); $badgeBg = $data['styles']['category_badge_background'] ?? 'rgba(255, 255, 255, 0.2)'; $html .= $this->buildTextField('category_badge_background', 'Fondo de badges', $badgeBg, $componentId, 'styles'); $badgeText = $data['styles']['category_badge_text_color'] ?? '#FFFFFF'; $html .= $this->buildColorField('category_badge_text_color', 'Color del texto de badges', $badgeText, $componentId, 'styles'); $badgeBlur = $data['styles']['category_badge_blur'] ?? true; $html .= $this->buildToggle('category_badge_blur', 'Efecto blur en badges', $badgeBlur, $componentId, 'styles'); $html .= '
'; return $html; } private function buildToggle(string $name, string $label, bool $value, string $componentId, string $group, array $attrs = []): string { $fieldId = "roi_{$componentId}_{$group}_{$name}"; $checked = $value ? 'checked' : ''; $attrString = $this->buildAttributesString($attrs); return sprintf('
', esc_attr($fieldId), esc_attr($componentId), esc_attr($group), esc_attr($name), $checked, $attrString, esc_attr($fieldId), esc_html($label)); } private function buildTextField(string $name, string $label, string $value, string $componentId, string $group, string $placeholder = '', array $attrs = []): string { $fieldId = "roi_{$componentId}_{$group}_{$name}"; $attrString = $this->buildAttributesString($attrs); return sprintf('
', esc_attr($fieldId), esc_html($label), esc_attr($fieldId), esc_attr($componentId), esc_attr($group), esc_attr($name), esc_attr($value), esc_attr($placeholder), $attrString); } private function buildTextArea(string $name, string $label, string $value, string $componentId, string $group, string $placeholder = '', int $rows = 3, array $attrs = []): string { $fieldId = "roi_{$componentId}_{$group}_{$name}"; $attrString = $this->buildAttributesString($attrs); return sprintf('
', esc_attr($fieldId), esc_html($label), esc_attr($fieldId), esc_attr($componentId), esc_attr($group), esc_attr($name), $rows, esc_attr($placeholder), $attrString, esc_textarea($value)); } private function buildSelect(string $name, string $label, string $value, array $options, string $componentId, string $group, array $attrs = []): string { $fieldId = "roi_{$componentId}_{$group}_{$name}"; $attrString = $this->buildAttributesString($attrs); $html = sprintf('
', esc_attr($fieldId), esc_html($label)); $html .= sprintf('
'; return $html; } private function buildNumberField(string $name, string $label, $value, string $componentId, string $group, int $min = null, int $max = null, array $attrs = []): string { $fieldId = "roi_{$componentId}_{$group}_{$name}"; $attrs['type'] = 'number'; if ($min !== null) $attrs['min'] = $min; if ($max !== null) $attrs['max'] = $max; $attrString = $this->buildAttributesString($attrs); return sprintf('
', esc_attr($fieldId), esc_html($label), esc_attr($fieldId), esc_attr($componentId), esc_attr($group), esc_attr($name), esc_attr($value), $attrString); } private function buildColorField(string $name, string $label, string $value, string $componentId, string $group, array $attrs = []): string { $fieldId = "roi_{$componentId}_{$group}_{$name}"; return sprintf('
', esc_attr($fieldId), esc_html($label), esc_attr($fieldId), esc_attr($componentId), esc_attr($group), esc_attr($name), esc_attr($value), esc_attr($value)); } private function buildMediaField(string $name, string $label, string $value, string $componentId, string $group, array $attrs = []): string { $fieldId = "roi_{$componentId}_{$group}_{$name}"; $attrString = $this->buildAttributesString($attrs); $html = sprintf('
', esc_attr($fieldId), esc_html($label)); $html .= '
'; $html .= sprintf('', esc_attr($fieldId), esc_attr($componentId), esc_attr($group), esc_attr($name), esc_attr($value), $attrString); $html .= sprintf('', esc_attr($fieldId)); $html .= '
'; if (!empty($value)) { $html .= sprintf('
Preview
', esc_url($value)); } $html .= '
'; return $html; } private function buildAttributesString(array $attrs): string { $attrString = ''; foreach ($attrs as $key => $value) { $attrString .= sprintf(' %s="%s"', esc_attr($key), esc_attr($value)); } return $attrString; } private function buildFormScripts(string $componentId): string { return << SCRIPT; } public function getComponentId(): string { return $this->componentId; } }