feat(widgets): replicate 12 reference widgets for full Zibll parity

- rewrite schemas for posts, tab_posts, oneline_posts, hot_posts,
  term_cards, term_aggregation, media_cards, combo_info, partners,
  recent_comments, posts_toc and slider_media_combo to mirror the
  modern reference modules field by field (options, defaults,
  dependencies, min/max/step, subheadings)
- port reference renderers: hot ranking with TOP badges, category
  aggregation card, graphic cover cards, partners CSS marquee,
  combo info cards with auto band palette, recent comment list
- rename 分类与标签聚合卡片 to 分类聚合卡片 and restrict it to
  categories (no tags/topics branch in this project)
- drop topics filter fields and the topics query branch; align
  orderby value domain with supported post meta
- add searchable sortable terms admin field type and spinner unit
  suffix rendering
- unify widget pagination and lazy loading on the REST client with
  the runtime-owned ias reveal trigger; remove the legacy
  post_ajax_trigger dual path
- align section-navs TOC with the reference contract (wznav ids,
  3-heading minimum, zib-widget box)
This commit is contained in:
2026-09-05 11:28:00 +08:00
parent 9dc278bd83
commit b639d57c5b
25 changed files with 1388 additions and 446 deletions
+6 -18
View File
@@ -29,10 +29,10 @@ final class PostQuery {
$args['paged'] = 1;
}
// The modern tab widget uses Zibll's signed `cat` syntax. Legacy
// The modern post widgets use Zibll's signed `cat` syntax. Legacy
// category_ids remains available only to the unrelated generic posts
// widgets; a tab segment must never fall back to it.
$is_reference_segment = array_key_exists('cat', $segment) || array_key_exists('topics', $segment);
$is_reference_segment = array_key_exists('cat', $segment);
$cat_raw = array_key_exists('cat', $config) ? (string) $config['cat'] : ($is_reference_segment ? '' : (string) ($config['category_ids'] ?? ''));
$categories = self::signed_ids($cat_raw);
if (!empty($config['category_id'])) $categories = [(int) $config['category_id']];
@@ -44,17 +44,6 @@ final class PostQuery {
if ($tags) {
$args['tag__in'] = $tags;
}
$topics_raw = (string) ($config['topics'] ?? '');
$topics = self::signed_ids($topics_raw);
if ($topics) {
$tax_query = [];
$topic_in = array_values(array_filter($topics, static fn(int $id): bool => $id > 0));
$topic_not = array_values(array_map('abs', array_filter($topics, static fn(int $id): bool => $id < 0)));
if ($topic_in) $tax_query[] = ['taxonomy' => 'topics', 'field' => 'term_id', 'terms' => $topic_in, 'include_children' => true];
if ($topic_not) $tax_query[] = ['taxonomy' => 'topics', 'field' => 'term_id', 'terms' => $topic_not, 'operator' => 'NOT IN', 'include_children' => true];
if (count($tax_query) > 1) $tax_query = array_merge(['relation' => 'AND'], $tax_query);
if ($tax_query) $args['tax_query'] = $tax_query;
}
$days = max(0, (int) ($config['limit_day'] ?? 0));
if ($days > 0) {
@@ -65,7 +54,7 @@ final class PostQuery {
$args['date_query'] = [['after' => $format($now - ($days * DAY_IN_SECONDS)), 'before' => $format($now), 'inclusive' => true]];
}
self::apply_order($args, (string) ($config['orderby'] ?? 'date'), (string) ($config['order'] ?? 'DESC'));
$pay = $is_reference_segment ? '' : ($config['pay_type'] ?? '');
$pay = $is_reference_segment ? ($config['zibpay_type'] ?? []) : ($config['pay_type'] ?? '');
self::apply_pay_type($args, $pay);
return $args;
}
@@ -91,16 +80,15 @@ final class PostQuery {
$args['order'] = strtoupper($order) === 'ASC' ? 'ASC' : 'DESC';
$meta = [
'views' => class_exists('AKSRT\\Core\\DomainModel') ? \AKSRT\Core\DomainModel::POST_VIEW_COUNT_KEY : 'aksrt_post_views',
'like' => '_aksrt_like_count', 'likes' => '_aksrt_like_count',
'favorite' => '_aksrt_favorite_count', 'favorites' => '_aksrt_favorite_count',
'downloads' => class_exists('AKSRT\\Core\\DomainModel') ? \AKSRT\Core\DomainModel::RESOURCE_DOWNLOAD_COUNT_KEY : '_aksrt_res_download_count',
'like' => '_aksrt_like_count',
'favorite' => '_aksrt_favorite_count',
];
if (isset($meta[$orderby])) {
$args['meta_key'] = $meta[$orderby];
$args['orderby'] = 'meta_value_num';
return;
}
if ($orderby === 'comments' || $orderby === 'comment_count') {
if ($orderby === 'comment_count') {
$args['orderby'] = 'comment_count';
} elseif (in_array($orderby, ['date', 'modified', 'rand'], true)) {
$args['orderby'] = $orderby;