导入 AKSRT 主题开发源码

This commit is contained in:
Claude Code committed 2026-07-03 22:50:34 +08:00
1 parent 9681dd3d48
commit 1268a55dd0
595 files changed
+127705

No files matched your search

+297
View File
@@ -0,0 +1,297 @@
<?php
/**
* Forum board template.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
get_header();
$forum = class_exists('AKSRT_Forum') ? AKSRT_Forum::get_instance() : null;
$current_user_id = get_current_user_id();
$board = get_queried_object();
$board_id = $board ? (int) $board->term_id : 0;
$paged = max(1, (int) get_query_var('paged', 1));
$view = $forum ? $forum->get_board_view($board_id, [
'user_id' => $current_user_id,
'paged' => $paged,
]) : [
'board' => null,
'topics' => [],
'sticky_topics' => [],
'moderators' => [],
'pagination' => ['page' => 1, 'max_pages' => 1, 'total' => 0],
'permissions' => [],
'application' => null,
'board_options' => [],
];
$board_data = $view['board'] ?? null;
$topics = $view['topics'] ?? [];
$sticky_topics = $view['sticky_topics'] ?? [];
$moderators = $view['moderators'] ?? [];
$permissions = $view['permissions'] ?? [];
$application = $view['application'] ?? null;
$board_options = $view['board_options'] ?? [];
$compose_url = add_query_arg('board', $board_id, home_url('/compose/'));
$admin_forum_url = admin_url('admin.php?page=aksrt-theme-admin#/forum/topics');
// Forum settings — names
$forum_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_forum_settings() : [];
$forum_names = $forum_settings['names'] ?? [];
$name_topic = $forum_names['posts'] ?? __('主题', 'aksrt');
$name_reply = $forum_names['comment'] ?? __('回复', 'aksrt');
$name_sticky = __('置顶', 'aksrt');
$name_featured = __('精华', 'aksrt');
?>
<main id="main-content" class="site-main container" tabindex="-1">
<div class="aksrt-forum-board container">
<div class="aksrt-forum-board__header">
<div class="aksrt-forum-board__info">
<h1 class="aksrt-forum-board__title"><?php echo esc_html((string) ($board_data['name'] ?? '')); ?></h1>
<?php if (!empty($board_data['description'])) : ?>
<p class="aksrt-forum-board__desc"><?php echo esc_html((string) $board_data['description']); ?></p>
<?php endif; ?>
<div class="aksrt-forum-board__meta">
<span><i class="fas fa-list-alt"></i> <?php printf(esc_html__('%1$d 个%2$s', 'aksrt'), (int) ($board_data['topic_count'] ?? 0), esc_html($name_topic)); ?></span>
<span><i class="fas fa-shield-alt"></i> <?php printf(esc_html__('%d 位版主', 'aksrt'), count($moderators)); ?></span>
</div>
</div>
<div class="aksrt-forum-board__actions">
<?php if (!empty($permissions['can_compose'])) : ?>
<a href="<?php echo esc_url($compose_url); ?>" class="aksrt-forum-board__compose-btn">
<i class="fas fa-pen"></i>
<?php esc_html_e('发布新主题', 'aksrt'); ?>
</a>
<?php else : ?>
<a href="<?php echo esc_url(wp_login_url(get_term_link($board))); ?>" class="aksrt-forum-board__compose-btn">
<i class="fas fa-sign-in-alt"></i>
<?php esc_html_e('登录后发帖', 'aksrt'); ?>
</a>
<?php endif; ?>
<?php if (!empty($permissions['can_moderate'])) : ?>
<a href="<?php echo esc_url($admin_forum_url); ?>" class="aksrt-forum-board__manage-btn">
<i class="fas fa-tools"></i>
<?php esc_html_e('进入治理后台', 'aksrt'); ?>
</a>
<?php endif; ?>
</div>
</div>
<section class="aksrt-forum-board__governance">
<div class="aksrt-forum-board__governance-card">
<h2 class="aksrt-forum-board__section-title"><?php esc_html_e('权限反馈', 'aksrt'); ?></h2>
<?php if (!is_user_logged_in()) : ?>
<p><?php esc_html_e('登录后可以发帖、申请版主,并在有权限时执行治理动作。', 'aksrt'); ?></p>
<?php elseif (!empty($permissions['can_moderate'])) : ?>
<p><?php esc_html_e('你当前拥有本版块治理权限,可在主题页执行审核、移动版块、可见性调整等操作。', 'aksrt'); ?></p>
<?php elseif ($application) : ?>
<p>
<?php esc_html_e('你的版主申请状态:', 'aksrt'); ?>
<strong><?php echo esc_html((string) ($application['status_label'] ?? '')); ?></strong>
</p>
<?php else : ?>
<p><?php esc_html_e('当前可浏览并发帖,若你熟悉本版块内容,可提交版主申请参与治理。', 'aksrt'); ?></p>
<?php endif; ?>
</div>
<div class="aksrt-forum-board__governance-card">
<h2 class="aksrt-forum-board__section-title"><?php esc_html_e('版主团队', 'aksrt'); ?></h2>
<?php if (!empty($moderators)) : ?>
<div class="aksrt-forum-board__moderators">
<?php foreach ($moderators as $moderator) : ?>
<div class="aksrt-forum-board__moderator">
<?php if (!empty($moderator['avatar_url'])) : ?>
<img src="<?php echo esc_url((string) $moderator['avatar_url']); ?>" alt="" width="36" height="36">
<?php endif; ?>
<span><?php echo esc_html((string) ($moderator['display_name'] ?? '')); ?></span>
</div>
<?php endforeach; ?>
</div>
<?php else : ?>
<p><?php esc_html_e('当前还没有设置版主。', 'aksrt'); ?></p>
<?php endif; ?>
</div>
<?php if (is_user_logged_in() && empty($permissions['can_moderate'])) : ?>
<div class="aksrt-forum-board__governance-card">
<h2 class="aksrt-forum-board__section-title"><?php esc_html_e('申请版主', 'aksrt'); ?></h2>
<?php if ($application) : ?>
<p><?php echo esc_html((string) ($application['status_label'] ?? '')); ?></p>
<?php if (!empty($application['review_note'])) : ?>
<p class="aksrt-forum-board__application-note"><?php echo esc_html((string) $application['review_note']); ?></p>
<?php endif; ?>
<?php else : ?>
<form class="aksrt-forum-board__application-form js-aksrt-moderator-apply-form" data-board-id="<?php echo esc_attr((string) $board_id); ?>">
<label for="aksrt-board-apply-reason"><?php esc_html_e('申请理由', 'aksrt'); ?></label>
<textarea id="aksrt-board-apply-reason" name="reason" rows="3" placeholder="<?php esc_attr_e('说明你熟悉该版块内容、希望承担的治理职责等。', 'aksrt'); ?>" required></textarea>
<div class="aksrt-forum-board__application-actions">
<button type="submit" class="aksrt-forum-board__apply-btn"><?php esc_html_e('提交申请', 'aksrt'); ?></button>
<span class="aksrt-forum-board__application-feedback js-aksrt-action-feedback" aria-live="polite"></span>
</div>
</form>
<?php endif; ?>
</div>
<?php endif; ?>
</section>
<?php if (!empty($sticky_topics)) : ?>
<div class="aksrt-forum-board__sticky">
<h3><i class="fas fa-thumbtack"></i> <?php esc_html_e('置顶主题', 'aksrt'); ?></h3>
<?php foreach ($sticky_topics as $topic) : ?>
<a href="<?php echo esc_url((string) ($topic['permalink'] ?? '#')); ?>" class="aksrt-forum-board__sticky-item">
<?php
$sticky_label = (string) ($topic['sticky_label'] ?? '');
if ($sticky_label === '') {
$sticky_label = __('置顶', 'aksrt');
}
?>
<span class="aksrt-forum-board__sticky-badge"><?php echo esc_html($sticky_label); ?></span>
<span class="aksrt-forum-board__sticky-title"><?php echo esc_html((string) ($topic['title'] ?? '')); ?></span>
<span class="aksrt-forum-board__sticky-meta">
<?php echo esc_html((string) ($topic['author']['display_name'] ?? '')); ?>
· <?php echo esc_html((string) ($topic['date'] ?? '')); ?>
</span>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="aksrt-forum-board__topics">
<?php if (!empty($topics)) : ?>
<?php foreach ($topics as $topic) :
$topic_id = (int) ($topic['id'] ?? 0);
?>
<?php
$item_sticky_level_class = (int) ($topic['sticky_level'] ?? 0) > 0
? ' is-sticky is-sticky-' . (int) ($topic['sticky_level'] ?? 0)
: '';
?>
<article class="aksrt-forum-topic-item<?php echo esc_attr($item_sticky_level_class); ?><?php echo !empty($topic['featured']) ? ' is-featured' : ''; ?>">
<div class="aksrt-forum-topic-item__avatar">
<?php if (!empty($topic['author']['avatar_url'])) : ?>
<img src="<?php echo esc_url((string) $topic['author']['avatar_url']); ?>" alt="" width="40" height="40">
<?php endif; ?>
</div>
<?php if (!empty($topic['cover'])) : ?>
<div class="aksrt-forum-topic-item__cover">
<?php if ($topic['cover']['type'] === 'video') : ?>
<div class="aksrt-forum-topic-item__cover-video">
<img src="<?php echo esc_url((string) ($topic['cover']['poster'] ?: $topic['cover']['url'])); ?>" alt="" loading="lazy">
<span class="aksrt-forum-topic-item__cover-play"><i class="fas fa-play-circle"></i></span>
</div>
<?php elseif ($topic['cover']['type'] === 'slide') : ?>
<div class="aksrt-forum-topic-item__cover-slide">
<img src="<?php echo esc_url((string) ($topic['cover']['images'][0] ?? '')); ?>" alt="" loading="lazy">
<span class="aksrt-forum-topic-item__cover-count"><i class="fas fa-images"></i> <?php echo count($topic['cover']['images']); ?></span>
</div>
<?php else : ?>
<img src="<?php echo esc_url((string) ($topic['cover']['url'] ?? '')); ?>" alt="" loading="lazy">
<?php endif; ?>
</div>
<?php endif; ?>
<div class="aksrt-forum-topic-item__body">
<div class="aksrt-forum-topic-item__title">
<?php
$item_sticky_level = (int) ($topic['sticky_level'] ?? 0);
$item_sticky_label = (string) ($topic['sticky_label'] ?? '');
if ($item_sticky_level > 0 && $item_sticky_label !== '') :
$item_sticky_mod = $item_sticky_level >= 3 ? 'global' : ($item_sticky_level === 2 ? 'super' : 'plate');
?>
<span class="aksrt-forum-topic-item__badge aksrt-forum-topic-item__badge--sticky aksrt-forum-topic-item__badge--sticky-<?php echo esc_attr($item_sticky_mod); ?>"><?php echo esc_html($item_sticky_label); ?></span>
<?php endif; ?>
<?php if (!empty($topic['featured'])) : ?><span class="aksrt-forum-topic-item__badge aksrt-forum-topic-item__badge--featured"><?php esc_html_e('精华', 'aksrt'); ?></span><?php endif; ?>
<?php if (($topic['bbs_type'] ?? 'standard') === 'question') : ?>
<?php $q_status = (int) ($topic['question_status'] ?? 0); ?>
<span class="aksrt-forum-topic-item__badge aksrt-forum-topic-item__badge--question<?php echo $q_status === 1 ? ' aksrt-forum-topic-item__badge--solved' : ''; ?>">
<?php echo $q_status === 1 ? esc_html__('已解决', 'aksrt') : esc_html__('提问', 'aksrt'); ?>
</span>
<?php endif; ?>
<?php if (!empty($topic['locked'])) : ?><i class="fas fa-lock aksrt-forum-topic-item__lock"></i><?php endif; ?>
<?php if (!empty($topic['visibility']['key']) && $topic['visibility']['key'] !== 'public') : ?>
<span class="aksrt-forum-topic-item__badge aksrt-forum-topic-item__badge--muted"><?php echo esc_html((string) ($topic['visibility']['label'] ?? '')); ?></span>
<?php endif; ?>
<a href="<?php echo esc_url((string) ($topic['permalink'] ?? '#')); ?>"><?php echo esc_html((string) ($topic['title'] ?? '')); ?></a>
</div>
<div class="aksrt-forum-topic-item__meta">
<span><?php echo esc_html((string) ($topic['author']['display_name'] ?? '')); ?></span>
<span><?php echo esc_html((string) ($topic['date'] ?? '')); ?></span>
<?php if (!empty($topic['special_topic'])) : ?>
<span><?php echo esc_html((string) $topic['special_topic']); ?></span>
<?php endif; ?>
</div>
</div>
<div class="aksrt-forum-topic-item__stats">
<span title="<?php echo esc_attr($name_reply); ?>"><i class="fas fa-comment"></i> <?php echo esc_html(number_format_i18n((int) ($topic['comment_count'] ?? 0))); ?></span>
<span title="<?php esc_attr_e('浏览', 'aksrt'); ?>"><i class="fas fa-eye"></i> <?php echo esc_html(number_format_i18n((int) ($topic['views'] ?? 0))); ?></span>
</div>
<?php if (!empty($permissions['can_moderate'])) : ?>
<div class="aksrt-forum-topic-item__actions">
<?php
$sticky_level = (int) ($topic['sticky_level'] ?? 0);
// 快捷按钮:无置顶↔版块置顶 切换;超级/全局置顶需进入治理表单调整。
$sticky_next = $sticky_level > 0 ? 0 : 1;
?>
<button
type="button"
class="aksrt-forum-topic-item__action js-aksrt-topic-action"
data-topic-id="<?php echo esc_attr((string) $topic_id); ?>"
data-action="sticky"
data-value="<?php echo esc_attr((string) $sticky_next); ?>"
data-value-type="int"
>
<?php echo $sticky_level > 0 ? esc_html__('取消置顶', 'aksrt') : esc_html__('置顶', 'aksrt'); ?>
</button>
<button
type="button"
class="aksrt-forum-topic-item__action js-aksrt-topic-action"
data-topic-id="<?php echo esc_attr((string) $topic_id); ?>"
data-action="locked"
data-value="<?php echo !empty($topic['locked']) ? '0' : '1'; ?>"
>
<?php echo !empty($topic['locked']) ? esc_html__('解锁', 'aksrt') : esc_html__('锁定', 'aksrt'); ?>
</button>
<a href="<?php echo esc_url((string) ($topic['permalink'] ?? '#') . '#aksrt-topic-moderation'); ?>" class="aksrt-forum-topic-item__action aksrt-forum-topic-item__action--link">
<?php esc_html_e('更多治理', 'aksrt'); ?>
</a>
</div>
<?php endif; ?>
</article>
<?php endforeach; ?>
<?php if (($view['pagination']['max_pages'] ?? 1) > 1) : ?>
<div class="aksrt-forum-board__pagination">
<?php
echo paginate_links([
'total' => (int) ($view['pagination']['max_pages'] ?? 1),
'current' => $paged,
'prev_text' => '<i class="fas fa-chevron-left"></i>',
'next_text' => '<i class="fas fa-chevron-right"></i>',
]);
?>
</div>
<?php endif; ?>
<?php else : ?>
<div class="aksrt-forum-board__empty">
<i class="fas fa-comments"></i>
<p><?php esc_html_e('当前版块还没有公开主题。', 'aksrt'); ?></p>
<?php if (!empty($permissions['can_compose'])) : ?>
<a href="<?php echo esc_url($compose_url); ?>"><?php esc_html_e('发布第一个主题', 'aksrt'); ?></a>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
</main>
<?php get_footer(); ?>
+409
View File
@@ -0,0 +1,409 @@
<?php
/**
* Template Name: 论坛发帖
* Template Post Type: page
*
* §7.4 — wp_editor rich editor + sidebar panels + server-side draft + capability gates.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
get_header();
if (!is_user_logged_in()) {
$login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url(get_permalink());
wp_safe_redirect($login_url);
exit;
}
$forum = class_exists('AKSRT_Forum') ? AKSRT_Forum::get_instance() : null;
$current_user_id = get_current_user_id();
$board_id = isset($_GET['board']) ? (int) $_GET['board'] : 0;
$draft_id = isset($_GET['draft']) ? (int) $_GET['draft'] : 0;
$view = $forum ? $forum->get_compose_view($current_user_id, ['board_id' => $board_id]) : [
'boards' => [],
'selected_board_id' => 0,
'visibility_options' => [],
'publish_mode' => 'pending',
'draft_count' => 0,
'drafts' => [],
'capabilities' => [],
];
$forum_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_forum_settings() : [];
$title_placeholder = $forum_settings['other']['t_placeholder'] ?? __('请输入标题', 'aksrt');
$content_placeholder = $forum_settings['other']['c_placeholder'] ?? __('请输入内容', 'aksrt');
$title_maxlen = max(5, min(100, (int) ($forum_settings['other']['title_strlen_limit'] ?? 30)));
$vote_max = (int) ($forum_settings['other']['vote_max'] ?? 8);
$forum_name = $forum_settings['names']['forum'] ?? __('论坛', 'aksrt');
$boards = $view['boards'] ?? [];
$visibility_options = $view['visibility_options'] ?? [];
$publish_mode = (string) ($view['publish_mode'] ?? 'pending');
$draft_count = (int) ($view['draft_count'] ?? 0);
$drafts = $view['drafts'] ?? [];
$caps = $view['capabilities'] ?? [];
$nonce = wp_create_nonce('aksrt_forum_compose');
// Load draft data if resuming
$draft_data = null;
if ($draft_id > 0 && $forum) {
$draft_data = $forum->load_draft_data($current_user_id, $draft_id);
if ($draft_data) {
$board_id = (int) ($draft_data['board_id'] ?? 0);
}
}
$initial_content = $draft_data ? $draft_data['content'] : '';
?>
<main id="main-content" class="site-main container" tabindex="-1">
<div class="aksrt-forum-compose container">
<div class="aksrt-forum-compose__header">
<div>
<h1><i class="fas fa-pen-fancy"></i> <?php esc_html_e('发布新主题', 'aksrt'); ?></h1>
<p class="aksrt-forum-compose__notice">
<?php
echo $publish_mode === 'publish'
? esc_html__('你在当前版块具备直接发布权限。', 'aksrt')
: esc_html__('普通用户发帖将进入审核流程,审核通过后才会公开展示。', 'aksrt');
?>
</p>
</div>
<a href="<?php echo esc_url(home_url('/forums/')); ?>" class="aksrt-forum-compose__back">
<i class="fas fa-arrow-left"></i> <?php printf(esc_html__('返回%s', 'aksrt'), esc_html($forum_name)); ?>
</a>
</div>
<?php if ($draft_count > 0) : ?>
<div class="aksrt-forum-compose__draft-notice">
<i class="fas fa-file-alt"></i>
<?php printf(
esc_html__('您有 %d 篇草稿。', 'aksrt'),
$draft_count
); ?>
<button type="button" class="aksrt-forum-compose__draft-toggle js-aksrt-draft-toggle">
<?php esc_html_e('查看草稿', 'aksrt'); ?>
<i class="fas fa-chevron-down"></i>
</button>
<div class="aksrt-forum-compose__draft-list" id="compose-draft-list" hidden>
<?php foreach ($drafts as $d) : ?>
<div class="aksrt-forum-compose__draft-item" data-draft-id="<?php echo esc_attr((string) $d['id']); ?>">
<a href="<?php echo esc_url(add_query_arg('draft', $d['id'], get_permalink())); ?>" class="aksrt-forum-compose__draft-title">
<?php echo esc_html($d['title']); ?>
</a>
<span class="aksrt-forum-compose__draft-meta">
<?php echo esc_html($d['board_name'] ?: __('未选版块', 'aksrt')); ?> &middot;
<?php echo esc_html(human_time_diff(strtotime($d['date']), current_time('timestamp'))); ?><?php esc_html_e('前', 'aksrt'); ?>
</span>
<button type="button" class="aksrt-forum-compose__draft-delete js-aksrt-delete-draft" data-draft-id="<?php echo esc_attr((string) $d['id']); ?>" title="<?php esc_attr_e('删除草稿', 'aksrt'); ?>">
<i class="fas fa-trash-alt"></i>
</button>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<form
id="aksrt-forum-compose-form"
class="aksrt-forum-compose__form aksrt-forum-compose__layout js-aksrt-forum-compose-form"
data-ajax="<?php echo esc_url(admin_url('admin-ajax.php')); ?>"
data-nonce="<?php echo esc_attr($nonce); ?>"
data-publish-mode="<?php echo esc_attr($publish_mode); ?>"
data-vote-max="<?php echo esc_attr((string) $vote_max); ?>"
data-draft-id="<?php echo esc_attr((string) ($draft_data['draft_id'] ?? 0)); ?>"
>
<!-- ═══ Main content area ═══ -->
<div class="aksrt-forum-compose__main">
<div class="aksrt-forum-compose__field">
<label for="compose-title"><?php esc_html_e('主题标题', 'aksrt'); ?> <span class="required">*</span></label>
<input type="text" id="compose-title" name="title" required
maxlength="<?php echo esc_attr((string) $title_maxlen); ?>"
placeholder="<?php echo esc_attr($title_placeholder); ?>"
value="<?php echo esc_attr($draft_data['title'] ?? ''); ?>"
data-aksrt-maxlength="<?php echo esc_attr((string) $title_maxlen); ?>">
<span class="aksrt-forum-compose__char-counter" id="compose-title-counter">
<span class="js-aksrt-counter-current"><?php echo esc_html((string) mb_strlen($draft_data['title'] ?? '')); ?></span> / <?php echo esc_html((string) $title_maxlen); ?>
</span>
</div>
<div class="aksrt-forum-compose__field aksrt-forum-compose__editor-wrap">
<label><?php esc_html_e('主题内容', 'aksrt'); ?> <span class="required">*</span></label>
<?php
$editor_settings = [
'textarea_name' => 'content',
'textarea_rows' => 18,
'media_buttons' => !empty($caps['can_upload_image']) || !empty($caps['can_upload_video']) || !empty($caps['can_upload_file']),
'teeny' => false,
'quicktags' => true,
'tinymce' => [
'toolbar1' => 'formatselect,bold,italic,underline,strikethrough,blockquote,bullist,numlist,alignleft,aligncenter,alignright,link,unlink,wp_more,fullscreen',
'toolbar2' => 'pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help',
'plugins' => 'paste,link,lists,fullscreen,wordpress,wplink,charmap',
],
];
if (empty($caps['can_upload_image']) && empty($caps['can_upload_video']) && empty($caps['can_upload_file'])) {
$editor_settings['tinymce']['toolbar1'] = str_replace(',wp_more', '', $editor_settings['tinymce']['toolbar1']);
}
wp_editor($initial_content, 'compose-content', $editor_settings);
?>
</div>
</div>
<!-- ═══ Sidebar panels ═══ -->
<div class="aksrt-forum-compose__sidebar">
<!-- Panel: Submit / Status -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-paper-plane"></i> <?php esc_html_e('发布', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<p class="aksrt-forum-compose__status-line">
<i class="fas fa-info-circle"></i>
<span id="compose-status-text">
<?php echo $publish_mode === 'publish'
? esc_html__('状态:直接发布', 'aksrt')
: esc_html__('状态:待审核', 'aksrt'); ?>
</span>
</p>
<div class="aksrt-forum-compose__actions">
<button type="submit" class="aksrt-forum-compose__submit" id="compose-submit">
<i class="fas fa-paper-plane"></i> <?php esc_html_e('提交主题', 'aksrt'); ?>
</button>
<button type="button" class="aksrt-forum-compose__draft" id="compose-draft">
<i class="fas fa-save"></i> <?php esc_html_e('保存草稿', 'aksrt'); ?>
</button>
</div>
<span class="aksrt-forum-compose__feedback js-aksrt-action-feedback" aria-live="polite"></span>
</div>
</div>
<!-- Panel: Board selector -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-th-large"></i> <?php esc_html_e('版块', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field aksrt-remote-select" data-search-action="aksrt_forum_search_boards">
<input type="hidden" id="compose-board" name="board_id" value="<?php echo esc_attr((string) $board_id); ?>">
<input type="text" class="aksrt-remote-select__input js-aksrt-remote-input"
placeholder="<?php esc_attr_e('搜索版块…', 'aksrt'); ?>"
autocomplete="off"
value="<?php
if ($board_id > 0) {
foreach ($boards as $b) {
if (((int) ($b['id'] ?? 0)) === $board_id) {
echo esc_attr((string) ($b['name'] ?? ''));
break;
}
}
}
?>">
<div class="aksrt-remote-select__dropdown" hidden></div>
</div>
</div>
</div>
<!-- Panel: Post type -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-tag"></i> <?php esc_html_e('类型 & 分类', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field">
<label for="compose-bbs-type"><?php esc_html_e('帖子类型', 'aksrt'); ?></label>
<select id="compose-bbs-type" name="bbs_type">
<option value="standard" <?php selected($draft_data['bbs_type'] ?? '', 'standard'); ?>><?php esc_html_e('标准帖子', 'aksrt'); ?></option>
<option value="question" <?php selected($draft_data['bbs_type'] ?? '', 'question'); ?>><?php esc_html_e('提问', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-compose__field">
<label for="compose-special"><?php esc_html_e('专题/系列', 'aksrt'); ?></label>
<input type="text" id="compose-special" name="special_topic" maxlength="80"
placeholder="<?php esc_attr_e('例如:站点重构周报', 'aksrt'); ?>"
value="<?php echo esc_attr($draft_data['special_topic'] ?? ''); ?>">
</div>
<?php if (taxonomy_exists('aksrt_forum_topic_cat')) : ?>
<div class="aksrt-forum-compose__field aksrt-remote-select" data-search-action="aksrt_forum_search_topics">
<label><?php esc_html_e('话题', 'aksrt'); ?></label>
<input type="hidden" name="topic_cat" value="<?php echo esc_attr($draft_data['topic_cat'] ?? ''); ?>">
<input type="text" class="aksrt-remote-select__input js-aksrt-remote-input"
placeholder="<?php esc_attr_e('搜索话题…', 'aksrt'); ?>"
autocomplete="off"
value="<?php echo esc_attr($draft_data['topic_cat'] ?? ''); ?>">
<div class="aksrt-remote-select__dropdown" hidden></div>
</div>
<?php endif; ?>
</div>
</div>
<!-- Panel: Tags -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-tags"></i> <?php esc_html_e('标签', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field aksrt-tag-input" data-search-action="aksrt_forum_search_tags" data-max="5">
<input type="hidden" id="compose-tags" name="tags" value="<?php echo esc_attr($draft_data['tags'] ?? ''); ?>">
<div class="aksrt-tag-input__tokens" id="compose-tag-tokens"></div>
<input type="text" class="aksrt-tag-input__input js-aksrt-tag-search"
placeholder="<?php esc_attr_e('输入标签名,回车添加', 'aksrt'); ?>"
autocomplete="off" maxlength="30">
<div class="aksrt-tag-input__dropdown" hidden></div>
</div>
</div>
</div>
<!-- Panel: Visibility -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-eye"></i> <?php esc_html_e('可见性', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field">
<select id="compose-visibility" name="visibility">
<?php foreach ($visibility_options as $option) : ?>
<option value="<?php echo esc_attr((string) ($option['value'] ?? '')); ?>"
<?php selected($draft_data['visibility'] ?? 'public', $option['value'] ?? ''); ?>>
<?php echo esc_html((string) ($option['label'] ?? '')); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="aksrt-forum-compose__visibility-extra" id="compose-credits-cost-field" style="display:none;">
<label for="compose-credits-cost"><?php esc_html_e('积分价格', 'aksrt'); ?></label>
<input type="number" id="compose-credits-cost" name="credits_cost" min="1" max="99999"
value="<?php echo esc_attr((string) ($draft_data['credits_cost'] ?? '')); ?>"
placeholder="<?php esc_attr_e('查看需要的积分数', 'aksrt'); ?>">
</div>
<div class="aksrt-forum-compose__visibility-extra" id="compose-pay-price-field" style="display:none;">
<label for="compose-pay-price"><?php esc_html_e('付费价格(¥)', 'aksrt'); ?></label>
<input type="number" id="compose-pay-price" name="pay_price" min="0.01" step="0.01" max="99999"
value="<?php echo esc_attr((string) ($draft_data['pay_price'] ?? '')); ?>"
placeholder="<?php esc_attr_e('查看需要的金额', 'aksrt'); ?>">
</div>
<div class="aksrt-forum-compose__visibility-extra" id="compose-role-field" style="display:none;">
<label for="compose-visibility-roles"><?php esc_html_e('允许的角色', 'aksrt'); ?></label>
<?php $selected_roles = $draft_data['visibility_roles'] ?? []; ?>
<select id="compose-visibility-roles" name="visibility_roles[]" multiple>
<?php foreach (wp_roles()->get_names() as $role_slug => $role_name) : ?>
<option value="<?php echo esc_attr($role_slug); ?>"
<?php echo in_array($role_slug, $selected_roles, true) ? 'selected' : ''; ?>>
<?php echo esc_html(translate_user_role($role_name)); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<!-- Panel: Cover -->
<?php if (!empty($caps['can_set_cover'])) : ?>
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-image"></i> <?php esc_html_e('封面', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field">
<select id="compose-cover-type" name="cover_type">
<option value="" <?php selected($draft_data['cover_type'] ?? '', ''); ?>><?php esc_html_e('无封面', 'aksrt'); ?></option>
<?php if (!empty($caps['can_set_cover_image'])) : ?>
<option value="image" <?php selected($draft_data['cover_type'] ?? '', 'image'); ?>><?php esc_html_e('图片封面', 'aksrt'); ?></option>
<?php endif; ?>
<?php if (!empty($caps['can_set_cover_slide'])) : ?>
<option value="slide" <?php selected($draft_data['cover_type'] ?? '', 'slide'); ?>><?php esc_html_e('幻灯片封面', 'aksrt'); ?></option>
<?php endif; ?>
<?php if (!empty($caps['can_set_cover_video'])) : ?>
<option value="video" <?php selected($draft_data['cover_type'] ?? '', 'video'); ?>><?php esc_html_e('视频封面', 'aksrt'); ?></option>
<?php endif; ?>
</select>
</div>
<div class="aksrt-forum-compose__cover-upload" id="compose-cover-image-field" style="display:none;">
<input type="hidden" name="cover_image" id="compose-cover-image" value="<?php echo esc_attr($draft_data['cover_image'] ?? ''); ?>">
<div class="aksrt-forum-compose__cover-preview" id="compose-cover-preview">
<?php if (!empty($draft_data['cover_image'])) : ?>
<img src="<?php echo esc_url($draft_data['cover_image']); ?>" alt="">
<?php endif; ?>
</div>
<button type="button" class="aksrt-forum-compose__cover-btn" id="compose-cover-upload-btn"><?php esc_html_e('选择图片', 'aksrt'); ?></button>
</div>
<div class="aksrt-forum-compose__cover-upload" id="compose-cover-slide-field" style="display:none;">
<input type="hidden" name="featured_slide" id="compose-featured-slide"
value="<?php echo esc_attr(!empty($draft_data['featured_slide']) ? wp_json_encode($draft_data['featured_slide']) : ''); ?>">
<div class="aksrt-forum-compose__cover-preview" id="compose-slide-preview">
<?php if (!empty($draft_data['featured_slide'])) : foreach ($draft_data['featured_slide'] as $su) : ?>
<img src="<?php echo esc_url($su); ?>" alt="">
<?php endforeach; endif; ?>
</div>
<button type="button" class="aksrt-forum-compose__cover-btn" id="compose-slide-upload-btn"><?php esc_html_e('选择图片', 'aksrt'); ?></button>
</div>
<div class="aksrt-forum-compose__cover-upload" id="compose-cover-video-field" style="display:none;">
<input type="url" name="featured_video" id="compose-featured-video"
value="<?php echo esc_attr($draft_data['featured_video'] ?? ''); ?>"
placeholder="<?php esc_attr_e('https://...mp4', 'aksrt'); ?>">
</div>
</div>
</div>
<?php endif; ?>
<!-- Panel: Vote -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title">
<label class="aksrt-forum-compose__checkbox">
<input type="checkbox" id="compose-vote-enabled" name="vote_enabled" value="1"
<?php checked(!empty($draft_data['vote_enabled'])); ?>>
<span><i class="fas fa-poll"></i> <?php esc_html_e('投票', 'aksrt'); ?></span>
</label>
</h3>
<div class="aksrt-forum-compose__panel-body aksrt-forum-compose__vote-fields" <?php echo empty($draft_data['vote_enabled']) ? 'hidden' : ''; ?>>
<div class="aksrt-forum-compose__field">
<label for="compose-vote-title"><?php esc_html_e('投票标题', 'aksrt'); ?></label>
<input type="text" id="compose-vote-title" name="vote_title" maxlength="120"
value="<?php echo esc_attr($draft_data['vote_title'] ?? ''); ?>"
placeholder="<?php esc_attr_e('你更希望改造哪个模块?', 'aksrt'); ?>">
</div>
<div class="aksrt-forum-compose__field">
<label class="aksrt-forum-compose__checkbox">
<input type="checkbox" id="compose-vote-multiple" name="vote_multiple" value="1"
<?php checked(!empty($draft_data['vote_multiple'])); ?>>
<span><?php esc_html_e('允许多选', 'aksrt'); ?></span>
</label>
</div>
<div class="aksrt-forum-compose__field">
<label for="compose-vote-type"><?php esc_html_e('投票类型', 'aksrt'); ?></label>
<select id="compose-vote-type" name="vote_type">
<option value="standard" <?php selected($draft_data['vote_type'] ?? '', 'standard'); ?>><?php esc_html_e('标准投票', 'aksrt'); ?></option>
<option value="pk" <?php selected($draft_data['vote_type'] ?? '', 'pk'); ?>><?php esc_html_e('PK 双选', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-compose__field">
<label for="compose-vote-expiry"><?php esc_html_e('投票有效期', 'aksrt'); ?></label>
<select id="compose-vote-expiry" name="vote_expiry_days">
<option value="0" <?php selected((int) ($draft_data['vote_expiry_days'] ?? 0), 0); ?>><?php esc_html_e('永久', 'aksrt'); ?></option>
<option value="1" <?php selected((int) ($draft_data['vote_expiry_days'] ?? 0), 1); ?>><?php esc_html_e('1 天', 'aksrt'); ?></option>
<option value="7" <?php selected((int) ($draft_data['vote_expiry_days'] ?? 0), 7); ?>><?php esc_html_e('7 天', 'aksrt'); ?></option>
<option value="30" <?php selected((int) ($draft_data['vote_expiry_days'] ?? 0), 30); ?>><?php esc_html_e('30 天', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-compose__field">
<label for="compose-vote-options"><?php printf(esc_html__('选项(最多 %d 项)', 'aksrt'), (int) $vote_max); ?></label>
<textarea id="compose-vote-options" name="vote_options" rows="4"
placeholder="<?php esc_attr_e("每行一个选项", 'aksrt'); ?>"><?php echo esc_textarea($draft_data['vote_options'] ?? ''); ?></textarea>
</div>
</div>
</div>
</div><!-- /.aksrt-forum-compose__sidebar -->
</form>
</div>
</main>
<?php get_footer(); ?>
+362
View File
@@ -0,0 +1,362 @@
<?php
/**
* 论坛帖子编辑模板
*
* §7.4 — Full-field AJAX editing with wp_editor, matching compose capabilities.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
if (!is_user_logged_in()) {
wp_safe_redirect(wp_login_url(get_permalink()));
exit;
}
$topic_id = get_the_ID();
$user_id = get_current_user_id();
$forum = class_exists('AKSRT_Forum') ? AKSRT_Forum::get_instance() : null;
if (!$forum || !$forum->can_edit_topic($user_id, $topic_id)) {
wp_safe_redirect(get_permalink($topic_id));
exit;
}
$topic = get_post($topic_id);
// Board
$board_id = 0;
$board_name = '';
if ($forum->is_plate_cpt_active()) {
$board_id = (int) get_post_meta($topic_id, '_aksrt_plate_id', true);
if ($board_id > 0) {
$board_name = get_the_title($board_id);
}
} else {
$terms = wp_get_post_terms($topic_id, 'aksrt_forum_board', ['fields' => 'all']);
if (!is_wp_error($terms) && !empty($terms)) {
$board_id = (int) $terms[0]->term_id;
$board_name = (string) $terms[0]->name;
}
}
// Tags
$tags = wp_get_post_terms($topic_id, 'aksrt_forum_tag', ['fields' => 'names']);
$tag_str = !is_wp_error($tags) && !empty($tags) ? implode(', ', $tags) : '';
// Topic category
$topic_cat = '';
if (taxonomy_exists('aksrt_forum_topic_cat')) {
$cats = wp_get_post_terms($topic_id, 'aksrt_forum_topic_cat', ['fields' => 'names']);
if (!is_wp_error($cats) && !empty($cats)) {
$topic_cat = $cats[0];
}
}
// Post meta
$visibility = get_post_meta($topic_id, '_aksrt_visibility', true) ?: 'public';
$bbs_type = get_post_meta($topic_id, '_aksrt_bbs_type', true) ?: 'standard';
$special_topic = get_post_meta($topic_id, '_aksrt_special_topic', true) ?: '';
$cover_type = get_post_meta($topic_id, '_aksrt_cover_type', true) ?: '';
$cover_image = get_post_meta($topic_id, '_aksrt_cover_image', true) ?: '';
$featured_slide = get_post_meta($topic_id, '_aksrt_featured_slide', true) ?: [];
$featured_video = get_post_meta($topic_id, '_aksrt_featured_video', true) ?: '';
$credits_cost = (int) get_post_meta($topic_id, '_aksrt_credits_cost', true);
$pay_price = get_post_meta($topic_id, '_aksrt_pay_price', true) ?: '';
$visibility_roles = get_post_meta($topic_id, '_aksrt_visibility_roles', true) ?: [];
$vote_enabled = get_post_meta($topic_id, '_aksrt_vote_enabled', true) === '1';
$vote_title = get_post_meta($topic_id, '_aksrt_vote_title', true) ?: '';
$vote_multiple = get_post_meta($topic_id, '_aksrt_vote_multiple', true) === '1';
$vote_type = get_post_meta($topic_id, '_aksrt_vote_type', true) ?: 'standard';
$vote_expiry_days = (int) get_post_meta($topic_id, '_aksrt_vote_expiry_days', true);
$vote_options_raw = get_post_meta($topic_id, '_aksrt_vote_options', true) ?: [];
$vote_options_text = is_array($vote_options_raw) ? implode("\n", array_column($vote_options_raw, 'label')) : '';
// Settings & capabilities
$forum_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_forum_settings() : [];
$title_maxlen = max(5, min(100, (int) ($forum_settings['other']['title_strlen_limit'] ?? 30)));
$vote_max = (int) ($forum_settings['other']['vote_max'] ?? 8);
$caps = $forum->get_compose_capabilities($user_id);
$visibility_options = $forum->get_visibility_options();
$nonce = wp_create_nonce('aksrt_forum_compose');
get_header();
?>
<main id="main-content" class="site-main container" tabindex="-1">
<div class="aksrt-forum-compose container">
<div class="aksrt-forum-compose__header">
<div>
<h1><i class="fas fa-edit"></i> <?php esc_html_e('编辑帖子', 'aksrt'); ?></h1>
</div>
<a href="<?php echo esc_url(get_permalink($topic_id)); ?>" class="aksrt-forum-compose__back">
<i class="fas fa-arrow-left"></i> <?php esc_html_e('返回帖子', 'aksrt'); ?>
</a>
</div>
<form
id="aksrt-forum-compose-form"
class="aksrt-forum-compose__form aksrt-forum-compose__layout js-aksrt-forum-edit-form"
data-ajax="<?php echo esc_url(admin_url('admin-ajax.php')); ?>"
data-nonce="<?php echo esc_attr($nonce); ?>"
data-topic-id="<?php echo esc_attr((string) $topic_id); ?>"
data-vote-max="<?php echo esc_attr((string) $vote_max); ?>"
>
<!-- ═══ Main content area ═══ -->
<div class="aksrt-forum-compose__main">
<div class="aksrt-forum-compose__field">
<label for="compose-title"><?php esc_html_e('主题标题', 'aksrt'); ?> <span class="required">*</span></label>
<input type="text" id="compose-title" name="title" required
maxlength="<?php echo esc_attr((string) $title_maxlen); ?>"
value="<?php echo esc_attr($topic->post_title); ?>"
data-aksrt-maxlength="<?php echo esc_attr((string) $title_maxlen); ?>">
<span class="aksrt-forum-compose__char-counter" id="compose-title-counter">
<span class="js-aksrt-counter-current"><?php echo esc_html((string) mb_strlen($topic->post_title)); ?></span> / <?php echo esc_html((string) $title_maxlen); ?>
</span>
</div>
<div class="aksrt-forum-compose__field aksrt-forum-compose__editor-wrap">
<label><?php esc_html_e('主题内容', 'aksrt'); ?> <span class="required">*</span></label>
<?php
wp_editor($topic->post_content, 'compose-content', [
'textarea_name' => 'content',
'textarea_rows' => 18,
'media_buttons' => !empty($caps['can_upload_image']) || !empty($caps['can_upload_video']) || !empty($caps['can_upload_file']),
'teeny' => false,
'quicktags' => true,
'tinymce' => [
'toolbar1' => 'formatselect,bold,italic,underline,strikethrough,blockquote,bullist,numlist,alignleft,aligncenter,alignright,link,unlink,wp_more,fullscreen',
'toolbar2' => 'pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help',
'plugins' => 'paste,link,lists,fullscreen,wordpress,wplink,charmap',
],
]);
?>
</div>
</div>
<!-- ═══ Sidebar panels ═══ -->
<div class="aksrt-forum-compose__sidebar">
<!-- Panel: Submit -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-save"></i> <?php esc_html_e('保存', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__actions">
<button type="submit" class="aksrt-forum-compose__submit" id="compose-submit">
<i class="fas fa-save"></i> <?php esc_html_e('保存修改', 'aksrt'); ?>
</button>
<a href="<?php echo esc_url(get_permalink($topic_id)); ?>" class="aksrt-forum-compose__draft">
<?php esc_html_e('取消', 'aksrt'); ?>
</a>
</div>
<span class="aksrt-forum-compose__feedback js-aksrt-action-feedback" aria-live="polite"></span>
</div>
</div>
<!-- Panel: Board (read-only in edit mode) -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-th-large"></i> <?php esc_html_e('版块', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<p class="aksrt-forum-compose__readonly"><?php echo esc_html($board_name ?: __('未分配', 'aksrt')); ?></p>
</div>
</div>
<!-- Panel: Type & Classification -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-tag"></i> <?php esc_html_e('类型 & 分类', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field">
<label for="compose-bbs-type"><?php esc_html_e('帖子类型', 'aksrt'); ?></label>
<select id="compose-bbs-type" name="bbs_type">
<option value="standard" <?php selected($bbs_type, 'standard'); ?>><?php esc_html_e('标准帖子', 'aksrt'); ?></option>
<option value="question" <?php selected($bbs_type, 'question'); ?>><?php esc_html_e('提问', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-compose__field">
<label for="compose-special"><?php esc_html_e('专题/系列', 'aksrt'); ?></label>
<input type="text" id="compose-special" name="special_topic" maxlength="80"
value="<?php echo esc_attr($special_topic); ?>">
</div>
<?php if (taxonomy_exists('aksrt_forum_topic_cat')) : ?>
<div class="aksrt-forum-compose__field aksrt-remote-select" data-search-action="aksrt_forum_search_topics">
<label><?php esc_html_e('话题', 'aksrt'); ?></label>
<input type="hidden" name="topic_cat" value="<?php echo esc_attr($topic_cat); ?>">
<input type="text" class="aksrt-remote-select__input js-aksrt-remote-input"
placeholder="<?php esc_attr_e('搜索话题…', 'aksrt'); ?>"
autocomplete="off"
value="<?php echo esc_attr($topic_cat); ?>">
<div class="aksrt-remote-select__dropdown" hidden></div>
</div>
<?php endif; ?>
</div>
</div>
<!-- Panel: Tags -->
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-tags"></i> <?php esc_html_e('标签', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field aksrt-tag-input" data-search-action="aksrt_forum_search_tags" data-max="5">
<input type="hidden" id="compose-tags" name="tags" value="<?php echo esc_attr($tag_str); ?>">
<div class="aksrt-tag-input__tokens" id="compose-tag-tokens"></div>
<input type="text" class="aksrt-tag-input__input js-aksrt-tag-search"
placeholder="<?php esc_attr_e('输入标签名,回车添加', 'aksrt'); ?>"
autocomplete="off" maxlength="30">
<div class="aksrt-tag-input__dropdown" hidden></div>
</div>
</div>
</div>
<!-- Panel: Visibility -->
<?php if (!empty($caps['can_set_visibility'])) : ?>
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-eye"></i> <?php esc_html_e('可见性', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field">
<select id="compose-visibility" name="visibility">
<?php foreach ($visibility_options as $option) : ?>
<option value="<?php echo esc_attr((string) ($option['value'] ?? '')); ?>"
<?php selected($visibility, $option['value'] ?? ''); ?>>
<?php echo esc_html((string) ($option['label'] ?? '')); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="aksrt-forum-compose__visibility-extra" id="compose-credits-cost-field" style="display:none;">
<label for="compose-credits-cost"><?php esc_html_e('积分价格', 'aksrt'); ?></label>
<input type="number" id="compose-credits-cost" name="credits_cost" min="1" max="99999"
value="<?php echo esc_attr((string) $credits_cost); ?>">
</div>
<div class="aksrt-forum-compose__visibility-extra" id="compose-pay-price-field" style="display:none;">
<label for="compose-pay-price"><?php esc_html_e('付费价格(¥)', 'aksrt'); ?></label>
<input type="number" id="compose-pay-price" name="pay_price" min="0.01" step="0.01" max="99999"
value="<?php echo esc_attr($pay_price); ?>">
</div>
<div class="aksrt-forum-compose__visibility-extra" id="compose-role-field" style="display:none;">
<label for="compose-visibility-roles"><?php esc_html_e('允许的角色', 'aksrt'); ?></label>
<select id="compose-visibility-roles" name="visibility_roles[]" multiple>
<?php foreach (wp_roles()->get_names() as $role_slug => $role_name) : ?>
<option value="<?php echo esc_attr($role_slug); ?>"
<?php echo in_array($role_slug, $visibility_roles, true) ? 'selected' : ''; ?>>
<?php echo esc_html(translate_user_role($role_name)); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<?php endif; ?>
<!-- Panel: Cover -->
<?php if (!empty($caps['can_set_cover'])) : ?>
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title"><i class="fas fa-image"></i> <?php esc_html_e('封面', 'aksrt'); ?></h3>
<div class="aksrt-forum-compose__panel-body">
<div class="aksrt-forum-compose__field">
<select id="compose-cover-type" name="cover_type">
<option value="" <?php selected($cover_type, ''); ?>><?php esc_html_e('无封面', 'aksrt'); ?></option>
<?php if (!empty($caps['can_set_cover_image'])) : ?>
<option value="image" <?php selected($cover_type, 'image'); ?>><?php esc_html_e('图片封面', 'aksrt'); ?></option>
<?php endif; ?>
<?php if (!empty($caps['can_set_cover_slide'])) : ?>
<option value="slide" <?php selected($cover_type, 'slide'); ?>><?php esc_html_e('幻灯片封面', 'aksrt'); ?></option>
<?php endif; ?>
<?php if (!empty($caps['can_set_cover_video'])) : ?>
<option value="video" <?php selected($cover_type, 'video'); ?>><?php esc_html_e('视频封面', 'aksrt'); ?></option>
<?php endif; ?>
</select>
</div>
<div class="aksrt-forum-compose__cover-upload" id="compose-cover-image-field" style="display:none;">
<input type="hidden" name="cover_image" id="compose-cover-image" value="<?php echo esc_attr($cover_image); ?>">
<div class="aksrt-forum-compose__cover-preview" id="compose-cover-preview">
<?php if ($cover_image) : ?>
<img src="<?php echo esc_url($cover_image); ?>" alt="">
<?php endif; ?>
</div>
<button type="button" class="aksrt-forum-compose__cover-btn" id="compose-cover-upload-btn"><?php esc_html_e('选择图片', 'aksrt'); ?></button>
</div>
<div class="aksrt-forum-compose__cover-upload" id="compose-cover-slide-field" style="display:none;">
<input type="hidden" name="featured_slide" id="compose-featured-slide"
value="<?php echo esc_attr(is_array($featured_slide) && !empty($featured_slide) ? wp_json_encode($featured_slide) : ''); ?>">
<div class="aksrt-forum-compose__cover-preview" id="compose-slide-preview">
<?php if (is_array($featured_slide)) : foreach ($featured_slide as $su) : ?>
<img src="<?php echo esc_url($su); ?>" alt="">
<?php endforeach; endif; ?>
</div>
<button type="button" class="aksrt-forum-compose__cover-btn" id="compose-slide-upload-btn"><?php esc_html_e('选择图片', 'aksrt'); ?></button>
</div>
<div class="aksrt-forum-compose__cover-upload" id="compose-cover-video-field" style="display:none;">
<input type="url" name="featured_video" id="compose-featured-video"
value="<?php echo esc_attr($featured_video); ?>"
placeholder="<?php esc_attr_e('https://...mp4', 'aksrt'); ?>">
</div>
</div>
</div>
<?php endif; ?>
<!-- Panel: Vote -->
<?php if (!empty($caps['can_set_vote'])) : ?>
<div class="aksrt-forum-compose__panel">
<h3 class="aksrt-forum-compose__panel-title">
<label class="aksrt-forum-compose__checkbox">
<input type="checkbox" id="compose-vote-enabled" name="vote_enabled" value="1"
<?php checked($vote_enabled); ?>>
<span><i class="fas fa-poll"></i> <?php esc_html_e('投票', 'aksrt'); ?></span>
</label>
</h3>
<div class="aksrt-forum-compose__panel-body aksrt-forum-compose__vote-fields" <?php echo !$vote_enabled ? 'hidden' : ''; ?>>
<div class="aksrt-forum-compose__field">
<label for="compose-vote-title"><?php esc_html_e('投票标题', 'aksrt'); ?></label>
<input type="text" id="compose-vote-title" name="vote_title" maxlength="120"
value="<?php echo esc_attr($vote_title); ?>">
</div>
<div class="aksrt-forum-compose__field">
<label class="aksrt-forum-compose__checkbox">
<input type="checkbox" id="compose-vote-multiple" name="vote_multiple" value="1"
<?php checked($vote_multiple); ?>>
<span><?php esc_html_e('允许多选', 'aksrt'); ?></span>
</label>
</div>
<div class="aksrt-forum-compose__field">
<label for="compose-vote-type"><?php esc_html_e('投票类型', 'aksrt'); ?></label>
<select id="compose-vote-type" name="vote_type">
<option value="standard" <?php selected($vote_type, 'standard'); ?>><?php esc_html_e('标准投票', 'aksrt'); ?></option>
<option value="pk" <?php selected($vote_type, 'pk'); ?>><?php esc_html_e('PK 双选', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-compose__field">
<label for="compose-vote-expiry"><?php esc_html_e('投票有效期', 'aksrt'); ?></label>
<select id="compose-vote-expiry" name="vote_expiry_days">
<option value="0" <?php selected($vote_expiry_days, 0); ?>><?php esc_html_e('永久', 'aksrt'); ?></option>
<option value="1" <?php selected($vote_expiry_days, 1); ?>><?php esc_html_e('1 天', 'aksrt'); ?></option>
<option value="7" <?php selected($vote_expiry_days, 7); ?>><?php esc_html_e('7 天', 'aksrt'); ?></option>
<option value="30" <?php selected($vote_expiry_days, 30); ?>><?php esc_html_e('30 天', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-compose__field">
<label for="compose-vote-options"><?php printf(esc_html__('选项(最多 %d 项)', 'aksrt'), (int) $vote_max); ?></label>
<textarea id="compose-vote-options" name="vote_options" rows="4"><?php echo esc_textarea($vote_options_text); ?></textarea>
</div>
</div>
</div>
<?php endif; ?>
</div><!-- /.aksrt-forum-compose__sidebar -->
</form>
</div>
</main>
<?php get_footer(); ?>
+107
View File
@@ -0,0 +1,107 @@
<?php
/**
* Plate category (分区) archive template.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
get_header();
$forum = class_exists('AKSRT_Forum') ? AKSRT_Forum::get_instance() : null;
$term = get_queried_object();
$cat_id = $term ? (int) $term->term_id : 0;
$forum_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_forum_settings() : [];
$forum_names = $forum_settings['names'] ?? [];
$forum_name = $forum_names['forum'] ?? __('论坛', 'aksrt');
$plates = [];
if ($forum && $cat_id > 0) {
$plates = $forum->get_sorted_plates('menu_order', 'ASC', 100);
$plates = array_filter($plates, static function ($plate) use ($cat_id): bool {
return isset($plate['plate_cat']['id']) && (int) $plate['plate_cat']['id'] === $cat_id;
});
$plates = array_values($plates);
}
$cat_moderator_ids = get_term_meta($cat_id, '_aksrt_cat_moderator', true);
$cat_moderators = [];
if (is_array($cat_moderator_ids)) {
foreach ($cat_moderator_ids as $uid) {
$user = get_userdata((int) $uid);
if ($user) {
$cat_moderators[] = [
'id' => (int) $user->ID,
'name' => $user->display_name,
'avatar' => function_exists('aksrt_get_avatar_url') ? aksrt_get_avatar_url($user->ID, 36) : get_avatar_url($user->ID, ['size' => 36]),
];
}
}
}
?>
<main id="main-content" class="site-main content-shell" tabindex="-1">
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
<div class="aksrt-forum-plate-cat container">
<div class="aksrt-forum-plate-cat__header">
<h1><?php echo esc_html($term ? $term->name : ''); ?></h1>
<?php if ($term && $term->description) : ?>
<p><?php echo esc_html($term->description); ?></p>
<?php endif; ?>
<?php if (!empty($cat_moderators)) : ?>
<div class="aksrt-forum-plate-cat__moderators">
<span><?php esc_html_e('分区版主:', 'aksrt'); ?></span>
<?php foreach ($cat_moderators as $mod) : ?>
<span class="aksrt-forum-plate-cat__moderator">
<?php if (!empty($mod['avatar'])) : ?>
<img src="<?php echo esc_url($mod['avatar']); ?>" alt="" width="24" height="24">
<?php endif; ?>
<?php echo esc_html($mod['name']); ?>
</span>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<div class="aksrt-forum-plate-cat__plates">
<?php if (!empty($plates)) : ?>
<?php foreach ($plates as $plate) : ?>
<a href="<?php echo esc_url((string) ($plate['url'] ?? '#')); ?>" class="aksrt-forum-plate-cat__plate-card">
<?php if (!empty($plate['cover_url'])) : ?>
<img class="aksrt-forum-plate-cat__plate-cover" src="<?php echo esc_url($plate['cover_url']); ?>" alt="" loading="lazy">
<?php elseif (!empty($plate['icon'])) : ?>
<div class="aksrt-forum-plate-cat__plate-icon"><i class="<?php echo esc_attr($plate['icon']); ?>"></i></div>
<?php endif; ?>
<div class="aksrt-forum-plate-cat__plate-info">
<h3><?php echo esc_html((string) ($plate['name'] ?? '')); ?></h3>
<p><?php echo esc_html((string) ($plate['description'] ?? '')); ?></p>
<div class="aksrt-forum-plate-cat__plate-meta">
<span><?php printf(esc_html__('%d 主题', 'aksrt'), (int) ($plate['post_count'] ?? 0)); ?></span>
<span><?php printf(esc_html__('%d 关注', 'aksrt'), (int) ($plate['follow_count'] ?? 0)); ?></span>
<?php if (!empty($plate['is_hot'])) : ?>
<span class="aksrt-forum-plate-cat__hot-badge"><?php esc_html_e('热门', 'aksrt'); ?></span>
<?php endif; ?>
</div>
</div>
</a>
<?php endforeach; ?>
<?php else : ?>
<div class="aksrt-forum-plate-cat__empty">
<p><?php esc_html_e('该分区暂无版块。', 'aksrt'); ?></p>
</div>
<?php endif; ?>
</div>
<div class="aksrt-forum-plate-cat__back">
<a href="<?php echo esc_url(home_url('/forums/')); ?>">
<i class="fas fa-arrow-left"></i> <?php printf(esc_html__('返回%s', 'aksrt'), esc_html($forum_name)); ?>
</a>
</div>
</div>
</main>
<?php get_footer(); ?>
+312
View File
@@ -0,0 +1,312 @@
<?php
/**
* Plate CPT single template (§7.2 板块独立页面).
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
get_header();
$forum = class_exists('AKSRT_Forum') ? AKSRT_Forum::get_instance() : null;
$current_user_id = get_current_user_id();
$plate_id = get_queried_object_id();
$paged = max(1, (int) get_query_var('paged', 1));
$view = $forum ? $forum->get_board_view($plate_id, [
'user_id' => $current_user_id,
'paged' => $paged,
]) : [
'board' => null,
'topics' => [],
'sticky_topics' => [],
'moderators' => [],
'pagination' => ['page' => 1, 'max_pages' => 1, 'total' => 0],
'permissions' => [],
'application' => null,
'board_options' => [],
];
$board_data = $view['board'] ?? null;
$topics = $view['topics'] ?? [];
$sticky_topics = $view['sticky_topics'] ?? [];
$moderators = $view['moderators'] ?? [];
$permissions = $view['permissions'] ?? [];
$application = $view['application'] ?? null;
$compose_url = add_query_arg('board', $plate_id, home_url('/compose/'));
$forum_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_forum_settings() : [];
$forum_names = $forum_settings['names'] ?? [];
$name_topic = $forum_names['posts'] ?? __('主题', 'aksrt');
$name_reply = $forum_names['comment'] ?? __('回复', 'aksrt');
$is_followed = $forum && $current_user_id > 0 ? $forum->is_user_following_plate($current_user_id, $plate_id) : false;
?>
<main id="main-content" class="site-main content-shell" tabindex="-1">
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
<?php if (!empty($permissions['access_denied'])) : ?>
<div class="aksrt-forum-board container">
<div class="aksrt-forum-board__access-denied">
<i class="fas fa-lock"></i>
<h2><?php esc_html_e('访问受限', 'aksrt'); ?></h2>
<p><?php
$reason = $permissions['access_reason'] ?? 'login';
if ($reason === 'login') {
esc_html_e('请登录后访问此版块。', 'aksrt');
} elseif ($reason === 'follow') {
esc_html_e('请先关注此版块后才能浏览内容。', 'aksrt');
} elseif ($reason === 'role') {
esc_html_e('你当前的角色无权访问此版块。', 'aksrt');
}
?></p>
</div>
</div>
<?php else : ?>
<div class="aksrt-forum-board container">
<div class="aksrt-forum-board__header">
<div class="aksrt-forum-board__info">
<?php if (!empty($board_data['cover_url'])) : ?>
<img class="aksrt-forum-board__cover" src="<?php echo esc_url((string) $board_data['cover_url']); ?>" alt="" loading="lazy">
<?php endif; ?>
<h1 class="aksrt-forum-board__title"><?php echo esc_html((string) ($board_data['name'] ?? '')); ?></h1>
<?php if (!empty($board_data['description'])) : ?>
<p class="aksrt-forum-board__desc"><?php echo esc_html((string) $board_data['description']); ?></p>
<?php endif; ?>
<div class="aksrt-forum-board__meta">
<span><i class="fas fa-list-alt"></i> <?php printf(esc_html__('%1$d 个%2$s', 'aksrt'), (int) ($board_data['post_count'] ?? $board_data['topic_count'] ?? 0), esc_html($name_topic)); ?></span>
<span><i class="fas fa-comments"></i> <?php printf(esc_html__('%d 条%s', 'aksrt'), (int) ($board_data['reply_count'] ?? 0), esc_html($name_reply)); ?></span>
<span><i class="fas fa-eye"></i> <?php printf(esc_html__('%d 浏览', 'aksrt'), (int) ($board_data['views'] ?? 0)); ?></span>
<span><i class="fas fa-heart"></i> <?php printf(esc_html__('%d 关注', 'aksrt'), (int) ($board_data['follow_count'] ?? 0)); ?></span>
<span><i class="fas fa-shield-alt"></i> <?php printf(esc_html__('%d 位版主', 'aksrt'), count($moderators)); ?></span>
</div>
</div>
<div class="aksrt-forum-board__actions">
<?php if ($current_user_id > 0) : ?>
<button type="button"
class="aksrt-forum-board__follow-btn js-aksrt-follow-plate"
data-plate-id="<?php echo esc_attr((string) $plate_id); ?>"
data-followed="<?php echo $is_followed ? '1' : '0'; ?>">
<i class="fas <?php echo $is_followed ? 'fa-heart' : 'fa-heart'; ?>"></i>
<?php echo $is_followed ? esc_html__('已关注', 'aksrt') : esc_html__('关注', 'aksrt'); ?>
</button>
<?php endif; ?>
<?php if (!empty($permissions['can_compose'])) : ?>
<a href="<?php echo esc_url($compose_url); ?>" class="aksrt-forum-board__compose-btn">
<i class="fas fa-pen"></i>
<?php esc_html_e('发布新主题', 'aksrt'); ?>
</a>
<?php endif; ?>
<?php
$is_forum_admin = $forum && $forum->is_forum_admin($current_user_id);
$is_plate_author = $board_data && (int) ($board_data['author_id'] ?? 0) === $current_user_id;
?>
<?php if ($is_forum_admin || $is_plate_author) : ?>
<button type="button" class="aksrt-forum-board__manage-btn js-aksrt-edit-plate"
data-plate-id="<?php echo esc_attr((string) $plate_id); ?>"
data-name="<?php echo esc_attr((string) ($board_data['name'] ?? '')); ?>"
data-description="<?php echo esc_attr((string) ($board_data['description'] ?? '')); ?>"
data-icon="<?php echo esc_attr((string) ($board_data['icon'] ?? '')); ?>"
data-cover="<?php echo esc_attr((string) ($board_data['cover_url'] ?? '')); ?>">
<i class="fas fa-cog"></i> <?php esc_html_e('编辑版块', 'aksrt'); ?>
</button>
<?php endif; ?>
<?php if ($is_forum_admin) : ?>
<button type="button" class="aksrt-forum-board__manage-btn aksrt-forum-board__manage-btn--danger js-aksrt-delete-plate"
data-plate-id="<?php echo esc_attr((string) $plate_id); ?>"
data-topic-count="<?php echo esc_attr((string) ($board_data['post_count'] ?? $board_data['topic_count'] ?? 0)); ?>">
<i class="fas fa-trash-alt"></i> <?php esc_html_e('删除版块', 'aksrt'); ?>
</button>
<?php endif; ?>
</div>
</div>
<?php if (!empty($board_data['content'])) : ?>
<div class="aksrt-forum-board__content entry-content">
<?php echo wp_kses_post((string) $board_data['content']); ?>
</div>
<?php endif; ?>
<section class="aksrt-forum-board__governance">
<div class="aksrt-forum-board__governance-card">
<h2 class="aksrt-forum-board__section-title"><?php esc_html_e('版主团队', 'aksrt'); ?></h2>
<?php if (!empty($moderators)) : ?>
<div class="aksrt-forum-board__moderators">
<?php foreach ($moderators as $moderator) : ?>
<div class="aksrt-forum-board__moderator">
<?php if (!empty($moderator['avatar'])) : ?>
<img src="<?php echo esc_url((string) $moderator['avatar']); ?>" alt="" width="36" height="36">
<?php endif; ?>
<span><?php echo esc_html((string) ($moderator['name'] ?? $moderator['display_name'] ?? '')); ?></span>
<?php if (!empty($moderator['role'])) : ?>
<small class="aksrt-forum-board__moderator-role"><?php echo esc_html((string) $moderator['role']); ?></small>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php else : ?>
<p><?php esc_html_e('当前还没有设置版主。', 'aksrt'); ?></p>
<?php endif; ?>
</div>
<div class="aksrt-forum-board__governance-card">
<h2 class="aksrt-forum-board__section-title"><?php esc_html_e('版主申请', 'aksrt'); ?></h2>
<?php if (!is_user_logged_in()) : ?>
<p class="aksrt-forum-board__application-note"><?php esc_html_e('登录后可申请协助管理本版块。', 'aksrt'); ?></p>
<a href="<?php echo esc_url(wp_login_url(get_permalink())); ?>" class="aksrt-forum-board__apply-btn"><?php esc_html_e('登录后申请', 'aksrt'); ?></a>
<?php elseif (!empty($application)) : ?>
<p class="aksrt-forum-board__application-note">
<?php printf(
esc_html__('你最近一次申请状态:%s', 'aksrt'),
esc_html((string) ($application['status_label'] ?? __('待处理', 'aksrt')))
); ?>
</p>
<?php if (!empty($application['reason'])) : ?>
<blockquote class="aksrt-forum-board__application-reason"><?php echo esc_html((string) $application['reason']); ?></blockquote>
<?php endif; ?>
<?php if (!empty($application['review_note'])) : ?>
<p class="aksrt-forum-board__application-note"><?php printf(esc_html__('审核备注:%s', 'aksrt'), esc_html((string) $application['review_note'])); ?></p>
<?php endif; ?>
<?php if (($application['status'] ?? '') !== 'pending' && !empty($permissions['can_apply_moderator'])) : ?>
<form class="aksrt-forum-board__application-form js-aksrt-moderator-apply-form" data-board-id="<?php echo esc_attr((string) $plate_id); ?>">
<label for="aksrt-plate-apply-reason"><?php esc_html_e('重新申请理由', 'aksrt'); ?></label>
<textarea id="aksrt-plate-apply-reason" name="reason" rows="4" placeholder="<?php esc_attr_e('请简要说明你的社区经验、擅长领域或管理计划。', 'aksrt'); ?>"></textarea>
<div class="aksrt-forum-board__application-actions">
<button type="submit" class="aksrt-forum-board__apply-btn"><?php esc_html_e('重新提交申请', 'aksrt'); ?></button>
<span class="aksrt-forum-board__application-feedback js-aksrt-action-feedback" aria-live="polite"></span>
</div>
</form>
<?php endif; ?>
<?php elseif (!empty($permissions['can_apply_moderator'])) : ?>
<p class="aksrt-forum-board__application-note"><?php esc_html_e('如果你熟悉本版块内容并愿意协助维护秩序,可以提交版主申请。', 'aksrt'); ?></p>
<form class="aksrt-forum-board__application-form js-aksrt-moderator-apply-form" data-board-id="<?php echo esc_attr((string) $plate_id); ?>">
<label for="aksrt-plate-apply-reason"><?php esc_html_e('申请理由', 'aksrt'); ?></label>
<textarea id="aksrt-plate-apply-reason" name="reason" rows="4" placeholder="<?php esc_attr_e('请简要说明你的社区经验、擅长领域或管理计划。', 'aksrt'); ?>"></textarea>
<div class="aksrt-forum-board__application-actions">
<button type="submit" class="aksrt-forum-board__apply-btn"><?php esc_html_e('提交版主申请', 'aksrt'); ?></button>
<span class="aksrt-forum-board__application-feedback js-aksrt-action-feedback" aria-live="polite"></span>
</div>
</form>
<?php else : ?>
<p class="aksrt-forum-board__application-note"><?php esc_html_e('你当前已是本版块管理成员,或暂不满足申请条件。', 'aksrt'); ?></p>
<?php endif; ?>
</div>
</section>
<?php if (!empty($sticky_topics)) : ?>
<div class="aksrt-forum-board__sticky">
<h3><i class="fas fa-thumbtack"></i> <?php esc_html_e('置顶主题', 'aksrt'); ?></h3>
<?php foreach ($sticky_topics as $topic) : ?>
<a href="<?php echo esc_url((string) ($topic['permalink'] ?? '#')); ?>" class="aksrt-forum-board__sticky-item">
<?php
$sticky_label = (string) ($topic['sticky_label'] ?? __('置顶', 'aksrt'));
?>
<span class="aksrt-forum-board__sticky-badge"><?php echo esc_html($sticky_label); ?></span>
<span class="aksrt-forum-board__sticky-title"><?php echo esc_html((string) ($topic['title'] ?? '')); ?></span>
<span class="aksrt-forum-board__sticky-meta">
<?php echo esc_html((string) ($topic['author']['display_name'] ?? '')); ?>
· <?php echo esc_html((string) ($topic['date'] ?? '')); ?>
</span>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="aksrt-forum-board__topics">
<?php if (!empty($topics)) : ?>
<?php foreach ($topics as $topic) : ?>
<?php
$topic_id = (int) ($topic['id'] ?? 0);
$item_sticky_level = (int) ($topic['sticky_level'] ?? 0);
$item_sticky_class = $item_sticky_level > 0
? ' is-sticky is-sticky-' . $item_sticky_level
: '';
?>
<article class="aksrt-forum-topic-item<?php echo esc_attr($item_sticky_class); ?><?php echo !empty($topic['featured']) ? ' is-featured' : ''; ?>">
<div class="aksrt-forum-topic-item__avatar">
<?php if (!empty($topic['author']['avatar_url'])) : ?>
<img src="<?php echo esc_url((string) $topic['author']['avatar_url']); ?>" alt="" width="40" height="40">
<?php endif; ?>
</div>
<div class="aksrt-forum-topic-item__body">
<div class="aksrt-forum-topic-item__title">
<?php if (!empty($topic['featured'])) : ?>
<span class="aksrt-forum-topic-item__badge aksrt-forum-topic-item__badge--featured"><?php esc_html_e('精华', 'aksrt'); ?></span>
<?php endif; ?>
<?php if (($topic['bbs_type'] ?? 'standard') === 'question') : ?>
<?php $q_status = (int) ($topic['question_status'] ?? 0); ?>
<span class="aksrt-forum-topic-item__badge aksrt-forum-topic-item__badge--question<?php echo $q_status === 1 ? ' aksrt-forum-topic-item__badge--solved' : ''; ?>">
<?php echo $q_status === 1 ? esc_html__('已解决', 'aksrt') : esc_html__('提问', 'aksrt'); ?>
</span>
<?php endif; ?>
<a href="<?php echo esc_url((string) ($topic['permalink'] ?? '#')); ?>"><?php echo esc_html((string) ($topic['title'] ?? '')); ?></a>
</div>
<div class="aksrt-forum-topic-item__meta">
<span><?php echo esc_html((string) ($topic['author']['display_name'] ?? '')); ?></span>
<span><?php echo esc_html((string) ($topic['date'] ?? '')); ?></span>
</div>
</div>
<?php if (!empty($topic['cover'])) : ?>
<div class="aksrt-forum-topic-item__cover">
<?php if ($topic['cover']['type'] === 'video') : ?>
<div class="aksrt-forum-topic-item__cover-video">
<?php if (!empty($topic['cover']['poster'])) : ?>
<img src="<?php echo esc_url((string) $topic['cover']['poster']); ?>" alt="" loading="lazy">
<?php endif; ?>
<i class="fas fa-play-circle"></i>
</div>
<?php elseif ($topic['cover']['type'] === 'slide') : ?>
<div class="aksrt-forum-topic-item__cover-slide">
<?php if (!empty($topic['cover']['images'][0])) : ?>
<img src="<?php echo esc_url((string) $topic['cover']['images'][0]); ?>" alt="" loading="lazy">
<?php endif; ?>
<span class="aksrt-forum-topic-item__cover-count"><i class="fas fa-images"></i> <?php echo count($topic['cover']['images']); ?></span>
</div>
<?php else : ?>
<img src="<?php echo esc_url((string) ($topic['cover']['url'] ?? '')); ?>" alt="" loading="lazy">
<?php endif; ?>
</div>
<?php endif; ?>
<div class="aksrt-forum-topic-item__stats">
<span title="<?php echo esc_attr($name_reply); ?>"><i class="fas fa-comment"></i> <?php echo esc_html(number_format_i18n((int) ($topic['comment_count'] ?? 0))); ?></span>
<span title="<?php esc_attr_e('浏览', 'aksrt'); ?>"><i class="fas fa-eye"></i> <?php echo esc_html(number_format_i18n((int) ($topic['views'] ?? 0))); ?></span>
</div>
</article>
<?php endforeach; ?>
<?php if (($view['pagination']['max_pages'] ?? 1) > 1) : ?>
<div class="aksrt-forum-board__pagination">
<?php
echo paginate_links([
'total' => (int) ($view['pagination']['max_pages'] ?? 1),
'current' => $paged,
'prev_text' => '<i class="fas fa-chevron-left"></i>',
'next_text' => '<i class="fas fa-chevron-right"></i>',
]);
?>
</div>
<?php endif; ?>
<?php else : ?>
<div class="aksrt-forum-board__empty">
<i class="fas fa-comments"></i>
<p><?php esc_html_e('当前版块还没有公开主题。', 'aksrt'); ?></p>
<?php if (!empty($permissions['can_compose'])) : ?>
<a href="<?php echo esc_url($compose_url); ?>"><?php esc_html_e('发布第一个主题', 'aksrt'); ?></a>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
</main>
<?php get_footer(); ?>
+92
View File
@@ -0,0 +1,92 @@
<?php
/**
* 论坛标签归档模板
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
get_header();
$term = get_queried_object();
$paged = max(1, (int) get_query_var('paged'));
$forum = class_exists('AKSRT_Forum') ? AKSRT_Forum::get_instance() : null;
$view = $forum ? $forum->get_tag_archive_view([
'term_id' => $term->term_id,
'paged' => $paged,
]) : ['topics' => [], 'term' => null, 'total' => 0, 'max_pages' => 0];
$topics = $view['topics'];
$total = $view['total'];
$max_pages = $view['max_pages'];
$term_name = $term->name ?? '';
$term_desc = $term->description ?? '';
?>
<main id="main-content" class="site-main container" tabindex="-1">
<div class="aksrt-forum-tag container">
<header class="aksrt-forum-tag__header">
<h1 class="aksrt-forum-tag__title">
<i class="fas fa-tag"></i>
<?php echo esc_html($term_name); ?>
</h1>
<?php if ($term_desc) : ?>
<p class="aksrt-forum-tag__desc"><?php echo esc_html($term_desc); ?></p>
<?php endif; ?>
<p class="aksrt-forum-tag__count"><?php printf(esc_html__('共 %d 个话题', 'aksrt'), $total); ?></p>
</header>
<?php if (!empty($topics)) : ?>
<div class="aksrt-forum-tag__list">
<?php foreach ($topics as $topic) : ?>
<article class="aksrt-forum-topic-card">
<div class="aksrt-forum-topic-card__body">
<h3 class="aksrt-forum-topic-card__title">
<a href="<?php echo esc_url($topic['permalink']); ?>"><?php echo esc_html($topic['title']); ?></a>
</h3>
<?php if ($topic['excerpt']) : ?>
<p class="aksrt-forum-topic-card__excerpt"><?php echo esc_html(wp_trim_words($topic['excerpt'], 30)); ?></p>
<?php endif; ?>
<div class="aksrt-forum-topic-card__meta">
<span class="aksrt-forum-topic-card__author">
<i class="fas fa-user"></i> <?php echo esc_html($topic['author']); ?>
</span>
<span class="aksrt-forum-topic-card__date">
<i class="fas fa-clock"></i> <?php echo esc_html($topic['date']); ?>
</span>
<span class="aksrt-forum-topic-card__comments">
<i class="fas fa-comment"></i> <?php echo (int) $topic['comment_count']; ?>
</span>
<span class="aksrt-forum-topic-card__views">
<i class="fas fa-eye"></i> <?php echo (int) $topic['views']; ?>
</span>
</div>
</div>
</article>
<?php endforeach; ?>
</div>
<?php if ($max_pages > 1) : ?>
<nav class="aksrt-forum-tag__pagination" aria-label="<?php esc_attr_e('话题分页', 'aksrt'); ?>">
<?php
echo paginate_links([
'total' => $max_pages,
'current' => $paged,
'prev_text' => '<i class="fas fa-chevron-left"></i>',
'next_text' => '<i class="fas fa-chevron-right"></i>',
]);
?>
</nav>
<?php endif; ?>
<?php else : ?>
<div class="aksrt-forum-tag__empty">
<i class="fas fa-comments"></i>
<p><?php esc_html_e('该标签下暂无话题', 'aksrt'); ?></p>
</div>
<?php endif; ?>
</div>
</main>
<?php get_footer(); ?>
+635
View File
@@ -0,0 +1,635 @@
<?php
/**
* Forum topic template.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
get_header();
if (!have_posts()) {
get_template_part('templates/parts/content', 'none');
get_footer();
return;
}
the_post();
$forum = class_exists('AKSRT_Forum') ? AKSRT_Forum::get_instance() : null;
$current_user_id = get_current_user_id();
$topic_id = get_the_ID();
$view = $forum ? $forum->get_topic_view($topic_id, $current_user_id) : [
'topic' => null,
'board' => null,
'permissions' => [],
'board_options' => [],
'visibility_options' => [],
'review_options' => [],
];
$topic = $view['topic'] ?? null;
$board = $view['board'] ?? null;
$permissions = $view['permissions'] ?? [];
$board_options = $view['board_options'] ?? [];
$visibility_options = $view['visibility_options'] ?? [];
$review_options = $view['review_options'] ?? [];
// Forum settings for names, breadcrumbs, reply
$forum_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_forum_settings() : [];
$forum_names = $forum_settings['names'] ?? [];
$forum_bc = $forum_settings['post_page'] ?? [];
$reply_settings = $forum_settings['reply'] ?? [];
$show_breadcrumbs = $forum_bc['breadcrumbs'] ?? true;
$bc_show_home = $forum_bc['breadcrumbs_bbs_home'] ?? true;
$bc_forum_name = $forum_bc['breadcrumbs_bbs_home_name'] ?: ($forum_names['forum'] ?? __('论坛', 'aksrt'));
$reply_placeholder = $reply_settings['placeholder'] ?? __('写下你的回复…', 'aksrt');
$name_sticky = $forum_names['posts'] ?? __('置顶', 'aksrt');
$name_featured = $forum_names['topic'] ?? __('精华', 'aksrt');
$name_reply = $forum_names['comment'] ?? __('回复', 'aksrt');
if (!$topic) {
get_template_part('templates/parts/content', 'none');
get_footer();
return;
}
if (empty($topic['can_view'])) :
$deny_vis = $topic['visibility']['key'] ?? '';
$credits_cost = (int) get_post_meta($topic_id, '_aksrt_credits_cost', true);
$pay_price = get_post_meta($topic_id, '_aksrt_pay_price', true);
?>
<main id="main-content" class="site-main content-shell" tabindex="-1">
<div class="aksrt-forum-topic container">
<div class="aksrt-forum-topic__denied">
<i class="fas fa-eye-slash"></i>
<h1><?php esc_html_e('当前主题暂不可访问', 'aksrt'); ?></h1>
<?php if ($deny_vis === 'login') : ?>
<p><?php esc_html_e('该主题仅限登录用户查看,请先登录后重试。', 'aksrt'); ?></p>
<a href="<?php echo esc_url(wp_login_url(get_permalink($topic_id))); ?>" class="aksrt-forum-topic__primary-btn"><?php esc_html_e('登录查看', 'aksrt'); ?></a>
<?php elseif ($deny_vis === 'comment') : ?>
<p><?php esc_html_e('评论后即可查看该主题的完整内容。', 'aksrt'); ?></p>
<?php elseif ($deny_vis === 'role') : ?>
<p><?php esc_html_e('你当前的角色无权查看此主题。', 'aksrt'); ?></p>
<?php elseif ($deny_vis === 'credits' && $credits_cost > 0) : ?>
<p><?php printf(esc_html__('查看该主题需要 %d 积分。', 'aksrt'), $credits_cost); ?></p>
<?php if (is_user_logged_in()) : ?>
<button type="button" class="aksrt-forum-topic__primary-btn js-aksrt-unlock-topic"
data-topic-id="<?php echo esc_attr((string) $topic_id); ?>"
data-cost="<?php echo esc_attr((string) $credits_cost); ?>">
<i class="fas fa-unlock"></i> <?php printf(esc_html__('使用 %d 积分解锁', 'aksrt'), $credits_cost); ?>
</button>
<span class="aksrt-forum-topic__unlock-feedback js-aksrt-action-feedback" aria-live="polite"></span>
<?php else : ?>
<a href="<?php echo esc_url(wp_login_url(get_permalink($topic_id))); ?>" class="aksrt-forum-topic__primary-btn"><?php esc_html_e('登录后解锁', 'aksrt'); ?></a>
<?php endif; ?>
<?php elseif ($deny_vis === 'pay') : ?>
<p><?php esc_html_e('该主题为付费内容,请购买后查看。', 'aksrt'); ?></p>
<?php if (!empty($pay_price)) : ?>
<span class="aksrt-forum-topic__pay-price"><?php printf(esc_html__('价格:¥%s', 'aksrt'), esc_html((string) $pay_price)); ?></span>
<?php endif; ?>
<?php else : ?>
<p><?php esc_html_e('该主题当前处于受限可见或审核状态。', 'aksrt'); ?></p>
<?php endif; ?>
</div>
</div>
</main>
<?php
get_footer();
return;
endif;
if ($forum) {
$forum->increment_view_count($topic_id);
$topic['views'] = (int) ($topic['views'] ?? 0) + 1;
}
$is_locked = !empty($topic['locked']);
$comments_enabled = !empty($permissions['can_reply']);
?>
<main id="main-content" class="site-main container" tabindex="-1">
<div class="aksrt-forum-topic container">
<?php if ($show_breadcrumbs) : ?>
<div class="aksrt-forum-topic__breadcrumb">
<?php if ($bc_show_home) : ?>
<a href="<?php echo esc_url(home_url('/forums/')); ?>"><?php echo esc_html($bc_forum_name); ?></a>
<?php endif; ?>
<?php if ($board) : ?>
<?php if ($bc_show_home) : ?><span class="aksrt-forum-topic__sep">/</span><?php endif; ?>
<a href="<?php echo esc_url((string) ($board['url'] ?? '#')); ?>"><?php echo esc_html((string) ($board['name'] ?? '')); ?></a>
<?php endif; ?>
<span class="aksrt-forum-topic__sep">/</span>
<span><?php echo esc_html((string) ($topic['title'] ?? '')); ?></span>
</div>
<?php endif; ?>
<header class="aksrt-forum-topic__header">
<div class="aksrt-forum-topic__header-top">
<h1 class="aksrt-forum-topic__title">
<?php
$sticky_level = (int) ($topic['sticky_level'] ?? 0);
$sticky_label = (string) ($topic['sticky_label'] ?? '');
if ($sticky_level > 0 && $sticky_label !== '') :
$sticky_mod = $sticky_level >= 3 ? 'global' : ($sticky_level === 2 ? 'super' : 'plate');
?>
<span class="aksrt-forum-topic__badge aksrt-forum-topic__badge--sticky aksrt-forum-topic__badge--sticky-<?php echo esc_attr($sticky_mod); ?>">
<?php echo esc_html($sticky_label); ?>
</span>
<?php endif; ?>
<?php if (!empty($topic['featured'])) : ?><span class="aksrt-forum-topic__badge aksrt-forum-topic__badge--featured"><?php esc_html_e('精华', 'aksrt'); ?></span><?php endif; ?>
<?php if ($is_locked) : ?><span class="aksrt-forum-topic__badge aksrt-forum-topic__badge--locked"><?php esc_html_e('已锁定', 'aksrt'); ?></span><?php endif; ?>
<?php if (($topic['visibility']['key'] ?? 'public') !== 'public') : ?><span class="aksrt-forum-topic__badge aksrt-forum-topic__badge--visibility"><?php echo esc_html((string) ($topic['visibility']['label'] ?? '')); ?></span><?php endif; ?>
<?php if (($topic['bbs_type'] ?? 'standard') === 'question') : ?>
<?php $q_status = (int) ($topic['question_status'] ?? 0); ?>
<span class="aksrt-forum-topic__badge aksrt-forum-topic__badge--question<?php echo $q_status === 1 ? ' aksrt-forum-topic__badge--solved' : ''; ?>">
<?php echo $q_status === 1 ? esc_html($forum_names['question_ok_badge'] ?? __('已解决', 'aksrt')) : esc_html($forum_names['question_badge'] ?? __('提问', 'aksrt')); ?>
</span>
<?php endif; ?>
<?php echo esc_html((string) ($topic['title'] ?? '')); ?>
</h1>
<div class="aksrt-forum-topic__meta">
<span class="aksrt-forum-topic__author">
<?php if (!empty($topic['author']['avatar_url'])) : ?>
<img src="<?php echo esc_url((string) $topic['author']['avatar_url']); ?>" alt="" width="24" height="24">
<?php endif; ?>
<?php echo esc_html((string) ($topic['author']['display_name'] ?? '')); ?>
</span>
<span><i class="fas fa-clock"></i> <?php echo esc_html((string) ($topic['date'] ?? '')); ?></span>
<span><i class="fas fa-eye"></i> <?php echo esc_html(number_format_i18n((int) ($topic['views'] ?? 0))); ?></span>
<span><i class="fas fa-comment"></i> <?php echo esc_html(number_format_i18n((int) ($topic['comment_count'] ?? 0))); ?></span>
<?php if (!empty($topic['review_status']['label'])) : ?>
<span><i class="fas fa-shield-check"></i> <?php echo esc_html((string) $topic['review_status']['label']); ?></span>
<?php endif; ?>
<?php if (($topic['score'] ?? 0) !== 0) : ?>
<span class="aksrt-forum-topic__score-badge"><i class="fas fa-star"></i> <?php echo esc_html(number_format_i18n((int) $topic['score'])); ?></span>
<?php endif; ?>
<?php if (($topic['favorite_count'] ?? 0) > 0) : ?>
<span><i class="fas fa-bookmark"></i> <?php echo esc_html(number_format_i18n((int) $topic['favorite_count'])); ?></span>
<?php endif; ?>
</div>
<div class="aksrt-forum-topic__quick-actions">
<?php if (is_user_logged_in()) : ?>
<button type="button" class="aksrt-forum-topic__quick-action js-aksrt-report-trigger"
data-target-type="post"
data-target-id="<?php echo esc_attr((string) $topic_id); ?>"
data-target-title="<?php echo esc_attr((string) ($topic['title'] ?? '')); ?>">
<i class="far fa-flag"></i>
<?php esc_html_e('举报', 'aksrt'); ?>
</button>
<?php endif; ?>
<?php if (is_user_logged_in()) : ?>
<?php $is_fav = !empty($topic['is_favorited']); ?>
<button type="button"
class="aksrt-forum-topic__quick-action js-aksrt-topic-favorite"
data-topic-id="<?php echo esc_attr((string) $topic_id); ?>"
data-favorited="<?php echo $is_fav ? '1' : '0'; ?>">
<i class="<?php echo $is_fav ? 'fas' : 'far'; ?> fa-bookmark"></i>
<span class="js-aksrt-favorite-label"><?php echo $is_fav ? esc_html__('已收藏', 'aksrt') : esc_html__('收藏', 'aksrt'); ?></span>
</button>
<?php endif; ?>
<?php if (!empty($permissions['can_edit'])) : ?>
<a href="<?php echo esc_url(add_query_arg('edit', '1', get_permalink($topic_id))); ?>" class="aksrt-forum-topic__quick-action">
<i class="fas fa-edit"></i>
<?php esc_html_e('编辑主题', 'aksrt'); ?>
</a>
<?php endif; ?>
<?php if (!empty($permissions['can_moderate'])) : ?>
<a href="#aksrt-topic-moderation" class="aksrt-forum-topic__quick-action">
<i class="fas fa-tools"></i>
<?php esc_html_e('治理动作', 'aksrt'); ?>
</a>
<?php endif; ?>
</div>
</header>
<div class="aksrt-forum-report-modal" id="aksrt-report-modal" hidden>
<div class="aksrt-forum-report-modal__backdrop js-aksrt-report-close"></div>
<div class="aksrt-forum-report-modal__dialog" role="dialog" aria-modal="true" aria-labelledby="aksrt-report-title">
<div class="aksrt-forum-report-modal__head">
<h2 id="aksrt-report-title"><?php esc_html_e('提交举报', 'aksrt'); ?></h2>
<button type="button" class="aksrt-forum-report-modal__close js-aksrt-report-close" aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>">×</button>
</div>
<p class="aksrt-forum-report-modal__target js-aksrt-report-target"></p>
<form class="aksrt-forum-report-modal__form js-aksrt-report-form">
<input type="hidden" name="target_type" value="post">
<input type="hidden" name="target_id" value="<?php echo esc_attr((string) $topic_id); ?>">
<div class="aksrt-forum-topic__field">
<label for="aksrt-report-category"><?php esc_html_e('举报分类', 'aksrt'); ?></label>
<select id="aksrt-report-category" name="category">
<option value="spam"><?php esc_html_e('垃圾信息', 'aksrt'); ?></option>
<option value="abuse"><?php esc_html_e('人身攻击', 'aksrt'); ?></option>
<option value="copyright"><?php esc_html_e('版权投诉', 'aksrt'); ?></option>
<option value="other"><?php esc_html_e('其他问题', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-topic__field">
<label for="aksrt-report-reason"><?php esc_html_e('举报说明', 'aksrt'); ?></label>
<textarea id="aksrt-report-reason" name="reason" rows="4" required placeholder="<?php esc_attr_e('请尽量描述清楚问题,以便管理员处理。', 'aksrt'); ?>"></textarea>
</div>
<div class="aksrt-forum-report-modal__actions">
<button type="submit" class="aksrt-forum-topic__primary-btn"><?php esc_html_e('提交举报', 'aksrt'); ?></button>
<span class="aksrt-forum-report-modal__feedback js-aksrt-action-feedback" aria-live="polite"></span>
</div>
</form>
</div>
</div>
<?php if (!empty($topic['cover'])) : ?>
<div class="aksrt-forum-topic__cover aksrt-forum-topic__cover--<?php echo esc_attr($topic['cover']['type']); ?>">
<?php if ($topic['cover']['type'] === 'video') : ?>
<div class="aksrt-forum-topic__cover-player" data-src="<?php echo esc_url((string) $topic['cover']['url']); ?>" data-poster="<?php echo esc_url((string) ($topic['cover']['poster'] ?? '')); ?>">
<?php if (!empty($topic['cover']['poster'])) : ?>
<img src="<?php echo esc_url((string) $topic['cover']['poster']); ?>" alt="" class="aksrt-forum-topic__cover-poster">
<?php endif; ?>
<button type="button" class="aksrt-forum-topic__cover-play-btn"><i class="fas fa-play-circle"></i></button>
</div>
<?php elseif ($topic['cover']['type'] === 'slide') : ?>
<div class="aksrt-forum-topic__cover-slides">
<?php foreach (($topic['cover']['images'] ?? []) as $slide_url) : ?>
<img src="<?php echo esc_url((string) $slide_url); ?>" alt="" loading="lazy">
<?php endforeach; ?>
</div>
<?php else : ?>
<img src="<?php echo esc_url((string) ($topic['cover']['url'] ?? '')); ?>" alt="" class="aksrt-forum-topic__cover-img">
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (!empty($topic['special_topic']) || !empty($topic['tags']) || !empty($topic['topic_cat'])) : ?>
<div class="aksrt-forum-topic__taxonomy">
<?php if (!empty($topic['topic_cat'])) : ?>
<a class="aksrt-forum-topic__chip aksrt-forum-topic__chip--topic-cat" href="<?php echo esc_url((string) ($topic['topic_cat']['url'] ?? '#')); ?>">
<?php echo esc_html((string) ($topic['topic_cat']['name'] ?? '')); ?>
</a>
<?php endif; ?>
<?php if (!empty($topic['special_topic'])) : ?>
<span class="aksrt-forum-topic__chip aksrt-forum-topic__chip--special"><?php echo esc_html((string) $topic['special_topic']); ?></span>
<?php endif; ?>
<?php foreach (($topic['tags'] ?? []) as $tag) : ?>
<a class="aksrt-forum-topic__chip" href="<?php echo esc_url((string) ($tag['url'] ?? '#')); ?>">
#<?php echo esc_html((string) ($tag['name'] ?? '')); ?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<article class="aksrt-forum-topic__content">
<?php the_content(); ?>
</article>
<?php
$score_extra_max = (int) ($forum_settings['post_page']['score_extra_max'] ?? 5);
$score_deduct_max = (int) ($forum_settings['post_page']['score_deduct_max'] ?? 3);
$current_score = (int) ($topic['score'] ?? 0);
?>
<?php if (is_user_logged_in() && (int) ($topic['author_id'] ?? 0) !== get_current_user_id()) : ?>
<div class="aksrt-forum-topic__score-actions" data-topic-id="<?php echo esc_attr((string) $topic_id); ?>">
<span class="aksrt-forum-topic__score-total">
<i class="fas fa-star"></i>
<span class="js-aksrt-score-value"><?php echo esc_html(number_format_i18n($current_score)); ?></span>
<?php esc_html_e('分', 'aksrt'); ?>
</span>
<?php if ($score_extra_max > 0) : ?>
<button type="button" class="aksrt-forum-topic__score-btn aksrt-forum-topic__score-btn--up js-aksrt-topic-score" data-amount="1" title="<?php esc_attr_e('加分', 'aksrt'); ?>">
<i class="fas fa-plus"></i>
</button>
<?php endif; ?>
<?php if ($score_deduct_max > 0) : ?>
<button type="button" class="aksrt-forum-topic__score-btn aksrt-forum-topic__score-btn--down js-aksrt-topic-score" data-amount="-1" title="<?php esc_attr_e('减分', 'aksrt'); ?>">
<i class="fas fa-minus"></i>
</button>
<?php endif; ?>
<span class="aksrt-forum-topic__score-feedback js-aksrt-action-feedback" aria-live="polite"></span>
</div>
<?php endif; ?>
<?php if (!empty($topic['vote']['enabled'])) : ?>
<?php
$vote_type = $topic['vote']['vote_type'] ?? 'standard';
$vote_expired = !empty($topic['vote']['expired']);
$vote_display = $topic['vote']['display_mode'] ?? 'percent';
$vote_expiry = (int) ($topic['vote']['expiry_days'] ?? 0);
$vote_disabled = $vote_expired || !empty($topic['vote']['has_voted']);
?>
<section class="aksrt-forum-topic__vote<?php echo $vote_type === 'pk' ? ' aksrt-forum-topic__vote--pk' : ''; ?><?php echo $vote_expired ? ' aksrt-forum-topic__vote--expired' : ''; ?>">
<div class="aksrt-forum-topic__vote-head">
<h2><?php echo esc_html((string) ($topic['vote']['title'] ?: __('参与投票', 'aksrt'))); ?></h2>
<span>
<?php printf(esc_html__('%d 人已投票', 'aksrt'), (int) ($topic['vote']['total_votes'] ?? 0)); ?>
<?php if ($vote_type === 'pk') : ?>
<span class="aksrt-forum-topic__vote-type-badge"><?php esc_html_e('PK', 'aksrt'); ?></span>
<?php endif; ?>
<?php if ($vote_expired) : ?>
<span class="aksrt-forum-topic__vote-expired-badge"><?php esc_html_e('已结束', 'aksrt'); ?></span>
<?php elseif ($vote_expiry > 0) : ?>
<span class="aksrt-forum-topic__vote-expiry-info"><?php printf(esc_html__('%d 天有效期', 'aksrt'), $vote_expiry); ?></span>
<?php endif; ?>
</span>
</div>
<form class="aksrt-forum-topic__vote-form js-aksrt-topic-vote-form" data-topic-id="<?php echo esc_attr((string) $topic_id); ?>" data-multiple="<?php echo !empty($topic['vote']['multiple']) ? '1' : '0'; ?>">
<div class="aksrt-forum-topic__vote-options">
<?php foreach (($topic['vote']['options'] ?? []) as $option) :
$selected = !empty($option['selected']);
$count = (int) ($option['count'] ?? 0);
$total_votes = max(1, (int) ($topic['vote']['total_votes'] ?? 0));
$ratio = (int) round(($count / $total_votes) * 100);
?>
<label class="aksrt-forum-topic__vote-option<?php echo $selected ? ' is-selected' : ''; ?>">
<input
type="<?php echo !empty($topic['vote']['multiple']) ? 'checkbox' : 'radio'; ?>"
name="option_ids[]"
value="<?php echo esc_attr((string) ($option['id'] ?? '')); ?>"
<?php checked($selected); ?>
<?php disabled($vote_disabled); ?>
>
<span class="aksrt-forum-topic__vote-label"><?php echo esc_html((string) ($option['label'] ?? '')); ?></span>
<span class="aksrt-forum-topic__vote-count">
<?php if ($vote_display === 'number') : ?>
<?php echo esc_html(number_format_i18n($count)); ?>
<?php else : ?>
<?php echo esc_html(number_format_i18n($count)); ?> / <?php echo esc_html((string) $ratio); ?>%
<?php endif; ?>
</span>
</label>
<?php endforeach; ?>
</div>
<div class="aksrt-forum-topic__vote-actions">
<?php if ($vote_expired) : ?>
<span class="aksrt-forum-topic__vote-feedback is-error"><?php esc_html_e('投票已结束。', 'aksrt'); ?></span>
<?php elseif (!empty($topic['vote']['has_voted'])) : ?>
<span class="aksrt-forum-topic__vote-feedback is-success"><?php esc_html_e('你已经参与过本次投票。', 'aksrt'); ?></span>
<?php else : ?>
<button type="submit" class="aksrt-forum-topic__primary-btn"><?php esc_html_e('提交投票', 'aksrt'); ?></button>
<span class="aksrt-forum-topic__vote-feedback js-aksrt-action-feedback" aria-live="polite"></span>
<?php endif; ?>
</div>
</form>
</section>
<?php endif; ?>
<?php if (!empty($permissions['can_moderate'])) : ?>
<section id="aksrt-topic-moderation" class="aksrt-forum-topic__moderation">
<div class="aksrt-forum-topic__moderation-head">
<h2><?php esc_html_e('主题治理', 'aksrt'); ?></h2>
<p><?php esc_html_e('支持审核、移动版块、可见性调整以及置顶/精华/锁定等治理动作。', 'aksrt'); ?></p>
</div>
<?php if (!empty($topic['moderation_note'])) : ?>
<div class="aksrt-forum-topic__moderation-note">
<strong><?php esc_html_e('最近治理备注:', 'aksrt'); ?></strong>
<span><?php echo esc_html((string) $topic['moderation_note']); ?></span>
</div>
<?php endif; ?>
<form class="aksrt-forum-topic__moderation-form js-aksrt-topic-moderation-form" data-topic-id="<?php echo esc_attr((string) $topic_id); ?>">
<div class="aksrt-forum-topic__moderation-grid">
<div class="aksrt-forum-topic__field">
<label for="aksrt-topic-moderation-action"><?php esc_html_e('治理动作', 'aksrt'); ?></label>
<select id="aksrt-topic-moderation-action" name="action" class="js-aksrt-moderation-action" required>
<option value="review"><?php esc_html_e('审核状态', 'aksrt'); ?></option>
<option value="move_board"><?php esc_html_e('移动版块', 'aksrt'); ?></option>
<option value="visibility"><?php esc_html_e('修改可见性', 'aksrt'); ?></option>
<option value="sticky"><?php esc_html_e('置顶切换', 'aksrt'); ?></option>
<option value="featured"><?php esc_html_e('精华切换', 'aksrt'); ?></option>
<option value="locked"><?php esc_html_e('锁定切换', 'aksrt'); ?></option>
<option value="close"><?php esc_html_e('关闭帖子', 'aksrt'); ?></option>
<option value="hide"><?php esc_html_e('隐藏帖子', 'aksrt'); ?></option>
<option value="delete"><?php esc_html_e('删除到回收站', 'aksrt'); ?></option>
<?php if (get_post_status($topic_id) === 'trash') : ?>
<option value="undelete"><?php esc_html_e('撤销删除', 'aksrt'); ?></option>
<?php endif; ?>
<?php if (($topic['bbs_type'] ?? 'standard') === 'question') : ?>
<option value="question_status"><?php esc_html_e('提问状态', 'aksrt'); ?></option>
<?php endif; ?>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="review">
<label for="aksrt-topic-review-status"><?php esc_html_e('审核结果', 'aksrt'); ?></label>
<select id="aksrt-topic-review-status" name="review_status">
<?php foreach ($review_options as $option) : ?>
<option value="<?php echo esc_attr((string) ($option['value'] ?? '')); ?>" <?php selected((string) (($topic['review_status']['key'] ?? '')) === (string) ($option['value'] ?? '')); ?>>
<?php echo esc_html((string) ($option['label'] ?? '')); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="move_board" hidden>
<label for="aksrt-topic-target-board"><?php esc_html_e('目标版块', 'aksrt'); ?></label>
<select id="aksrt-topic-target-board" name="target_board_id">
<?php foreach ($board_options as $option) : ?>
<option value="<?php echo esc_attr((string) ($option['id'] ?? '')); ?>" <?php selected((int) ($board['id'] ?? 0), (int) ($option['id'] ?? 0)); ?>>
<?php echo esc_html((string) ($option['name'] ?? '')); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="visibility" hidden>
<label for="aksrt-topic-visibility"><?php esc_html_e('可见性', 'aksrt'); ?></label>
<select id="aksrt-topic-visibility" name="visibility">
<?php foreach ($visibility_options as $option) : ?>
<option value="<?php echo esc_attr((string) ($option['value'] ?? '')); ?>" <?php selected((string) (($topic['visibility']['key'] ?? '')) === (string) ($option['value'] ?? '')); ?>>
<?php echo esc_html((string) ($option['label'] ?? '')); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field js-aksrt-visibility-extra" data-field="visibility" data-visibility-field="credits" hidden>
<label for="aksrt-topic-credits-cost"><?php esc_html_e('积分价格', 'aksrt'); ?></label>
<input id="aksrt-topic-credits-cost" name="credits_cost" type="number" min="1" max="99999" value="<?php echo esc_attr((string) ((int) get_post_meta($topic_id, '_aksrt_credits_cost', true))); ?>">
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field js-aksrt-visibility-extra" data-field="visibility" data-visibility-field="pay" hidden>
<label for="aksrt-topic-pay-price"><?php esc_html_e('付费价格(¥)', 'aksrt'); ?></label>
<input id="aksrt-topic-pay-price" name="pay_price" type="number" min="0.01" step="0.01" max="99999" value="<?php echo esc_attr((string) get_post_meta($topic_id, '_aksrt_pay_price', true)); ?>">
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field js-aksrt-visibility-extra" data-field="visibility" data-visibility-field="role" hidden>
<label for="aksrt-topic-visibility-roles"><?php esc_html_e('允许角色', 'aksrt'); ?></label>
<?php $current_visibility_roles = (array) get_post_meta($topic_id, '_aksrt_visibility_roles', true); ?>
<select id="aksrt-topic-visibility-roles" name="visibility_roles[]" multiple>
<?php foreach (wp_roles()->get_names() as $role_slug => $role_name) : ?>
<option value="<?php echo esc_attr($role_slug); ?>" <?php selected(in_array($role_slug, $current_visibility_roles, true)); ?>>
<?php echo esc_html(translate_user_role($role_name)); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="sticky" hidden>
<label for="aksrt-topic-sticky"><?php esc_html_e('置顶级别', 'aksrt'); ?></label>
<select id="aksrt-topic-sticky" name="sticky_value">
<?php
$current_sticky = (int) ($topic['sticky_level'] ?? 0);
$sticky_levels = [
0 => __('不置顶', 'aksrt'),
1 => __('版块置顶', 'aksrt'),
2 => __('超级置顶', 'aksrt'),
3 => __('全局置顶', 'aksrt'),
];
foreach ($sticky_levels as $level => $label) :
?>
<option value="<?php echo esc_attr((string) $level); ?>" <?php selected($current_sticky, $level); ?>>
<?php echo esc_html($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="featured" hidden>
<label for="aksrt-topic-featured"><?php esc_html_e('精华状态', 'aksrt'); ?></label>
<select id="aksrt-topic-featured" name="featured_value">
<option value="1" <?php selected(!empty($topic['featured'])); ?>><?php esc_html_e('设为精华', 'aksrt'); ?></option>
<option value="0" <?php selected(empty($topic['featured'])); ?>><?php esc_html_e('取消精华', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="locked" hidden>
<label for="aksrt-topic-locked"><?php esc_html_e('锁定状态', 'aksrt'); ?></label>
<select id="aksrt-topic-locked" name="locked_value">
<option value="1" <?php selected(!empty($topic['locked'])); ?>><?php esc_html_e('锁定主题', 'aksrt'); ?></option>
<option value="0" <?php selected(empty($topic['locked'])); ?>><?php esc_html_e('解除锁定', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="close" hidden>
<label for="aksrt-topic-close"><?php esc_html_e('关闭状态', 'aksrt'); ?></label>
<select id="aksrt-topic-close" name="close_value">
<option value="1"><?php esc_html_e('关闭帖子', 'aksrt'); ?></option>
<option value="0"><?php esc_html_e('重新开放', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="hide" hidden>
<label for="aksrt-topic-hide"><?php esc_html_e('隐藏状态', 'aksrt'); ?></label>
<select id="aksrt-topic-hide" name="hide_value">
<option value="1"><?php esc_html_e('隐藏帖子', 'aksrt'); ?></option>
<option value="0"><?php esc_html_e('恢复显示', 'aksrt'); ?></option>
</select>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="delete" hidden>
<label for="aksrt-topic-delete-confirm"><?php esc_html_e('删除确认', 'aksrt'); ?></label>
<select id="aksrt-topic-delete-confirm" name="delete_value">
<option value="1"><?php esc_html_e('确认删除到回收站', 'aksrt'); ?></option>
</select>
<small><?php esc_html_e('删除后作者会收到通知,主题可在回收站中恢复。', 'aksrt'); ?></small>
</div>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="undelete" hidden>
<label for="aksrt-topic-undelete-confirm"><?php esc_html_e('恢复确认', 'aksrt'); ?></label>
<select id="aksrt-topic-undelete-confirm" name="undelete_value">
<option value="1"><?php esc_html_e('确认恢复主题', 'aksrt'); ?></option>
</select>
</div>
<?php if (($topic['bbs_type'] ?? 'standard') === 'question') : ?>
<div class="aksrt-forum-topic__field js-aksrt-moderation-field" data-field="question_status" hidden>
<label for="aksrt-topic-question-status"><?php esc_html_e('提问状态', 'aksrt'); ?></label>
<select id="aksrt-topic-question-status" name="question_status_value">
<option value="0" <?php selected((int) ($topic['question_status'] ?? 0), 0); ?>><?php esc_html_e('未解决', 'aksrt'); ?></option>
<option value="1" <?php selected((int) ($topic['question_status'] ?? 0), 1); ?>><?php esc_html_e('已解决', 'aksrt'); ?></option>
</select>
</div>
<?php endif; ?>
</div>
<div class="aksrt-forum-topic__field">
<label for="aksrt-topic-moderation-note"><?php esc_html_e('治理备注', 'aksrt'); ?></label>
<textarea id="aksrt-topic-moderation-note" name="note" rows="3" placeholder="<?php esc_attr_e('记录处理原因,便于后续审计和沟通。', 'aksrt'); ?>"></textarea>
</div>
<div class="aksrt-forum-topic__moderation-actions">
<button type="submit" class="aksrt-forum-topic__primary-btn"><?php esc_html_e('执行治理动作', 'aksrt'); ?></button>
<span class="aksrt-forum-topic__moderation-feedback js-aksrt-action-feedback" aria-live="polite"></span>
</div>
</form>
</section>
<?php endif; ?>
<section class="aksrt-forum-topic__replies" id="aksrt-forum-replies"
data-topic-id="<?php echo esc_attr((string) $topic_id); ?>"
data-nonce="<?php echo esc_attr(wp_create_nonce('aksrt_public_nonce')); ?>">
<div class="aksrt-forum-replies__header">
<h2 class="aksrt-forum-topic__replies-title">
<i class="fas fa-comments"></i>
<?php
printf(esc_html__('%1$d 条%2$s', 'aksrt'), (int) get_comments_number(), esc_html($name_reply));
?>
</h2>
<div class="aksrt-forum-replies__tabs">
<button type="button" class="aksrt-forum-replies__tab is-active" data-sort="newest"><?php esc_html_e('最新', 'aksrt'); ?></button>
<button type="button" class="aksrt-forum-replies__tab" data-sort="oldest"><?php esc_html_e('最早', 'aksrt'); ?></button>
<button type="button" class="aksrt-forum-replies__tab" data-sort="hottest"><?php esc_html_e('最热', 'aksrt'); ?></button>
<label class="aksrt-forum-replies__filter">
<input type="checkbox" class="aksrt-forum-replies__author-toggle" value="1">
<?php esc_html_e('只看楼主', 'aksrt'); ?>
</label>
</div>
</div>
<div class="aksrt-forum-replies__list js-aksrt-forum-replies-list">
<?php
if ($forum) {
$reply_data = $forum->get_forum_comments($topic_id, 'newest', false, 1, 30);
$forum->render_forum_comments($reply_data['comments'], $topic_id, $reply_data['adopted_id']);
$reply_max_pages = $reply_data['max_pages'];
$reply_total = $reply_data['total'];
} else {
$reply_max_pages = 1;
$reply_total = 0;
}
?>
</div>
<?php if ($reply_max_pages > 1) : ?>
<div class="aksrt-forum-replies__load-more">
<button type="button" class="aksrt-forum-replies__more-btn js-aksrt-forum-load-more"
data-page="1" data-max="<?php echo esc_attr((string) $reply_max_pages); ?>">
<i class="fas fa-chevron-down"></i> <?php esc_html_e('加载更多回复', 'aksrt'); ?>
</button>
</div>
<?php endif; ?>
</section>
<?php if ($comments_enabled) : ?>
<section class="aksrt-forum-topic__reply-form">
<h2><i class="fas fa-reply"></i> <?php esc_html_e('发表评论', 'aksrt'); ?></h2>
<?php
comment_form([
'title_reply' => '',
'comment_notes_before' => '',
'comment_field' => '<div class="aksrt-forum-topic__reply-field"><textarea name="comment" rows="5" required placeholder="' . esc_attr($reply_placeholder) . '"></textarea></div>',
'submit_button' => '<button type="submit" class="aksrt-forum-topic__reply-btn"><i class="fas fa-paper-plane"></i> %s</button>',
'submit_field' => '<div class="aksrt-forum-topic__reply-actions">%1$s %2$s</div>',
]);
?>
</section>
<?php elseif ($is_locked) : ?>
<div class="aksrt-forum-topic__locked-notice">
<i class="fas fa-lock"></i>
<?php esc_html_e('当前主题已锁定,暂不接受新的回复。', 'aksrt'); ?>
</div>
<?php else : ?>
<div class="aksrt-forum-topic__login-notice">
<a href="<?php echo esc_url(wp_login_url(get_permalink())); ?>"><?php esc_html_e('登录后参与回复', 'aksrt'); ?></a>
</div>
<?php endif; ?>
</div>
</main>
<?php get_footer(); ?>