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
+35 -1
View File
@@ -60,6 +60,9 @@ final class FormRenderer {
case 'checkbox':
self::checkboxes($field_id, $field_name, $field, $value);
break;
case 'terms':
self::terms($field_id, $field_name, $field, $value);
break;
case 'number':
case 'spinner':
case 'slider':
@@ -153,7 +156,38 @@ final class FormRenderer {
$max = isset($field['max']) ? ' max="' . esc_attr((string) $field['max']) . '"' : '';
$step = ' step="' . esc_attr((string) ($field['step'] ?? 1)) . '"';
$input_type = $type === 'slider' ? 'range' : 'number';
echo '<div class="aksrt-widget-number"><input class="widefat" type="' . esc_attr($input_type) . '" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr((string) $value) . '"' . $min . $max . $step . '><output>' . esc_html((string) $value) . '</output></div>';
$unit = trim((string) ($field['unit'] ?? ''));
echo '<div class="aksrt-widget-number"><input class="widefat" type="' . esc_attr($input_type) . '" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr((string) $value) . '"' . $min . $max . $step . '><output>' . esc_html((string) $value) . '</output>' . ($unit !== '' ? '<span class="aksrt-widget-number__unit">' . esc_html($unit) . '</span>' : '') . '</div>';
}
private static function terms(string $id, string $name, array $field, $value): void {
$taxonomy = (string) ($field['taxonomy'] ?? 'category');
$terms = get_terms(['taxonomy' => $taxonomy, 'hide_empty' => false, 'number' => 500, 'orderby' => 'name']);
if (is_wp_error($terms)) {
$terms = [];
}
$selected = array_values(array_filter(array_map('absint', (array) $value)));
$by_id = [];
foreach ($terms as $term) {
$by_id[(int) $term->term_id] = $term;
}
echo '<div class="aksrt-widget-terms" data-aksrt-terms="' . esc_attr($taxonomy) . '">';
echo '<input type="hidden" class="aksrt-widget-terms__value" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr(implode(',', $selected)) . '">';
echo '<div class="aksrt-widget-terms__selected">';
foreach ($selected as $term_id) {
if (!isset($by_id[$term_id])) {
continue;
}
echo '<span class="aksrt-widget-terms__chip" data-term-id="' . esc_attr((string) $term_id) . '"><span class="dashicons dashicons-move" aria-hidden="true"></span>' . esc_html((string) $by_id[$term_id]->name) . '<button type="button" class="button-link-delete aksrt-widget-terms__remove" aria-label="' . esc_attr__('移除', 'aksrt') . '">×</button></span>';
}
echo '</div>';
echo '<input type="search" class="widefat aksrt-widget-terms__search" placeholder="' . esc_attr__('输入关键词筛选', 'aksrt') . '" aria-label="' . esc_attr__('筛选可选分类', 'aksrt') . '">';
echo '<div class="aksrt-widget-terms__options">';
foreach ($terms as $term) {
$term_id = (int) $term->term_id;
echo '<label class="aksrt-widget-terms__option" data-term-name="' . esc_attr((string) $term->name) . '"><input type="checkbox" value="' . esc_attr((string) $term_id) . '" ' . checked(in_array($term_id, $selected, true), true, false) . '> ' . esc_html((string) $term->name) . '</label>';
}
echo '</div></div>';
}
private static function upload(string $id, string $name, string $value, string $library = ''): void {