- 购物车/商品/论坛表面复用 #77 soft recipe(mix 边 + soft ring) - 论坛 visibility=pay:订单 resource + 余额扣费闭环 - VIP 价/免费解锁 + 购买 CTA/AJAX,复用现有 Order/Credits Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
288 lines
11 KiB
PHP
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')]);
|
|
}
|
|
}
|
|
}
|