Files
roi-theme/Shared/Application/UseCases/RenderPostGrid/RenderPostGridRequest.php
FrankZamora 79e91f59ee feat(theme): add [roi_post_grid] shortcode for static pages
- 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>
2025-12-06 21:33:20 -06:00

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';
}
}