forum = $forum; } public function get_topic_list(array $args = []): array { $board_id = (int) ($args['board_id'] ?? 0); $limit = max(1, min(100, (int) ($args['limit'] ?? ($args['per_page'] ?? 20)))); $page = max(1, (int) ($args['page'] ?? $args['paged'] ?? 1)); $offset = array_key_exists('offset', $args) ? max(0, (int) $args['offset']) : ($page - 1) * $limit; $status = sanitize_key((string) ($args['status'] ?? 'publish')); $keyword = sanitize_text_field((string) ($args['keyword'] ?? '')); $visibility = sanitize_key((string) ($args['visibility'] ?? '')); $review_status = sanitize_key((string) ($args['review_status'] ?? '')); $author_id = (int) ($args['author_id'] ?? 0); $orderby = sanitize_key((string) ($args['orderby'] ?? 'date')); $viewer_user_id = (int) ($args['viewer_user_id'] ?? get_current_user_id()); $include_hidden = !empty($args['include_hidden']); $query_args = [ 'post_type' => 'aksrt_forum_topic', 'posts_per_page' => $limit, 'offset' => $offset, 'post_status' => $this->forum->normalize_post_status_query($status), 'order' => 'DESC', 'ignore_sticky_posts' => true, ]; if ($orderby === 'views') { $query_args['orderby'] = 'meta_value_num'; $query_args['meta_key'] = '_aksrt_views'; } elseif ($orderby === 'recommend') { $query_args['orderby'] = 'meta_value_num'; $query_args['meta_key'] = '_aksrt_recommend_score'; } elseif ($orderby === 'comment_count') { $query_args['orderby'] = 'comment_count'; } elseif ($orderby === 'score') { $query_args['orderby'] = 'meta_value_num'; $query_args['meta_key'] = '_aksrt_score'; } elseif ($orderby === 'favorites') { $query_args['orderby'] = 'meta_value_num'; $query_args['meta_key'] = '_aksrt_favorite_count'; } else { $query_args['orderby'] = 'date'; } if ($keyword !== '') { $query_args['s'] = $keyword; } if ($author_id > 0) { $query_args['author'] = $author_id; } $plate_id = (int) ($args['plate_id'] ?? 0); $plate_ids = $args['plate_ids'] ?? []; if (!empty($plate_ids) && is_array($plate_ids)) { $query_args['meta_query'][] = [ 'key' => '_aksrt_plate_id', 'value' => array_map('intval', $plate_ids), 'type' => 'NUMERIC', 'compare' => 'IN', ]; } elseif ($plate_id > 0) { $query_args['meta_query'][] = [ 'key' => '_aksrt_plate_id', 'value' => $plate_id, 'type' => 'NUMERIC', 'compare' => '=', ]; } elseif ($board_id > 0) { $query_args['tax_query'] = [[ 'taxonomy' => 'aksrt_forum_board', 'field' => 'term_id', 'terms' => $board_id, ]]; } $meta_query = []; if ($visibility !== '') { $meta_query[] = [ 'key' => '_aksrt_visibility', 'value' => $visibility, 'compare' => '=', ]; } if ($review_status !== '') { $meta_query[] = [ 'key' => '_aksrt_review_status', 'value' => $review_status, 'compare' => '=', ]; } if (!empty($meta_query)) { $query_args['meta_query'] = $meta_query; } $query = new WP_Query($query_args); $items = []; while ($query->have_posts()) { $query->the_post(); $post = get_post(get_the_ID()); if (!$post) { continue; } $topic = $this->forum->build_topic_payload($post, $viewer_user_id); if (!$include_hidden && !$topic['can_view']) { continue; } $items[] = $topic; } wp_reset_postdata(); return [ 'items' => $items, 'total' => (int) $query->found_posts, 'max_pages' => (int) $query->max_num_pages, 'page' => $page, ]; } /** * Get forum homepage view. */ public function get_home_view(int $user_id = 0): array { $boards = $this->forum->get_boards(); $stats = $this->get_stats(); $recent = $this->get_topic_list([ 'limit' => 10, 'status' => 'publish', 'viewer_user_id' => $user_id, ]); $hot = $this->get_topic_list([ 'limit' => 8, 'status' => 'publish', 'viewer_user_id' => $user_id, 'orderby' => 'views', ]); $applications = []; if ($user_id > 0) { foreach ($boards as $board) { $applications[(int) $board['id']] = $this->forum->get_board_application_for_user($user_id, (int) $board['id']); } } $config = $this->forum->get_config(); $home_tabs = $config['homepage']['tabs'] ?? [ ['type' => 'follow', 'label' => '关注'], ['type' => 'synthesis', 'label' => '综合'], ['type' => 'plate', 'label' => '版块'], ]; $active_index = (int) ($config['homepage']['tab_active_index'] ?? 1); $quick_posts = !empty($config['homepage']['quick_posts']); return [ 'boards' => $boards, 'recent_topics' => $recent['items'], 'hot_topics' => $hot['items'], 'stats' => $stats, 'permissions' => [ 'can_compose' => $user_id > 0 && $this->forum->forum_user_can($user_id, 'compose_post'), 'can_manage' => $this->forum->is_forum_admin($user_id), 'can_create_plate' => $this->forum->forum_user_can($user_id, 'plate_create'), 'user_tier' => $user_id > 0 ? $this->forum->get_user_plate_tier($user_id, 0) : AKSRT_Forum::TIER_NONE, ], 'applications' => $applications, 'home_tabs' => $home_tabs, 'active_index' => $active_index, 'quick_posts' => $quick_posts, ]; } // ── §7.10 Tab data streams ────────────────────────────────────────── /** * Get topics from plates the user follows. * * @return array{items:array,total:int,max_pages:int} */ public function get_follow_stream(int $user_id, int $page = 1, int $limit = 15): array { if ($user_id <= 0) { return ['items' => [], 'total' => 0, 'max_pages' => 1]; } $follow_ids = get_user_meta($user_id, 'aksrt_follow_plate', true); $follow_ids = is_array($follow_ids) ? array_filter(array_map('intval', $follow_ids)) : []; if (empty($follow_ids)) { return ['items' => [], 'total' => 0, 'max_pages' => 1]; } return $this->get_topic_list([ 'plate_ids' => $follow_ids, 'page' => $page, 'limit' => $limit, 'status' => 'publish', 'viewer_user_id' => $user_id, ]); } /** * Get synthesis (all topics) stream sorted by date. * * @return array{items:array,total:int,max_pages:int} */ public function get_synthesis_stream(int $page = 1, int $limit = 15, int $viewer = 0): array { return $this->get_topic_list([ 'page' => $page, 'limit' => $limit, 'status' => 'publish', 'viewer_user_id' => $viewer, ]); } /** * Get pending-review topics for moderators. * * @return array{items:array,total:int,max_pages:int} */ public function get_pending_stream(int $user_id, int $page = 1, int $limit = 15): array { if ($user_id <= 0 || !$this->forum->is_forum_admin($user_id)) { return ['items' => [], 'total' => 0, 'max_pages' => 1]; } return $this->get_topic_list([ 'page' => $page, 'limit' => $limit, 'status' => 'pending', 'viewer_user_id' => $user_id, 'include_hidden' => true, ]); } /** * AJAX: Load a forum home tab stream. */ public function ajax_home_tab(): void { check_ajax_referer('aksrt_public_nonce', 'nonce'); $tab_type = sanitize_key((string) ($_POST['tab_type'] ?? 'synthesis')); $page = max(1, (int) ($_POST['page'] ?? 1)); $user_id = get_current_user_id(); switch ($tab_type) { case 'follow': $result = $this->get_follow_stream($user_id, $page); break; case 'pending': $result = $this->get_pending_stream($user_id, $page); break; case 'plate': wp_send_json_success([ 'html' => '', 'type' => 'plate', 'boards' => $this->forum->get_boards(), 'total' => 0, 'max_pages' => 1, 'page' => 1, ]); return; default: $result = $this->get_synthesis_stream($page, 15, $user_id); } ob_start(); if (!empty($result['items'])) { foreach ($result['items'] as $topic) { $this->render_topic_row($topic); } } else { echo '

