feat(forum): rebuild plate, post and compose pages

Match the reference layouts for the remaining forum routes: plate pages
get the blurred header card, moderator row and the affix tab bar with
per-tab filtering, topping posts and moderator-only pending/trash tabs;
post pages get the article shell with breadcrumbs, cover, meta row,
vote box, tag row and footer actions; compose pages get the reference
editor plus settings sidebar (submit/draft, status, access, plate,
topic, tag, type, vote) with a cover picker. Saving now honours draft
state and the featured image through the REST contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Fable 5 committed 2026-11-11 16:17:55 +08:00
1 parent eceddb5f7d
commit 5d3358d844
13 files changed
+891 -199

No files matched your search

+55 -2
View File
@@ -73,8 +73,61 @@ final class Cards {
return '<h2 class="' . esc_attr($class) . '"><a' . $link_class . ' href="' . esc_url($url) . '" title="' . esc_attr($post->post_title) . '">' . $badges . esc_html($post->post_title) . '</a></h2>';
}
public static function plate_item(\WP_Post $plate): string {
$url = get_permalink($plate);
/** Plate page header: blurred cover, title, stats and moderators (reference layout). */
public static function plate_header(\WP_Post $plate): string {
$id = $plate->ID;
PlateStats::prime([$id]);
$stats = PlateStats::get($id);
$followers = (int) get_post_meta($id, '_jio_forum_follow_count', true);
$plate_name = (string) jio_get_setting('jio_forum_plate_name', '版块') ?: '版块';
$thumb = self::thumbnail($plate);
$cats = '';
$terms = wp_get_post_terms($id, Core::CATEGORY);
foreach (is_array($terms) ? $terms : [] as $term) {
$cats .= '<a class="badg badg-sm b-theme" href="' . esc_url(get_term_link($term)) . '">' . esc_html($term->name) . '</a>';
}
$meta = '<div class="px12-sm mt10"><item class="mate-posts mr10">' . esc_html(sprintf('%s %s', $plate_name, jio_cut_count($stats['posts']))) . '</item>'
. '<item class="mate-reply mr10">' . esc_html(sprintf('今日 %s', jio_cut_count($stats['today']))) . '</item>'
. ($followers > 0
? '<item class="mate-follow mr10">' . esc_html(sprintf('关注 %s', jio_cut_count($followers))) . '</item>'
: '') . '</div>';
$excerpt = wp_trim_words(wp_strip_all_tags($plate->post_excerpt ?: $plate->post_content), 40);
$html = '<div class="plate-header-wrap"><div class="forum-header blur-header relative-h mb20">';
$html .= '<div class="abs-blur-bg">' . $thumb . '</div><div class="absolute forum-mask"></div>';
if (get_post_meta($id, '_jio_forum_hot', true)) {
$html .= '<span class="img-badge top jb-red px12-sm">热门</span>';
}
$html .= '<div class="relative header-content"><div class="flex ac"><div class="item-info flex1">';
if ($cats !== '') $html .= '<div class="mb6">' . $cats . '</div>';
$html .= '<h1 class="forum-title em14"><a href="' . esc_url(get_permalink($plate)) . '">' . esc_html($plate->post_title) . '</a></h1>';
$html .= $meta;
if ($excerpt !== '') $html .= '<div class="desc px12-sm mt6">' . esc_html($excerpt) . '</div>';
$html .= '</div><div class="plate-thumb flex0 ml10">' . $thumb . '</div></div>';
$html .= self::plate_moderator_btns($plate);
return $html . '</div></div></div>';
}
/** Plate moderator avatars row under the header. */
private static function plate_moderator_btns(\WP_Post $plate): string {
$ids = array_values(array_unique(array_filter(array_merge(
[(int) $plate->post_author],
array_map('absint', (array) get_post_meta($plate->ID, '_jio_forum_moderators', true))
))));
if (!$ids) return '';
$btns = '';
foreach ($ids as $user_id) {
$user = get_userdata($user_id);
if (!$user) continue;
$btns .= '<a class="but c-white mr6 mt6" href="' . esc_url(get_author_posts_url($user_id)) . '" title="' . esc_attr($user->display_name) . '"><span class="avatar-mini avatar-img">' . get_avatar($user_id, 40) . '</span><span class="ml6">' . esc_html($user->display_name) . '</span></a>';
}
$html = '<div class="mt10 moderator-btns em09">' . $btns;
if (is_user_logged_in() && !Access::is_moderator(get_current_user_id(), $plate->ID) && jio_get_setting('jio_forum_moderator_apply', true)) {
$html .= '<button type="button" class="but hollow c-white mt6" data-forum-action="apply" data-id="' . (int) $plate->ID . '">申请版主</button>';
}
return $html . '</div>';
}
public static function plate_item(\WP_Post $plate): string { $url = get_permalink($plate);
$counts = PlateStats::get($plate->ID);
$today = $counts['today'] > 0 ? '<span class="badg but-plate hide-sm flex0" title="' . esc_attr(sprintf('今日新帖 %d', $counts['today'])) . '"><i class="fa fas fa-comment-dots c-red mr3"></i>' . esc_html(sprintf('今日:%s', jio_cut_count($counts['today']))) . '</span>' : '';
$excerpt = wp_trim_words(wp_strip_all_tags($plate->post_excerpt ?: $plate->post_content), 30);