Files
wordpress-theme-aksrt/inc/classes/forum/topic-service-traits/trait-aksrt-forum-topic-service-part-4.php
T
kate522andClaude Fable 5 043ac178fe fix(polish): 订单购物车论坛粉边软化 + 论坛付费帖购链路
- 购物车/商品/论坛表面复用 #77 soft recipe(mix 边 + soft ring)
- 论坛 visibility=pay:订单 resource + 余额扣费闭环
- VIP 价/免费解锁 + 购买 CTA/AJAX,复用现有 Order/Credits

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 13:34:03 +08:00

288 lines
11 KiB
PHP

<?php
defined('ABSPATH') || exit;
trait AKSRT_Forum_Topic_Service_Part_4 {
/**
* Get review options.
*/
public function get_review_options(): array {
$options = [];
foreach ($this->get_review_map() as $value => $label) {
$options[] = ['label' => $label, 'value' => $value];
}
return $options;
}
/**
* Check whether a user can publish directly.
*/
public function can_user_publish_directly(int $user_id, int $board_id = 0): bool {
if ($user_id <= 0) {
return false;
}
if (user_can($user_id, 'manage_options')) {
return true;
}
if ($this->forum->is_forum_admin($user_id)) {
return true;
}
if ($board_id > 0 && $this->forum->is_board_moderator($user_id, $board_id)) {
return true;
}
return false;
}
// ── AJAX edit (extracted from facade) ──
public function ajax_edit_topic(): void {
check_ajax_referer('aksrt_forum_compose', '_nonce');
$user_id = get_current_user_id();
$topic_id = (int) ($_POST['topic_id'] ?? 0);
if ($user_id <= 0) {
wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
}
if (!$this->forum->can_edit_topic($user_id, $topic_id)) {
wp_send_json_error(['message' => __('无编辑权限', 'aksrt')]);
}
$title = sanitize_text_field((string) ($_POST['title'] ?? ''));
$content = wp_kses_post((string) ($_POST['content'] ?? ''));
if ($title === '' || $content === '') {
wp_send_json_error(['message' => __('标题和内容不能为空', 'aksrt')]);
}
$result = wp_update_post([
'ID' => $topic_id,
'post_title' => $title,
'post_content' => $content,
], true);
if (is_wp_error($result)) {
wp_send_json_error(['message' => $result->get_error_message()]);
}
$tags = $this->split_tags((string) ($_POST['tags'] ?? ''));
$clean_tags = array_slice(array_values(array_filter(array_map('sanitize_text_field', $tags))), 0, 5);
wp_set_object_terms($topic_id, $clean_tags, 'aksrt_forum_tag');
if (isset($_POST['special_topic'])) {
update_post_meta($topic_id, '_aksrt_special_topic', sanitize_text_field((string) $_POST['special_topic']));
}
if (isset($_POST['topic_cat']) && taxonomy_exists('aksrt_forum_topic_cat')) {
$topic_cat = sanitize_text_field((string) $_POST['topic_cat']);
wp_set_object_terms($topic_id, $topic_cat !== '' ? [$topic_cat] : [], 'aksrt_forum_topic_cat');
}
$caps = $this->forum->get_compose_capabilities($user_id);
if ($caps['can_set_visibility'] && isset($_POST['visibility'])) {
$visibility = sanitize_key((string) $_POST['visibility']);
if (isset($this->get_visibility_map()[$visibility])) {
update_post_meta($topic_id, '_aksrt_visibility', $visibility);
if ($visibility === self::VISIBILITY_CREDITS) {
update_post_meta($topic_id, '_aksrt_credits_cost', max(0, (int) ($_POST['credits_cost'] ?? 0)));
}
if ($visibility === self::VISIBILITY_PAY) {
update_post_meta($topic_id, '_aksrt_pay_price', sanitize_text_field((string) ($_POST['pay_price'] ?? '')));
}
if ($visibility === self::VISIBILITY_ROLE) {
$roles = isset($_POST['visibility_roles']) && is_array($_POST['visibility_roles'])
? array_map('sanitize_key', $_POST['visibility_roles']) : [];
update_post_meta($topic_id, '_aksrt_visibility_roles', $roles);
}
}
}
if ($caps['can_set_cover']) {
$this->save_cover_meta($topic_id, [
'cover_type' => sanitize_key((string) ($_POST['cover_type'] ?? '')),
'cover_image' => esc_url_raw((string) ($_POST['cover_image'] ?? '')),
'featured_slide' => (string) ($_POST['featured_slide'] ?? ''),
'featured_video' => esc_url_raw((string) ($_POST['featured_video'] ?? '')),
]);
}
if ($caps['can_set_vote'] && isset($_POST['vote_enabled'])) {
$vote_data = [
'vote_enabled' => !empty($_POST['vote_enabled']),
'vote_title' => sanitize_text_field((string) ($_POST['vote_title'] ?? '')),
'vote_options_text' => sanitize_textarea_field((string) ($_POST['vote_options'] ?? '')),
'vote_multiple' => !empty($_POST['vote_multiple']),
'vote_type' => sanitize_key((string) ($_POST['vote_type'] ?? 'standard')),
'vote_expiry_days' => (int) ($_POST['vote_expiry_days'] ?? 0),
];
$vote_meta = $this->prepare_vote_meta($vote_data);
$this->save_vote_meta($topic_id, $vote_meta);
}
wp_send_json_success([
'message' => __('帖子已更新', 'aksrt'),
'redirect' => get_permalink($topic_id),
]);
}
public function can_edit_topic(int $user_id, int $topic_id): bool {
if ($user_id <= 0 || $topic_id <= 0) {
return false;
}
// Moderators and above can always edit
if ($this->forum->forum_user_can($user_id, 'topic_edit_other', $topic_id)) {
return true;
}
// Authors can edit their own unlocked topics
$post = get_post($topic_id);
if (!$post || $post->post_type !== 'aksrt_forum_topic') {
return false;
}
if ((int) $post->post_author !== $user_id) {
return false;
}
return get_post_meta($topic_id, '_aksrt_locked', true) !== '1';
}
public function update_topic_meta(int $topic_id, array $meta): bool {
if ($topic_id <= 0) {
return false;
}
if (!$this->forum->can_moderate_topic(get_current_user_id(), $topic_id) && !current_user_can('manage_options')) {
return false;
}
$allowed_keys = ['_aksrt_sticky', '_aksrt_featured', '_aksrt_locked', '_aksrt_highlight'];
foreach ($meta as $key => $value) {
if (!in_array($key, $allowed_keys, true)) {
continue;
}
update_post_meta($topic_id, $key, !empty($value) ? '1' : '0');
}
return true;
}
public function ajax_update_topic(): void {
$user_id = get_current_user_id();
$topic_id = (int) ($_POST['topic_id'] ?? 0);
if ($topic_id <= 0 || !$this->forum->forum_user_can($user_id, 'topic_moderate', $topic_id)) {
wp_send_json_error(['message' => __('权限不足', 'aksrt')]);
}
$meta = [];
if (isset($_POST['sticky'])) {
$meta['_aksrt_sticky'] = !empty($_POST['sticky']);
}
if (isset($_POST['featured'])) {
$meta['_aksrt_featured'] = !empty($_POST['featured']);
}
if (isset($_POST['locked'])) {
$meta['_aksrt_locked'] = !empty($_POST['locked']);
}
if ($this->update_topic_meta($topic_id, $meta)) {
wp_send_json_success(['message' => __('已更新', 'aksrt')]);
}
wp_send_json_error(['message' => __('更新失败', 'aksrt')]);
}
public function ajax_create_topic(): void {
check_ajax_referer('aksrt_forum_compose', '_nonce');
$user_id = get_current_user_id();
if ($user_id <= 0) {
wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
}
$data = [
'board_id' => (int) ($_POST['board_id'] ?? 0),
'title' => sanitize_text_field((string) ($_POST['title'] ?? '')),
'content' => wp_kses_post((string) ($_POST['content'] ?? '')),
'tags' => $this->split_tags((string) ($_POST['tags'] ?? '')),
'special_topic' => sanitize_text_field((string) ($_POST['special_topic'] ?? '')),
'visibility' => sanitize_key((string) ($_POST['visibility'] ?? self::VISIBILITY_PUBLIC)),
'bbs_type' => sanitize_key((string) ($_POST['bbs_type'] ?? self::BBS_TYPE_STANDARD)),
'topic_cat' => sanitize_text_field((string) ($_POST['topic_cat'] ?? '')),
'vote_enabled' => !empty($_POST['vote_enabled']),
'vote_title' => sanitize_text_field((string) ($_POST['vote_title'] ?? '')),
'vote_options_text' => sanitize_textarea_field((string) ($_POST['vote_options'] ?? '')),
'vote_multiple' => !empty($_POST['vote_multiple']),
'cover_type' => sanitize_key((string) ($_POST['cover_type'] ?? '')),
'cover_image' => esc_url_raw((string) ($_POST['cover_image'] ?? '')),
'featured_slide' => (string) ($_POST['featured_slide'] ?? ''),
'featured_video' => esc_url_raw((string) ($_POST['featured_video'] ?? '')),
'credits_cost' => (int) ($_POST['credits_cost'] ?? 0),
'pay_price' => sanitize_text_field((string) ($_POST['pay_price'] ?? '')),
'visibility_roles' => isset($_POST['visibility_roles']) && is_array($_POST['visibility_roles'])
? array_map('sanitize_key', $_POST['visibility_roles']) : [],
];
$draft_id = (int) ($_POST['draft_id'] ?? 0);
if ($draft_id > 0) {
$result = $this->forum->publish_draft($user_id, $draft_id, $data);
} else {
$result = $this->create_topic($user_id, $data);
}
if (is_wp_error($result)) {
wp_send_json_error(['message' => $result->get_error_message()]);
}
wp_send_json_success([
'message' => (string) ($result['message'] ?? __('主题已提交', 'aksrt')),
'post_id' => (int) ($result['post_id'] ?? 0),
'redirect' => (string) ($result['redirect'] ?? aksrt_get_forum_home_url()),
]);
}
public function ajax_unlock_topic(): void {
check_ajax_referer('aksrt_forum_action', '_nonce');
$user_id = get_current_user_id();
if ($user_id <= 0) {
wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
}
$topic_id = (int) ($_POST['topic_id'] ?? 0);
if ($topic_id <= 0) {
wp_send_json_error(['message' => __('主题不存在', 'aksrt')]);
}
$result = $this->unlock_topic_with_credits($user_id, $topic_id);
if (!empty($result['success'])) {
wp_send_json_success($result);
} else {
wp_send_json_error(['message' => $result['message'] ?? __('解锁失败', 'aksrt')]);
}
}
public function ajax_purchase_topic(): void {
check_ajax_referer('aksrt_forum_action', '_nonce');
$user_id = get_current_user_id();
if ($user_id <= 0) {
wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
}
$topic_id = (int) ($_POST['topic_id'] ?? 0);
if ($topic_id <= 0) {
wp_send_json_error(['message' => __('主题不存在', 'aksrt')]);
}
$result = $this->purchase_topic_with_balance($user_id, $topic_id);
if (!empty($result['success'])) {
wp_send_json_success($result);
} else {
wp_send_json_error(['message' => $result['message'] ?? __('购买失败', 'aksrt')]);
}
}
}