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>
This commit is contained in:
FrankZamora
2025-12-06 21:33:20 -06:00
parent c23dc22d76
commit 79e91f59ee
13 changed files with 1532 additions and 2 deletions

View File

@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
namespace ROITheme\Shared\Infrastructure\Wordpress;
use ROITheme\Shared\Infrastructure\Di\DIContainer;
use ROITheme\Shared\Application\UseCases\RenderPostGrid\RenderPostGridRequest;
/**
* Registra el shortcode [roi_post_grid] en WordPress
*
* RESPONSABILIDAD:
* - Registrar shortcode via add_shortcode
* - Sanitizar atributos del shortcode
* - Delegar ejecucion a RenderPostGridUseCase
*
* NO RESPONSABLE DE:
* - Logica de negocio
* - Construccion de queries
* - Generacion de HTML/CSS
*
* @package ROITheme\Shared\Infrastructure\Wordpress
*/
final class PostGridShortcodeRegistrar
{
private const SHORTCODE_TAG = 'roi_post_grid';
/**
* Registra el shortcode en WordPress
*/
public static function register(): void
{
add_shortcode(self::SHORTCODE_TAG, [new self(), 'handleShortcode']);
}
/**
* Callback del shortcode
*
* @param array|string $atts Atributos del shortcode
* @return string HTML del grid
*/
public function handleShortcode($atts): string
{
$atts = $this->sanitizeAttributes($atts);
// Obtener paged desde query var si existe
$id = $atts['id'] ?? '';
$queryVar = !empty($id) ? "paged_{$id}" : 'paged';
$atts['paged'] = max(1, (int) get_query_var($queryVar, 1));
// Crear request DTO
$request = RenderPostGridRequest::fromArray($atts);
// Obtener UseCase desde DIContainer
$container = DIContainer::getInstance();
$useCase = $container->getRenderPostGridUseCase();
return $useCase->execute($request);
}
/**
* Sanitiza atributos del shortcode
*
* @param array|string $atts
* @return array<string, mixed>
*/
private function sanitizeAttributes($atts): array
{
$atts = shortcode_atts([
'category' => '',
'exclude_category' => '',
'tag' => '',
'author' => '',
'posts_per_page' => '9',
'columns' => '3',
'orderby' => 'date',
'order' => 'DESC',
'show_pagination' => 'false',
'offset' => '0',
'exclude_posts' => '',
'show_thumbnail' => 'true',
'show_excerpt' => 'true',
'show_meta' => 'true',
'show_categories' => 'true',
'excerpt_length' => '20',
'class' => '',
'id' => '',
], $atts, self::SHORTCODE_TAG);
// Sanitizar cada valor
return array_map(function ($value) {
return is_string($value) ? sanitize_text_field($value) : $value;
}, $atts);
}
}