feat(forum): add the reference forum widgets

Port the six forum widgets from the reference theme: posts list,
multi-tab posts, plate list (default and card), plate info, moderator
list and topic list. They join the schema widget catalog under a forum
group that stays hidden while the forum module is off, reuse the shared
forum cards, paginate through the widget REST client contract, and pull
the forum stylesheet/runtime onto any sidebar that hosts them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Fable 5 committed 2026-11-11 15:47:13 +08:00
1 parent 376827ea97
commit eceddb5f7d
12 files changed
+724 -13

No files matched your search

+11 -4
View File
@@ -33,16 +33,23 @@ final class FrontendRenderer {
self::render_reference_widget($definition, $instance, $widget, $content, true);
return;
}
if (in_array($definition->slug(), ['user_card', 'author_card', 'tab_posts', 'posts'], true)) {
if (in_array($definition->slug(), ['user_card', 'author_card', 'tab_posts', 'posts'], true)
|| in_array($definition->slug(), ['forum_posts', 'forum_tab_posts'], true)) {
self::render_reference_widget($definition, $instance, $widget, $content);
return;
}
if (in_array($definition->slug(), ['forum_plate_info', 'forum_moderators'], true)) {
// Reference: the plate card and the moderator box ship their own
// surface and title, so they only take the wrapper layer.
self::render_reference_widget($definition, $instance, $widget, $content, true, true);
return;
}
if (in_array($definition->slug(), [
'post_pay', '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',
], true)) {
], true) || in_array($definition->slug(), ['forum_plates', 'forum_topics'], true)) {
echo (string) ($args['before_widget'] ?? '');
if ($definition->slug() !== 'post_pay') echo self::reference_title($instance);
$content_classes = ['widget-content'];
@@ -100,7 +107,7 @@ final class FrontendRenderer {
* 搜索框 / 一言自带卡片(.zib-widget.widget-search / .yiyan-box),
* 此时不再套 .widget-content 与第二层卡片;其余模块保持 .widget-content 结构层。
*/
private static function render_reference_widget(WidgetDefinition $definition, array $instance, SchemaWidget $widget, string $content, bool $own_card = false): void {
private static function render_reference_widget(WidgetDefinition $definition, array $instance, SchemaWidget $widget, string $content, bool $own_card = false, bool $own_title = false): void {
$classes = ['jio-widget-box-wrap', 'jio-' . str_replace('_', '-', $definition->slug()) . '-wrap'];
if (in_array($definition->slug(), ['user_card', 'author_card'], true)) {
$classes[] = 'jio-user-widget-wrap';
@@ -127,7 +134,7 @@ final class FrontendRenderer {
if ($own_card) {
// 参考主题:搜索框/一言的中间层是 .theme-box,承载 20px 底部间距与入场动画。
echo '<div class="widget-container"><div class="theme-box' . esc_attr($animation) . '">';
echo self::reference_title($instance); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if (!$own_title) echo self::reference_title($instance); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</div></div></div>';
return;