- Create PostGridShortcodeRegistrar for WordPress shortcode registration - Implement RenderPostGridUseCase following Clean Architecture - Add PostGridQueryBuilder for custom WP_Query construction - Add PostGridShortcodeRenderer for HTML/CSS generation - Register shortcode in DIContainer with proper DI - Add shortcode usage guide in post-grid admin panel - Fix sidebar layout: add hide_for_logged_in check to wrapper visibility Shortcode attributes: category, tag, author, posts_per_page, columns, show_pagination, show_thumbnail, show_excerpt, show_meta, etc. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
729 lines
40 KiB
PHP
729 lines
40 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Admin\PostGrid\Infrastructure\Ui;
|
|
|
|
use ROITheme\Admin\Infrastructure\Ui\AdminDashboardRenderer;
|
|
use ROITheme\Admin\Shared\Infrastructure\Ui\ExclusionFormPartial;
|
|
|
|
/**
|
|
* PostGridFormBuilder - Genera formulario admin para Post Grid
|
|
*
|
|
* Sigue el mismo patron visual que RelatedPostFormBuilder:
|
|
* - Header con gradiente navy
|
|
* - Layout de 2 columnas
|
|
* - Cards con borde izquierdo
|
|
* - Inputs compactos (form-control-sm)
|
|
*
|
|
* @package ROITheme\Admin\PostGrid\Infrastructure\Ui
|
|
*/
|
|
final class PostGridFormBuilder
|
|
{
|
|
public function __construct(
|
|
private AdminDashboardRenderer $renderer
|
|
) {}
|
|
|
|
public function buildForm(string $componentId): string
|
|
{
|
|
$html = '';
|
|
|
|
$html .= $this->buildHeader();
|
|
|
|
$html .= '<div class="row g-3">';
|
|
|
|
// Columna izquierda
|
|
$html .= '<div class="col-lg-6">';
|
|
$html .= $this->buildShortcodeGuide();
|
|
$html .= $this->buildVisibilityGroup($componentId);
|
|
$html .= $this->buildContentGroup($componentId);
|
|
$html .= $this->buildMediaGroup($componentId);
|
|
$html .= '</div>';
|
|
|
|
// Columna derecha
|
|
$html .= '<div class="col-lg-6">';
|
|
$html .= $this->buildLayoutGroup($componentId);
|
|
$html .= $this->buildTypographyGroup($componentId);
|
|
$html .= $this->buildColorsGroup($componentId);
|
|
$html .= $this->buildSpacingGroup($componentId);
|
|
$html .= $this->buildEffectsGroup($componentId);
|
|
$html .= '</div>';
|
|
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildHeader(): string
|
|
{
|
|
$html = '<div class="rounded p-4 mb-4 shadow text-white" ';
|
|
$html .= '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-grid-3x3-gap me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Configuracion de Post Grid';
|
|
$html .= ' </h3>';
|
|
$html .= ' <p class="mb-0 small" style="opacity: 0.85;">';
|
|
$html .= ' Grid de posts para listados, archivos y resultados de busqueda';
|
|
$html .= ' </p>';
|
|
$html .= ' </div>';
|
|
$html .= ' <button type="button" class="btn btn-sm btn-outline-light btn-reset-defaults" data-component="post-grid">';
|
|
$html .= ' <i class="bi bi-arrow-counterclockwise me-1"></i>';
|
|
$html .= ' Restaurar valores por defecto';
|
|
$html .= ' </button>';
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildVisibilityGroup(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-toggle-on me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Visibilidad';
|
|
$html .= ' </h5>';
|
|
|
|
$enabled = $this->renderer->getFieldValue($componentId, 'visibility', 'is_enabled', true);
|
|
$html .= $this->buildSwitch('postGridEnabled', 'Activar componente', 'bi-power', $enabled);
|
|
|
|
$showOnDesktop = $this->renderer->getFieldValue($componentId, 'visibility', 'show_on_desktop', true);
|
|
$html .= $this->buildSwitch('postGridShowOnDesktop', 'Mostrar en escritorio', 'bi-display', $showOnDesktop);
|
|
|
|
$showOnMobile = $this->renderer->getFieldValue($componentId, 'visibility', 'show_on_mobile', true);
|
|
$html .= $this->buildSwitch('postGridShowOnMobile', 'Mostrar en movil', 'bi-phone', $showOnMobile);
|
|
|
|
// Checkboxes de visibilidad por tipo de página
|
|
$html .= ' <hr class="my-3">';
|
|
$html .= ' <p class="small fw-semibold mb-2">';
|
|
$html .= ' <i class="bi bi-eye me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Mostrar en tipos de pagina';
|
|
$html .= ' </p>';
|
|
|
|
$showOnHome = $this->renderer->getFieldValue($componentId, '_page_visibility', 'show_on_home', true);
|
|
$showOnPosts = $this->renderer->getFieldValue($componentId, '_page_visibility', 'show_on_posts', false);
|
|
$showOnPages = $this->renderer->getFieldValue($componentId, '_page_visibility', 'show_on_pages', false);
|
|
$showOnArchives = $this->renderer->getFieldValue($componentId, '_page_visibility', 'show_on_archives', true);
|
|
$showOnSearch = $this->renderer->getFieldValue($componentId, '_page_visibility', 'show_on_search', true);
|
|
|
|
$html .= ' <div class="row g-2">';
|
|
$html .= ' <div class="col-md-4">';
|
|
$html .= $this->buildPageVisibilityCheckbox('postGridVisibilityHome', 'Home', 'bi-house', $showOnHome);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-4">';
|
|
$html .= $this->buildPageVisibilityCheckbox('postGridVisibilityPosts', 'Posts', 'bi-file-earmark-text', $showOnPosts);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-4">';
|
|
$html .= $this->buildPageVisibilityCheckbox('postGridVisibilityPages', 'Paginas', 'bi-file-earmark', $showOnPages);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-4">';
|
|
$html .= $this->buildPageVisibilityCheckbox('postGridVisibilityArchives', 'Archivos', 'bi-archive', $showOnArchives);
|
|
$html .= ' </div>';
|
|
$html .= ' <div class="col-md-4">';
|
|
$html .= $this->buildPageVisibilityCheckbox('postGridVisibilitySearch', 'Busqueda', 'bi-search', $showOnSearch);
|
|
$html .= ' </div>';
|
|
$html .= ' </div>';
|
|
|
|
// Reglas de exclusion
|
|
$exclusionPartial = new ExclusionFormPartial($this->renderer);
|
|
$html .= $exclusionPartial->render($componentId, 'postGrid');
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildContentGroup(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-card-text me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Contenido';
|
|
$html .= ' </h5>';
|
|
|
|
// Switches de contenido
|
|
$showThumbnail = $this->renderer->getFieldValue($componentId, 'content', 'show_thumbnail', true);
|
|
$html .= $this->buildSwitch('postGridShowThumbnail', 'Mostrar imagen destacada', 'bi-image', $showThumbnail);
|
|
|
|
$showExcerpt = $this->renderer->getFieldValue($componentId, 'content', 'show_excerpt', true);
|
|
$html .= $this->buildSwitch('postGridShowExcerpt', 'Mostrar extracto', 'bi-text-paragraph', $showExcerpt);
|
|
|
|
$showMeta = $this->renderer->getFieldValue($componentId, 'content', 'show_meta', true);
|
|
$html .= $this->buildSwitch('postGridShowMeta', 'Mostrar metadatos', 'bi-info-circle', $showMeta);
|
|
|
|
$showCategories = $this->renderer->getFieldValue($componentId, 'content', 'show_categories', true);
|
|
$html .= $this->buildSwitch('postGridShowCategories', 'Mostrar categorias', 'bi-folder', $showCategories);
|
|
|
|
$html .= ' <hr class="my-3">';
|
|
|
|
// Excerpt length
|
|
$excerptLength = $this->renderer->getFieldValue($componentId, 'content', 'excerpt_length', '20');
|
|
$html .= ' <div class="mb-3">';
|
|
$html .= ' <label for="postGridExcerptLength" class="form-label small mb-1 fw-semibold">Longitud del extracto</label>';
|
|
$html .= ' <select id="postGridExcerptLength" class="form-select form-select-sm">';
|
|
$html .= ' <option value="10"' . ($excerptLength === '10' ? ' selected' : '') . '>10 palabras</option>';
|
|
$html .= ' <option value="15"' . ($excerptLength === '15' ? ' selected' : '') . '>15 palabras</option>';
|
|
$html .= ' <option value="20"' . ($excerptLength === '20' ? ' selected' : '') . '>20 palabras</option>';
|
|
$html .= ' <option value="25"' . ($excerptLength === '25' ? ' selected' : '') . '>25 palabras</option>';
|
|
$html .= ' <option value="30"' . ($excerptLength === '30' ? ' selected' : '') . '>30 palabras</option>';
|
|
$html .= ' </select>';
|
|
$html .= ' </div>';
|
|
|
|
// Read more text
|
|
$readMoreText = $this->renderer->getFieldValue($componentId, 'content', 'read_more_text', 'Leer mas');
|
|
$html .= ' <div class="mb-3">';
|
|
$html .= ' <label for="postGridReadMoreText" class="form-label small mb-1 fw-semibold">Texto de leer mas</label>';
|
|
$html .= ' <input type="text" id="postGridReadMoreText" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($readMoreText) . '">';
|
|
$html .= ' </div>';
|
|
|
|
// No posts message
|
|
$noPostsMessage = $this->renderer->getFieldValue($componentId, 'content', 'no_posts_message', 'No se encontraron publicaciones');
|
|
$html .= ' <div class="mb-0">';
|
|
$html .= ' <label for="postGridNoPostsMessage" class="form-label small mb-1 fw-semibold">Mensaje sin posts</label>';
|
|
$html .= ' <input type="text" id="postGridNoPostsMessage" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($noPostsMessage) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildLayoutGroup(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-grid me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Disposicion';
|
|
$html .= ' </h5>';
|
|
|
|
// Columns desktop
|
|
$colsDesktop = $this->renderer->getFieldValue($componentId, 'layout', 'columns_desktop', '3');
|
|
$html .= ' <div class="mb-3">';
|
|
$html .= ' <label for="postGridColsDesktop" class="form-label small mb-1 fw-semibold">';
|
|
$html .= ' <i class="bi bi-display me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Columnas escritorio';
|
|
$html .= ' </label>';
|
|
$html .= ' <select id="postGridColsDesktop" class="form-select form-select-sm">';
|
|
$html .= ' <option value="2"' . ($colsDesktop === '2' ? ' selected' : '') . '>2 columnas</option>';
|
|
$html .= ' <option value="3"' . ($colsDesktop === '3' ? ' selected' : '') . '>3 columnas</option>';
|
|
$html .= ' <option value="4"' . ($colsDesktop === '4' ? ' selected' : '') . '>4 columnas</option>';
|
|
$html .= ' </select>';
|
|
$html .= ' </div>';
|
|
|
|
// Columns tablet
|
|
$colsTablet = $this->renderer->getFieldValue($componentId, 'layout', 'columns_tablet', '2');
|
|
$html .= ' <div class="mb-3">';
|
|
$html .= ' <label for="postGridColsTablet" class="form-label small mb-1 fw-semibold">';
|
|
$html .= ' <i class="bi bi-tablet me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Columnas tablet';
|
|
$html .= ' </label>';
|
|
$html .= ' <select id="postGridColsTablet" class="form-select form-select-sm">';
|
|
$html .= ' <option value="1"' . ($colsTablet === '1' ? ' selected' : '') . '>1 columna</option>';
|
|
$html .= ' <option value="2"' . ($colsTablet === '2' ? ' selected' : '') . '>2 columnas</option>';
|
|
$html .= ' <option value="3"' . ($colsTablet === '3' ? ' selected' : '') . '>3 columnas</option>';
|
|
$html .= ' </select>';
|
|
$html .= ' </div>';
|
|
|
|
// Columns mobile
|
|
$colsMobile = $this->renderer->getFieldValue($componentId, 'layout', 'columns_mobile', '1');
|
|
$html .= ' <div class="mb-3">';
|
|
$html .= ' <label for="postGridColsMobile" class="form-label small mb-1 fw-semibold">';
|
|
$html .= ' <i class="bi bi-phone me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Columnas movil';
|
|
$html .= ' </label>';
|
|
$html .= ' <select id="postGridColsMobile" class="form-select form-select-sm">';
|
|
$html .= ' <option value="1"' . ($colsMobile === '1' ? ' selected' : '') . '>1 columna</option>';
|
|
$html .= ' <option value="2"' . ($colsMobile === '2' ? ' selected' : '') . '>2 columnas</option>';
|
|
$html .= ' </select>';
|
|
$html .= ' </div>';
|
|
|
|
// Image position
|
|
$imagePosition = $this->renderer->getFieldValue($componentId, 'layout', 'image_position', 'top');
|
|
$html .= ' <div class="mb-0">';
|
|
$html .= ' <label for="postGridImagePosition" class="form-label small mb-1 fw-semibold">';
|
|
$html .= ' <i class="bi bi-aspect-ratio me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Posicion de imagen';
|
|
$html .= ' </label>';
|
|
$html .= ' <select id="postGridImagePosition" class="form-select form-select-sm">';
|
|
$html .= ' <option value="top"' . ($imagePosition === 'top' ? ' selected' : '') . '>Arriba</option>';
|
|
$html .= ' <option value="left"' . ($imagePosition === 'left' ? ' selected' : '') . '>Izquierda</option>';
|
|
$html .= ' <option value="none"' . ($imagePosition === 'none' ? ' selected' : '') . '>Sin imagen</option>';
|
|
$html .= ' </select>';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildMediaGroup(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-image me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Medios';
|
|
$html .= ' </h5>';
|
|
|
|
// Fallback image
|
|
$fallbackImage = $this->renderer->getFieldValue($componentId, 'media', 'fallback_image', '');
|
|
$html .= ' <div class="mb-3">';
|
|
$html .= ' <label for="postGridFallbackImage" class="form-label small mb-1 fw-semibold">URL imagen por defecto</label>';
|
|
$html .= ' <input type="url" id="postGridFallbackImage" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_url($fallbackImage) . '" placeholder="https://...">';
|
|
$html .= ' </div>';
|
|
|
|
// Fallback image alt
|
|
$fallbackImageAlt = $this->renderer->getFieldValue($componentId, 'media', 'fallback_image_alt', 'Imagen por defecto');
|
|
$html .= ' <div class="mb-0">';
|
|
$html .= ' <label for="postGridFallbackImageAlt" class="form-label small mb-1 fw-semibold">Texto alternativo</label>';
|
|
$html .= ' <input type="text" id="postGridFallbackImageAlt" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($fallbackImageAlt) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildTypographyGroup(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-fonts me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Tipografia';
|
|
$html .= ' </h5>';
|
|
|
|
// Heading level
|
|
$headingLevel = $this->renderer->getFieldValue($componentId, 'typography', 'heading_level', 'h3');
|
|
$html .= ' <div class="mb-3">';
|
|
$html .= ' <label for="postGridHeadingLevel" class="form-label small mb-1 fw-semibold">Nivel de encabezado</label>';
|
|
$html .= ' <select id="postGridHeadingLevel" class="form-select form-select-sm">';
|
|
$html .= ' <option value="h2"' . ($headingLevel === 'h2' ? ' selected' : '') . '>H2</option>';
|
|
$html .= ' <option value="h3"' . ($headingLevel === 'h3' ? ' selected' : '') . '>H3</option>';
|
|
$html .= ' <option value="h4"' . ($headingLevel === 'h4' ? ' selected' : '') . '>H4</option>';
|
|
$html .= ' <option value="h5"' . ($headingLevel === 'h5' ? ' selected' : '') . '>H5</option>';
|
|
$html .= ' <option value="h6"' . ($headingLevel === 'h6' ? ' selected' : '') . '>H6</option>';
|
|
$html .= ' </select>';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$cardTitleSize = $this->renderer->getFieldValue($componentId, 'typography', 'card_title_size', '1.1rem');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridCardTitleSize" class="form-label small mb-1 fw-semibold">Tamano titulo</label>';
|
|
$html .= ' <input type="text" id="postGridCardTitleSize" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($cardTitleSize) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$cardTitleWeight = $this->renderer->getFieldValue($componentId, 'typography', 'card_title_weight', '600');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridCardTitleWeight" class="form-label small mb-1 fw-semibold">Peso titulo</label>';
|
|
$html .= ' <input type="text" id="postGridCardTitleWeight" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($cardTitleWeight) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="row g-2 mb-0">';
|
|
|
|
$excerptSize = $this->renderer->getFieldValue($componentId, 'typography', 'excerpt_size', '0.9rem');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridExcerptSize" class="form-label small mb-1 fw-semibold">Tamano extracto</label>';
|
|
$html .= ' <input type="text" id="postGridExcerptSize" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($excerptSize) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$metaSize = $this->renderer->getFieldValue($componentId, 'typography', 'meta_size', '0.8rem');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridMetaSize" class="form-label small mb-1 fw-semibold">Tamano metadatos</label>';
|
|
$html .= ' <input type="text" id="postGridMetaSize" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($metaSize) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildColorsGroup(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-palette me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Colores';
|
|
$html .= ' </h5>';
|
|
|
|
// Cards
|
|
$html .= ' <p class="small fw-semibold mb-2">Cards</p>';
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$cardBgColor = $this->renderer->getFieldValue($componentId, 'colors', 'card_bg_color', '#ffffff');
|
|
$html .= $this->buildColorPicker('postGridCardBgColor', 'Fondo', $cardBgColor);
|
|
|
|
$cardTitleColor = $this->renderer->getFieldValue($componentId, 'colors', 'card_title_color', '#0E2337');
|
|
$html .= $this->buildColorPicker('postGridCardTitleColor', 'Titulo', $cardTitleColor);
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$cardHoverBgColor = $this->renderer->getFieldValue($componentId, 'colors', 'card_hover_bg_color', '#f9fafb');
|
|
$html .= $this->buildColorPicker('postGridCardHoverBgColor', 'Fondo hover', $cardHoverBgColor);
|
|
|
|
$cardBorderColor = $this->renderer->getFieldValue($componentId, 'colors', 'card_border_color', '#e5e7eb');
|
|
$html .= $this->buildColorPicker('postGridCardBorderColor', 'Borde', $cardBorderColor);
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$cardHoverBorderColor = $this->renderer->getFieldValue($componentId, 'colors', 'card_hover_border_color', '#FF8600');
|
|
$html .= $this->buildColorPicker('postGridCardHoverBorderColor', 'Borde hover', $cardHoverBorderColor);
|
|
|
|
$excerptColor = $this->renderer->getFieldValue($componentId, 'colors', 'excerpt_color', '#6b7280');
|
|
$html .= $this->buildColorPicker('postGridExcerptColor', 'Extracto', $excerptColor);
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$metaColor = $this->renderer->getFieldValue($componentId, 'colors', 'meta_color', '#9ca3af');
|
|
$html .= $this->buildColorPicker('postGridMetaColor', 'Metadatos', $metaColor);
|
|
|
|
$categoryBgColor = $this->renderer->getFieldValue($componentId, 'colors', 'category_bg_color', '#FFF5EB');
|
|
$html .= $this->buildColorPicker('postGridCategoryBgColor', 'Fondo cat.', $categoryBgColor);
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$categoryTextColor = $this->renderer->getFieldValue($componentId, 'colors', 'category_text_color', '#FF8600');
|
|
$html .= $this->buildColorPicker('postGridCategoryTextColor', 'Texto cat.', $categoryTextColor);
|
|
|
|
$html .= ' </div>';
|
|
|
|
// Paginacion
|
|
$html .= ' <p class="small fw-semibold mb-2">Paginacion</p>';
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$paginationColor = $this->renderer->getFieldValue($componentId, 'colors', 'pagination_color', '#0E2337');
|
|
$html .= $this->buildColorPicker('postGridPaginationColor', 'Color', $paginationColor);
|
|
|
|
$paginationActiveBg = $this->renderer->getFieldValue($componentId, 'colors', 'pagination_active_bg', '#FF8600');
|
|
$html .= $this->buildColorPicker('postGridPaginationActiveBg', 'Activo fondo', $paginationActiveBg);
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="row g-2 mb-0">';
|
|
|
|
$paginationActiveColor = $this->renderer->getFieldValue($componentId, 'colors', 'pagination_active_color', '#ffffff');
|
|
$html .= $this->buildColorPicker('postGridPaginationActiveColor', 'Activo texto', $paginationActiveColor);
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildSpacingGroup(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-arrows-move me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Espaciado';
|
|
$html .= ' </h5>';
|
|
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$gridGap = $this->renderer->getFieldValue($componentId, 'spacing', 'grid_gap', '1.5rem');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridGridGap" class="form-label small mb-1 fw-semibold">Espacio entre cards</label>';
|
|
$html .= ' <input type="text" id="postGridGridGap" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($gridGap) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$cardPadding = $this->renderer->getFieldValue($componentId, 'spacing', 'card_padding', '1.25rem');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridCardPadding" class="form-label small mb-1 fw-semibold">Padding card</label>';
|
|
$html .= ' <input type="text" id="postGridCardPadding" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($cardPadding) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="row g-2 mb-0">';
|
|
|
|
$sectionMarginTop = $this->renderer->getFieldValue($componentId, 'spacing', 'section_margin_top', '0');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridSectionMarginTop" class="form-label small mb-1 fw-semibold">Margen superior</label>';
|
|
$html .= ' <input type="text" id="postGridSectionMarginTop" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($sectionMarginTop) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$sectionMarginBottom = $this->renderer->getFieldValue($componentId, 'spacing', 'section_margin_bottom', '2rem');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridSectionMarginBottom" class="form-label small mb-1 fw-semibold">Margen inferior</label>';
|
|
$html .= ' <input type="text" id="postGridSectionMarginBottom" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($sectionMarginBottom) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildEffectsGroup(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-magic me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Efectos Visuales';
|
|
$html .= ' </h5>';
|
|
|
|
$html .= ' <div class="row g-2 mb-3">';
|
|
|
|
$cardBorderRadius = $this->renderer->getFieldValue($componentId, 'visual_effects', 'card_border_radius', '0.5rem');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridCardBorderRadius" class="form-label small mb-1 fw-semibold">Radio borde</label>';
|
|
$html .= ' <input type="text" id="postGridCardBorderRadius" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($cardBorderRadius) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$imageBorderRadius = $this->renderer->getFieldValue($componentId, 'visual_effects', 'image_border_radius', '0.375rem');
|
|
$html .= ' <div class="col-6">';
|
|
$html .= ' <label for="postGridImageBorderRadius" class="form-label small mb-1 fw-semibold">Radio imagen</label>';
|
|
$html .= ' <input type="text" id="postGridImageBorderRadius" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($imageBorderRadius) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="mb-3">';
|
|
$cardTransition = $this->renderer->getFieldValue($componentId, 'visual_effects', 'card_transition', 'all 0.3s ease');
|
|
$html .= ' <label for="postGridCardTransition" class="form-label small mb-1 fw-semibold">Transicion</label>';
|
|
$html .= ' <input type="text" id="postGridCardTransition" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($cardTransition) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="mb-3">';
|
|
$cardShadow = $this->renderer->getFieldValue($componentId, 'visual_effects', 'card_shadow', '0 1px 3px rgba(0,0,0,0.1)');
|
|
$html .= ' <label for="postGridCardShadow" class="form-label small mb-1 fw-semibold">Sombra normal</label>';
|
|
$html .= ' <input type="text" id="postGridCardShadow" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($cardShadow) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' <div class="mb-0">';
|
|
$cardHoverShadow = $this->renderer->getFieldValue($componentId, 'visual_effects', 'card_hover_shadow', '0 4px 12px rgba(0,0,0,0.15)');
|
|
$html .= ' <label for="postGridCardHoverShadow" class="form-label small mb-1 fw-semibold">Sombra hover</label>';
|
|
$html .= ' <input type="text" id="postGridCardHoverShadow" class="form-control form-control-sm" ';
|
|
$html .= ' value="' . esc_attr($cardHoverShadow) . '">';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildSwitch(string $id, string $label, string $icon, mixed $checked): string
|
|
{
|
|
$checked = $checked === true || $checked === '1' || $checked === 1;
|
|
|
|
$html = ' <div class="mb-2">';
|
|
$html .= ' <div class="form-check form-switch">';
|
|
$html .= sprintf(
|
|
' <input class="form-check-input" type="checkbox" id="%s" %s>',
|
|
esc_attr($id),
|
|
$checked ? 'checked' : ''
|
|
);
|
|
$html .= sprintf(
|
|
' <label class="form-check-label small" for="%s">',
|
|
esc_attr($id)
|
|
);
|
|
$html .= sprintf(' <i class="bi %s me-1" style="color: #FF8600;"></i>', esc_attr($icon));
|
|
$html .= sprintf(' <strong>%s</strong>', esc_html($label));
|
|
$html .= ' </label>';
|
|
$html .= ' </div>';
|
|
$html .= ' </div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildColorPicker(string $id, string $label, string $value): string
|
|
{
|
|
$html = ' <div class="col-6">';
|
|
$html .= sprintf(
|
|
' <label class="form-label small fw-semibold">%s</label>',
|
|
esc_html($label)
|
|
);
|
|
$html .= ' <div class="input-group input-group-sm">';
|
|
$html .= sprintf(
|
|
' <input type="color" class="form-control form-control-color" id="%s" value="%s">',
|
|
esc_attr($id),
|
|
esc_attr($value)
|
|
);
|
|
$html .= sprintf(
|
|
' <span class="input-group-text" id="%sValue">%s</span>',
|
|
esc_attr($id),
|
|
esc_html(strtoupper($value))
|
|
);
|
|
$html .= ' </div>';
|
|
$html .= ' </div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildPageVisibilityCheckbox(string $id, string $label, string $icon, mixed $checked): string
|
|
{
|
|
$checked = $checked === true || $checked === '1' || $checked === 1;
|
|
|
|
$html = ' <div class="form-check form-check-checkbox mb-2">';
|
|
$html .= sprintf(
|
|
' <input class="form-check-input" type="checkbox" id="%s" %s>',
|
|
esc_attr($id),
|
|
$checked ? 'checked' : ''
|
|
);
|
|
$html .= sprintf(
|
|
' <label class="form-check-label small" for="%s">',
|
|
esc_attr($id)
|
|
);
|
|
$html .= sprintf(' <i class="bi %s me-1" style="color: #FF8600;"></i>', esc_attr($icon));
|
|
$html .= sprintf(' %s', esc_html($label));
|
|
$html .= ' </label>';
|
|
$html .= ' </div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
private function buildShortcodeGuide(): string
|
|
{
|
|
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #FF8600;">';
|
|
$html .= ' <div class="card-body">';
|
|
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
|
$html .= ' <i class="bi bi-code-square me-2" style="color: #FF8600;"></i>';
|
|
$html .= ' Shortcode [roi_post_grid]';
|
|
$html .= ' </h5>';
|
|
|
|
$html .= ' <p class="small text-muted mb-3">';
|
|
$html .= ' Usa este shortcode para insertar grids de posts en cualquier pagina o entrada. ';
|
|
$html .= ' Los estilos se heredan de la configuracion de este componente.';
|
|
$html .= ' </p>';
|
|
|
|
// Uso basico
|
|
$html .= ' <p class="small fw-semibold mb-1">';
|
|
$html .= ' <i class="bi bi-1-circle me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Uso basico (9 posts, 3 columnas)';
|
|
$html .= ' </p>';
|
|
$html .= ' <div class="bg-dark text-light rounded p-2 mb-3" style="font-family: monospace; font-size: 0.8rem;">';
|
|
$html .= ' <code class="text-warning">[roi_post_grid]</code>';
|
|
$html .= ' </div>';
|
|
|
|
// Por categoria
|
|
$html .= ' <p class="small fw-semibold mb-1">';
|
|
$html .= ' <i class="bi bi-2-circle me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Filtrar por categoria';
|
|
$html .= ' </p>';
|
|
$html .= ' <div class="bg-dark text-light rounded p-2 mb-3" style="font-family: monospace; font-size: 0.8rem;">';
|
|
$html .= ' <code class="text-warning">[roi_post_grid category="precios-unitarios"]</code>';
|
|
$html .= ' </div>';
|
|
|
|
// Personalizar cantidad y columnas
|
|
$html .= ' <p class="small fw-semibold mb-1">';
|
|
$html .= ' <i class="bi bi-3-circle me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' 6 posts en 2 columnas';
|
|
$html .= ' </p>';
|
|
$html .= ' <div class="bg-dark text-light rounded p-2 mb-3" style="font-family: monospace; font-size: 0.8rem;">';
|
|
$html .= ' <code class="text-warning">[roi_post_grid posts_per_page="6" columns="2"]</code>';
|
|
$html .= ' </div>';
|
|
|
|
// Con paginacion
|
|
$html .= ' <p class="small fw-semibold mb-1">';
|
|
$html .= ' <i class="bi bi-4-circle me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Con paginacion';
|
|
$html .= ' </p>';
|
|
$html .= ' <div class="bg-dark text-light rounded p-2 mb-3" style="font-family: monospace; font-size: 0.8rem;">';
|
|
$html .= ' <code class="text-warning">[roi_post_grid posts_per_page="12" show_pagination="true"]</code>';
|
|
$html .= ' </div>';
|
|
|
|
// Filtrar por tag
|
|
$html .= ' <p class="small fw-semibold mb-1">';
|
|
$html .= ' <i class="bi bi-5-circle me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Filtrar por etiqueta';
|
|
$html .= ' </p>';
|
|
$html .= ' <div class="bg-dark text-light rounded p-2 mb-3" style="font-family: monospace; font-size: 0.8rem;">';
|
|
$html .= ' <code class="text-warning">[roi_post_grid tag="tutorial"]</code>';
|
|
$html .= ' </div>';
|
|
|
|
// Ejemplo completo
|
|
$html .= ' <p class="small fw-semibold mb-1">';
|
|
$html .= ' <i class="bi bi-6-circle me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Ejemplo completo';
|
|
$html .= ' </p>';
|
|
$html .= ' <div class="bg-dark text-light rounded p-2 mb-3" style="font-family: monospace; font-size: 0.75rem;">';
|
|
$html .= ' <code class="text-warning">[roi_post_grid category="cursos" posts_per_page="6" columns="3" show_meta="false" show_categories="true"]</code>';
|
|
$html .= ' </div>';
|
|
|
|
// Tabla de atributos
|
|
$html .= ' <hr class="my-3">';
|
|
$html .= ' <p class="small fw-semibold mb-2">';
|
|
$html .= ' <i class="bi bi-list-check me-1" style="color: #FF8600;"></i>';
|
|
$html .= ' Atributos disponibles';
|
|
$html .= ' </p>';
|
|
$html .= ' <div class="table-responsive">';
|
|
$html .= ' <table class="table table-sm table-bordered small mb-0">';
|
|
$html .= ' <thead class="table-light">';
|
|
$html .= ' <tr><th>Atributo</th><th>Default</th><th>Descripcion</th></tr>';
|
|
$html .= ' </thead>';
|
|
$html .= ' <tbody>';
|
|
$html .= ' <tr><td><code>posts_per_page</code></td><td>9</td><td>Cantidad de posts</td></tr>';
|
|
$html .= ' <tr><td><code>columns</code></td><td>3</td><td>Columnas (1-4)</td></tr>';
|
|
$html .= ' <tr><td><code>category</code></td><td>-</td><td>Slug de categoria</td></tr>';
|
|
$html .= ' <tr><td><code>exclude_category</code></td><td>-</td><td>Excluir categoria</td></tr>';
|
|
$html .= ' <tr><td><code>tag</code></td><td>-</td><td>Slug de etiqueta</td></tr>';
|
|
$html .= ' <tr><td><code>author</code></td><td>-</td><td>ID o username</td></tr>';
|
|
$html .= ' <tr><td><code>orderby</code></td><td>date</td><td>date, title, rand</td></tr>';
|
|
$html .= ' <tr><td><code>order</code></td><td>DESC</td><td>DESC o ASC</td></tr>';
|
|
$html .= ' <tr><td><code>show_pagination</code></td><td>false</td><td>Mostrar paginacion</td></tr>';
|
|
$html .= ' <tr><td><code>show_thumbnail</code></td><td>true</td><td>Mostrar imagen</td></tr>';
|
|
$html .= ' <tr><td><code>show_excerpt</code></td><td>true</td><td>Mostrar extracto</td></tr>';
|
|
$html .= ' <tr><td><code>show_meta</code></td><td>true</td><td>Fecha y autor</td></tr>';
|
|
$html .= ' <tr><td><code>show_categories</code></td><td>true</td><td>Badges categoria</td></tr>';
|
|
$html .= ' <tr><td><code>excerpt_length</code></td><td>20</td><td>Palabras extracto</td></tr>';
|
|
$html .= ' <tr><td><code>exclude_posts</code></td><td>-</td><td>IDs separados por coma</td></tr>';
|
|
$html .= ' <tr><td><code>offset</code></td><td>0</td><td>Saltar N posts</td></tr>';
|
|
$html .= ' <tr><td><code>id</code></td><td>-</td><td>ID unico (multiples grids)</td></tr>';
|
|
$html .= ' <tr><td><code>class</code></td><td>-</td><td>Clase CSS adicional</td></tr>';
|
|
$html .= ' </tbody>';
|
|
$html .= ' </table>';
|
|
$html .= ' </div>';
|
|
|
|
$html .= ' </div>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
}
|