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
+19 -2
View File
@@ -27,10 +27,27 @@ final class FrontendRenderer {
self::render_user_widget($definition, $instance, $widget, $content);
return;
}
if (in_array($definition->slug(), ['post_pay', 'tab_posts', 'slider', 'slider_media_combo', 'icon_cards', 'icon_cover_cards', 'buttons', 'notice'], true)) {
if (in_array($definition->slug(), [
'post_pay', 'tab_posts', 'posts', 'oneline_posts', 'hot_posts',
'slider', 'slider_media_combo', 'icon_cards', 'icon_cover_cards',
'buttons', 'notice', 'term_cards', 'term_aggregation', 'media_cards',
'combo_info', 'partners', 'recent_comments', 'posts_toc',
], true)) {
echo (string) ($args['before_widget'] ?? '');
if ($definition->slug() !== 'post_pay') echo self::reference_title($instance);
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$animation = '';
$content_classes = ['widget-content'];
$device_class = WidgetVisibility::device_class($instance);
if ($device_class !== '') {
$content_classes[] = $device_class;
}
if (!empty($instance['animation_in'])) {
$content_classes[] = 'obs-animate ani-' . sanitize_html_class((string) $instance['animation_in']);
if (!empty($instance['animation_repeat'])) {
$content_classes[] = 'obs-animate-repeat';
}
}
echo '<div class="' . esc_attr(implode(' ', $content_classes)) . '">' . $content . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo (string) ($args['after_widget'] ?? '');
return;
}