feat: rewrite schema-driven widget system

This commit is contained in:
2026-08-17 17:29:54 +08:00
parent 6c6c462df8
commit ad99ab53ce
28 changed files with 3489 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
<?php
namespace AKSRT\WidgetSystem;
defined('ABSPATH') || exit;
/**
* Shared list/card/mini markup and pagination payloads.
*/
final class PostRenderer {
public static function payload(array $instance, string $slug, int $page = 1, string $segment = ''): array {
$segment_config = $slug === 'tab_posts' ? PostQuery::segment($instance, $segment) : [];
$query = PostQuery::build($instance, $page, $segment_config);
$html = self::items($query, $instance, $slug, $page);
$max_pages = max(1, (int) $query->max_num_pages);
$total = (int) $query->found_posts;
return [
'html' => $html,
'paginate_html' => self::pagination($instance, $page, $max_pages),
'has_more' => $page < $max_pages,
'page' => $page,
'max_pages' => $max_pages,
'total' => $total,
];
}
public static function items(\WP_Query $query, array $instance, string $slug, int $page = 1): string {
if (!$query->have_posts()) {
return RendererHelpers::empty_state(__('暂无文章', 'aksrt'));
}
$style = (string) ($instance['style'] ?? 'card');
$mode = in_array($style, ['list', 'card', 'mini'], true) ? $style : 'card';
$config = [
'mode' => $mode,
'context' => 'widget',
'columns' => $mode === 'card' ? 3 : 1,
'show_thumb' => $slug !== 'hot_posts' || !empty($instance['show_thumbnail']),
'show_meta' => $mode !== 'mini',
'show_excerpt' => $mode !== 'mini',
'show_author' => false,
'show_comments' => true,
'show_likes' => true,
'show_tags' => false,
'show_badges' => true,
'show_number' => $slug === 'hot_posts',
'number_offset' => ($page - 1) * max(1, (int) ($instance['count'] ?? 8)),
'wrapper_class' => 'aksrt-widget-posts aksrt-widget-posts--' . $slug,
];
if ($slug === 'oneline_posts') {
return self::oneline($query, $config, !empty($instance['autoplay']));
}
if (function_exists('aksrt_render_post_list')) {
return aksrt_render_post_list($query, $config, false);
}
$html = '<div class="aksrt-widget-posts aksrt-widget-posts--fallback">';
while ($query->have_posts()) {
$query->the_post();
$html .= '<article><a href="' . esc_url(get_permalink()) . '">' . get_the_post_thumbnail(get_the_ID(), 'medium') . '<strong>' . esc_html(get_the_title()) . '</strong></a></article>';
}
wp_reset_postdata();
return $html . '</div>';
}
private static function oneline(\WP_Query $query, array $config, bool $autoplay): string {
$slides = '';
while ($query->have_posts()) {
$query->the_post();
$item = function_exists('aksrt_render_post')
? aksrt_render_post(array_merge($config, ['skip_wrapper' => true]))
: '<a href="' . esc_url(get_permalink()) . '">' . esc_html(get_the_title()) . '</a>';
$slides .= '<div class="swiper-slide">' . $item . '</div>';
}
wp_reset_postdata();
return '<div class="swiper aksrt-widget-swiper aksrt-widget-oneline" data-aksrt-swiper="scroll" data-autoplay="' . ($autoplay ? '1' : '0') . '"><div class="swiper-wrapper">' . $slides . '</div><button class="swiper-button-prev" type="button" aria-label="' . esc_attr__('上一组', 'aksrt') . '"></button><button class="swiper-button-next" type="button" aria-label="' . esc_attr__('下一组', 'aksrt') . '"></button></div>';
}
private static function pagination(array $instance, int $page, int $max_pages): string {
$mode = (string) ($instance['paginate'] ?? 'none');
if ($max_pages <= 1 || $mode === 'none') {
return '';
}
if ($mode === 'numbered') {
$start = max(1, min($page - 2, $max_pages - 4));
$end = min($max_pages, max(5, $page + 2));
$html = '<nav class="aksrt-widget-pagination" aria-label="' . esc_attr__('文章分页', 'aksrt') . '">';
for ($number = $start; $number <= $end; $number++) {
$html .= '<button type="button" data-widget-page="' . $number . '"' . ($number === $page ? ' aria-current="page"' : '') . '>' . $number . '</button>';
}
return $html . '</nav>';
}
$label = $mode === 'infinite' ? __('继续加载', 'aksrt') : __('加载更多', 'aksrt');
return '<button class="aksrt-widget-load-more" type="button" data-next-page="' . (int) ($page + 1) . '" data-mode="' . esc_attr($mode) . '">' . esc_html($label) . '</button>';
}
}