From 2ce1b550ff87d88478eb25923a3c34673fa4771d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Jul 2026 18:01:24 +0800 Subject: [PATCH 1/2] fix(forum): accept plate CPT IDs when creating topics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compose UI and board search already send aksrt_forum_plate post IDs as board_id, but create_topic still validated aksrt_forum_board term IDs and never wrote _aksrt_plate_id — so real plates failed with 版块不存在. Validate/store under the plate model (and fix move_board the same way). --- src/AKSRT/Forum/TopicService.php | 62 ++++++++++++++++++++++++--- src/AKSRT/Forum/TopicServicePart1.php | 28 ++++++++---- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/AKSRT/Forum/TopicService.php b/src/AKSRT/Forum/TopicService.php index b4a24470..e95f186c 100644 --- a/src/AKSRT/Forum/TopicService.php +++ b/src/AKSRT/Forum/TopicService.php @@ -100,9 +100,9 @@ class TopicService { // §7.3: Strip unauthorized media from content based on compose capabilities $content = $this->sanitize_topic_content($user_id, $content); - $board = get_term($board_id, 'aksrt_forum_board'); - if (!$board || is_wp_error($board)) { - return new \WP_Error('invalid_board', __('版块不存在', 'aksrt')); + $board_ok = $this->assert_board($board_id); + if (is_wp_error($board_ok)) { + return $board_ok; } if (!isset($this->get_visibility_map()[$visibility])) { @@ -125,7 +125,7 @@ class TopicService { return $post_id; } - wp_set_object_terms($post_id, [$board_id], 'aksrt_forum_board'); + $this->attach_topic_to_board((int) $post_id, $board_id); $clean_tags = array_values(array_filter(array_map('sanitize_text_field', $tags))); if (count($clean_tags) > 5) { @@ -198,12 +198,60 @@ class TopicService { } // ================================================================ - // Topic moderation + // Board / plate attachment helpers // ================================================================ /** - * Moderate topic. + * Validate board_id as plate CPT post ID when plate is active, else taxonomy term. * - * @return array|\WP_Error + * @return true|\WP_Error */ + private function assert_board(int $board_id, string $error_message = '') { + if ($error_message === '') { + $error_message = __('版块不存在', 'aksrt'); + } + + if ($board_id <= 0) { + return new \WP_Error('invalid_board', $error_message); + } + + if ($this->forum->is_plate_cpt_active()) { + $post = get_post($board_id); + if (!$post || $post->post_type !== 'aksrt_forum_plate' || $post->post_status !== 'publish') { + return new \WP_Error('invalid_board', $error_message); + } + return true; + } + + $board = get_term($board_id, 'aksrt_forum_board'); + if (!$board || is_wp_error($board)) { + return new \WP_Error('invalid_board', $error_message); + } + + return true; + } + + /** + * Attach a topic to a board. + * Plate CPT active: store `_aksrt_plate_id` only (native association). + * Otherwise: taxonomy term on aksrt_forum_board. + */ + private function attach_topic_to_board(int $topic_id, int $board_id): void { + if ($topic_id <= 0 || $board_id <= 0) { + return; + } + + if ($this->forum->is_plate_cpt_active()) { + update_post_meta($topic_id, '_aksrt_plate_id', $board_id); + return; + } + + if (taxonomy_exists('aksrt_forum_board')) { + wp_set_object_terms($topic_id, [$board_id], 'aksrt_forum_board'); + } + } + + // ================================================================ + // Topic moderation + // ================================================================ } diff --git a/src/AKSRT/Forum/TopicServicePart1.php b/src/AKSRT/Forum/TopicServicePart1.php index 5317f68a..52f9327d 100644 --- a/src/AKSRT/Forum/TopicServicePart1.php +++ b/src/AKSRT/Forum/TopicServicePart1.php @@ -25,17 +25,29 @@ trait TopicServicePart1 { switch ($action) { case 'move_board': $target_board_id = (int) ($payload['target_board_id'] ?? 0); - $target_board = get_term($target_board_id, 'aksrt_forum_board'); - if (!$target_board || is_wp_error($target_board)) { - return new \WP_Error('invalid_board', __('目标版块不存在', 'aksrt')); + $target_ok = $this->assert_board($target_board_id, __('目标版块不存在', 'aksrt')); + if (is_wp_error($target_ok)) { + return $target_ok; } - $current_board_ids = wp_get_post_terms($topic_id, 'aksrt_forum_board', ['fields' => 'ids']); - wp_set_object_terms($topic_id, [$target_board_id], 'aksrt_forum_board'); - foreach ($current_board_ids as $current_board_id) { - $this->forum->sync_board_count((int) $current_board_id); + if ($this->forum->is_plate_cpt_active()) { + $previous_plate_id = (int) $this->forum->get_topic_plate_id($topic_id); + $this->attach_topic_to_board($topic_id, $target_board_id); + if ($previous_plate_id > 0 && $previous_plate_id !== $target_board_id) { + $this->forum->sync_board_count($previous_plate_id); + } + $this->forum->sync_board_count($target_board_id); + } else { + $current_board_ids = wp_get_post_terms($topic_id, 'aksrt_forum_board', ['fields' => 'ids']); + if (is_wp_error($current_board_ids)) { + $current_board_ids = []; + } + $this->attach_topic_to_board($topic_id, $target_board_id); + foreach ($current_board_ids as $current_board_id) { + $this->forum->sync_board_count((int) $current_board_id); + } + $this->forum->sync_board_count($target_board_id); } - $this->forum->sync_board_count($target_board_id); break; case 'visibility': From 097178c9000902b80e13dc59ef5394588774ec78 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Jul 2026 18:18:11 +0800 Subject: [PATCH 2/2] fix(admin): register REST controllers via FQCN after PSR-4 Admin::register_rest_routes used bare class strings like 'GlobalController', so class_exists() failed after the namespace move and no aksrt/v1 settings/banner/schema routes registered (SPA 404). --- src/AKSRT/Admin/Admin.php | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/AKSRT/Admin/Admin.php b/src/AKSRT/Admin/Admin.php index 0f79f858..a43c365d 100644 --- a/src/AKSRT/Admin/Admin.php +++ b/src/AKSRT/Admin/Admin.php @@ -171,21 +171,22 @@ class Admin { } public function register_rest_routes(): void { + // FQCN required after PSR-4 move into AKSRT\Admin (unqualified class_exists skips all routes). $controllers = [ - 'GlobalController', - 'PageDisplayController', - 'PostListController', - 'PermissionsController', - 'UserController', - 'PaymentController', - 'ToolsController', - 'ImportExportController', - 'ShopController', - 'ForumController', - 'ExtensionController', - 'CommentController', - 'MessageController', - 'AIController', + GlobalController::class, + PageDisplayController::class, + PostListController::class, + PermissionsController::class, + UserController::class, + PaymentController::class, + ToolsController::class, + ImportExportController::class, + ShopController::class, + ForumController::class, + ExtensionController::class, + CommentController::class, + MessageController::class, + AIController::class, ]; foreach ($controllers as $class_name) {