- 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>
144 lines
4.8 KiB
PHP
144 lines
4.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Shared\Application\UseCases\RenderPostGrid;
|
|
|
|
/**
|
|
* RenderPostGridRequest - DTO de entrada para renderizar post grid shortcode
|
|
*
|
|
* RESPONSABILIDAD: Encapsular todos los atributos del shortcode [roi_post_grid]
|
|
*
|
|
* USO:
|
|
* ```php
|
|
* $request = RenderPostGridRequest::fromArray([
|
|
* 'category' => 'precios-unitarios',
|
|
* 'posts_per_page' => 6,
|
|
* 'columns' => 3
|
|
* ]);
|
|
* ```
|
|
*
|
|
* @package ROITheme\Shared\Application\UseCases\RenderPostGrid
|
|
*/
|
|
final readonly class RenderPostGridRequest
|
|
{
|
|
public function __construct(
|
|
public string $category = '',
|
|
public string $excludeCategory = '',
|
|
public string $tag = '',
|
|
public string $author = '',
|
|
public int $postsPerPage = 9,
|
|
public int $columns = 3,
|
|
public string $orderby = 'date',
|
|
public string $order = 'DESC',
|
|
public bool $showPagination = false,
|
|
public int $offset = 0,
|
|
public string $excludePosts = '',
|
|
public bool $showThumbnail = true,
|
|
public bool $showExcerpt = true,
|
|
public bool $showMeta = true,
|
|
public bool $showCategories = true,
|
|
public int $excerptLength = 20,
|
|
public string $class = '',
|
|
public string $id = '',
|
|
public int $paged = 1
|
|
) {}
|
|
|
|
/**
|
|
* Factory method: Crear desde array de atributos del shortcode
|
|
*
|
|
* @param array<string, mixed> $atts Atributos sanitizados del shortcode
|
|
* @return self
|
|
*/
|
|
public static function fromArray(array $atts): self
|
|
{
|
|
return new self(
|
|
category: (string) ($atts['category'] ?? ''),
|
|
excludeCategory: (string) ($atts['exclude_category'] ?? ''),
|
|
tag: (string) ($atts['tag'] ?? ''),
|
|
author: (string) ($atts['author'] ?? ''),
|
|
postsPerPage: self::clampInt((int) ($atts['posts_per_page'] ?? 9), 1, 50),
|
|
columns: self::clampInt((int) ($atts['columns'] ?? 3), 1, 4),
|
|
orderby: self::sanitizeOrderby((string) ($atts['orderby'] ?? 'date')),
|
|
order: self::sanitizeOrder((string) ($atts['order'] ?? 'DESC')),
|
|
showPagination: self::toBool($atts['show_pagination'] ?? false),
|
|
offset: max(0, (int) ($atts['offset'] ?? 0)),
|
|
excludePosts: (string) ($atts['exclude_posts'] ?? ''),
|
|
showThumbnail: self::toBool($atts['show_thumbnail'] ?? true),
|
|
showExcerpt: self::toBool($atts['show_excerpt'] ?? true),
|
|
showMeta: self::toBool($atts['show_meta'] ?? true),
|
|
showCategories: self::toBool($atts['show_categories'] ?? true),
|
|
excerptLength: max(1, (int) ($atts['excerpt_length'] ?? 20)),
|
|
class: (string) ($atts['class'] ?? ''),
|
|
id: (string) ($atts['id'] ?? ''),
|
|
paged: max(1, (int) ($atts['paged'] ?? 1))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Convertir a array de parametros para QueryBuilder
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function toQueryParams(): array
|
|
{
|
|
return [
|
|
'category' => $this->category,
|
|
'exclude_category' => $this->excludeCategory,
|
|
'tag' => $this->tag,
|
|
'author' => $this->author,
|
|
'posts_per_page' => $this->postsPerPage,
|
|
'orderby' => $this->orderby,
|
|
'order' => $this->order,
|
|
'offset' => $this->offset,
|
|
'exclude_posts' => $this->excludePosts,
|
|
'paged' => $this->paged,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Convertir a array de opciones para Renderer
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function toRenderOptions(): array
|
|
{
|
|
return [
|
|
'columns' => $this->columns,
|
|
'show_thumbnail' => $this->showThumbnail,
|
|
'show_excerpt' => $this->showExcerpt,
|
|
'show_meta' => $this->showMeta,
|
|
'show_categories' => $this->showCategories,
|
|
'excerpt_length' => $this->excerptLength,
|
|
'class' => $this->class,
|
|
'id' => $this->id,
|
|
'show_pagination' => $this->showPagination,
|
|
'posts_per_page' => $this->postsPerPage,
|
|
];
|
|
}
|
|
|
|
private static function clampInt(int $value, int $min, int $max): int
|
|
{
|
|
return max($min, min($max, $value));
|
|
}
|
|
|
|
private static function toBool(mixed $value): bool
|
|
{
|
|
if (is_bool($value)) {
|
|
return $value;
|
|
}
|
|
return $value === 'true' || $value === '1' || $value === 1;
|
|
}
|
|
|
|
private static function sanitizeOrderby(string $value): string
|
|
{
|
|
$allowed = ['date', 'title', 'modified', 'rand', 'comment_count'];
|
|
return in_array($value, $allowed, true) ? $value : 'date';
|
|
}
|
|
|
|
private static function sanitizeOrder(string $value): string
|
|
{
|
|
$upper = strtoupper($value);
|
|
return in_array($upper, ['ASC', 'DESC'], true) ? $upper : 'DESC';
|
|
}
|
|
}
|