' . esc_html__('暂无内容', 'aksrt') . '

'; } $html = ob_get_clean(); wp_send_json_success([ 'html' => $html, 'type' => $tab_type, 'total' => $result['total'], 'max_pages' => $result['max_pages'], 'page' => $page, 'has_more' => $page < $result['max_pages'], ]); } /** * Render a single topic row (reusable for AJAX and initial render). */ public function render_topic_row(array $topic): void { $board = !empty($topic['boards'][0]) ? $topic['boards'][0] : null; $names = $this->forum->get_config()['names'] ?? []; ?>

'aksrt_forum_topic', 'author' => $user_id, 'post_status' => $status, 'posts_per_page' => $limit, 'paged' => $page, 'orderby' => 'date', 'order' => 'DESC', ]; $query = new \WP_Query($query_args); $items = []; foreach ($query->posts as $post) { $items[] = $this->forum->build_topic_payload($post, $user_id); } return [ 'items' => $items, 'total' => (int) $query->found_posts, 'max_pages' => (int) $query->max_num_pages, ]; } /** * Get a user's favorited forum topics. * * @return array{items:array,total:int,max_pages:int} */ public function get_user_favorite_topics(int $user_id, int $page = 1, int $limit = 10): array { $fav_ids = get_user_meta($user_id, 'aksrt_favorite_forum_posts', true); $fav_ids = is_array($fav_ids) ? array_map('intval', array_filter($fav_ids)) : []; if (empty($fav_ids)) { return ['items' => [], 'total' => 0, 'max_pages' => 1]; } $query = new \WP_Query([ 'post_type' => 'aksrt_forum_topic', 'post__in' => $fav_ids, 'post_status' => 'publish', 'posts_per_page' => $limit, 'paged' => $page, 'orderby' => 'post__in', ]); $items = []; foreach ($query->posts as $post) { $items[] = $this->forum->build_topic_payload($post, $user_id); } return [ 'items' => $items, 'total' => (int) $query->found_posts, 'max_pages' => (int) $query->max_num_pages, ]; } /** * Get a user's managed plates (plates where user is moderator/author). * * @return array{owned:array,moderating:array} */ }