Files
wordpress-theme-aksrt/templates/forum/forum-edit.php
T
kate522 aaf458af1c refactor(autoload): migrate theme classes to Composer PSR-4
Move 288 types from global AKSRT_* + inc/classes manual requires into
namespace AKSRT\{Domain} under src/AKSRT/, wire composer.json psr-4,
and slim bootstrap to helpers/modules/hooks only. Split multi-class
widget/gateway files, update admin contract audit paths, and document
the layout in ADR/README.
2026-07-17 13:29:22 +08:00

363 lines
22 KiB
PHP

<?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\Forum') ? \AKSRT\Forum\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\Settings') ? \AKSRT\Settings\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(); ?>