导入 AKSRT 主题开发源码
This commit is contained in:
1 parent
9681dd3d48
commit
1268a55dd0
595 files changed
+127705
No files matched your search
@@ -0,0 +1,399 @@
|
||||
<?php
|
||||
/**
|
||||
* Forum board / plate service.
|
||||
*
|
||||
* Extracted from AKSRT_Forum to isolate board & plate CRUD, hierarchy,
|
||||
* view assembly, access checks, and follow handling into a cohesive unit.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class AKSRT_Forum_Board_Service {
|
||||
use AKSRT_Forum_Board_Service_Part_1;
|
||||
use AKSRT_Forum_Board_Service_Part_2;
|
||||
use AKSRT_Forum_Board_Service_Part_3;
|
||||
|
||||
|
||||
/** @var AKSRT_Forum */
|
||||
private $forum;
|
||||
|
||||
public function __construct(AKSRT_Forum $forum) {
|
||||
$this->forum = $forum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get board list (plate CPT).
|
||||
*
|
||||
* 读取 aksrt_forum_plate CPT,支持层级查询。
|
||||
* Fallback:若 plate CPT 不存在或迁移未完成,降级读取 taxonomy。
|
||||
*/
|
||||
public function get_boards(array $args = []): array {
|
||||
// 优先使用 plate CPT
|
||||
if ($this->forum->is_plate_cpt_active()) {
|
||||
return $this->get_boards_from_cpt($args);
|
||||
}
|
||||
|
||||
// Fallback: 读取旧 taxonomy(向后兼容)
|
||||
return $this->get_boards_from_taxonomy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 plate CPT 读取板块列表(新实现)。
|
||||
*/
|
||||
private function get_boards_from_cpt(array $args = []): array {
|
||||
$defaults = [
|
||||
'post_type' => 'aksrt_forum_plate',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => -1,
|
||||
'orderby' => 'menu_order',
|
||||
'order' => 'ASC',
|
||||
'hierarchical' => true,
|
||||
];
|
||||
|
||||
$query_args = wp_parse_args($args, $defaults);
|
||||
$plates = get_posts($query_args);
|
||||
|
||||
if (empty($plates)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$boards = [];
|
||||
foreach ($plates as $plate) {
|
||||
$plate_id = (int) $plate->ID;
|
||||
$moderators = $this->forum->get_plate_moderators($plate_id);
|
||||
$applications = $this->forum->get_plate_moderator_applications($plate_id);
|
||||
|
||||
$boards[] = [
|
||||
'id' => $plate_id,
|
||||
'name' => (string) $plate->post_title,
|
||||
'description' => (string) $plate->post_excerpt,
|
||||
'content' => (string) $plate->post_content,
|
||||
'icon' => (string) get_post_meta($plate_id, '_aksrt_icon', true),
|
||||
'sort_order' => (int) $plate->menu_order,
|
||||
'post_count' => (int) get_post_meta($plate_id, '_aksrt_posts_count', true),
|
||||
'reply_count' => (int) get_post_meta($plate_id, '_aksrt_reply_count', true),
|
||||
'today_reply_count' => (int) get_post_meta($plate_id, '_aksrt_today_reply_count', true),
|
||||
'views' => (int) get_post_meta($plate_id, '_aksrt_views', true),
|
||||
'follow_count' => (int) get_post_meta($plate_id, '_aksrt_follow_count', true),
|
||||
'last_reply' => (string) get_post_meta($plate_id, '_aksrt_last_reply', true),
|
||||
'last_post' => (string) get_post_meta($plate_id, '_aksrt_last_post', true),
|
||||
'moderator_count' => count($moderators),
|
||||
'pending_application_count' => count(array_filter($applications, static function ($item): bool {
|
||||
return (string) ($item['status'] ?? '') === AKSRT_Forum::APPLICATION_PENDING;
|
||||
})),
|
||||
'url' => (string) get_permalink($plate),
|
||||
'author_id' => (int) $plate->post_author,
|
||||
'parent_id' => (int) $plate->post_parent,
|
||||
'created_at' => (string) $plate->post_date,
|
||||
'thumbnail_url' => (string) get_the_post_thumbnail_url($plate, 'thumbnail'),
|
||||
];
|
||||
}
|
||||
|
||||
return $this->build_hierarchical_boards($boards);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 taxonomy 读取板块(向后兼容)。
|
||||
*/
|
||||
private function get_boards_from_taxonomy(): array {
|
||||
$terms = get_terms([
|
||||
'taxonomy' => 'aksrt_forum_board',
|
||||
'hide_empty' => false,
|
||||
'orderby' => 'meta_value_num',
|
||||
'meta_key' => '_aksrt_sort_order',
|
||||
'order' => 'ASC',
|
||||
]);
|
||||
|
||||
if (is_wp_error($terms) || empty($terms)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$boards = [];
|
||||
foreach ($terms as $term) {
|
||||
$board_id = (int) $term->term_id;
|
||||
$moderators = $this->forum->get_board_moderators($board_id);
|
||||
$applications = $this->forum->get_board_moderator_applications($board_id);
|
||||
$board_link = get_term_link($term);
|
||||
|
||||
$boards[] = [
|
||||
'id' => $board_id,
|
||||
'name' => (string) $term->name,
|
||||
'description' => (string) $term->description,
|
||||
'content' => '',
|
||||
'icon' => (string) get_term_meta($board_id, '_aksrt_icon', true),
|
||||
'sort_order' => (int) get_term_meta($board_id, '_aksrt_sort_order', true),
|
||||
'post_count' => (int) $term->count,
|
||||
'reply_count' => 0,
|
||||
'today_reply_count' => 0,
|
||||
'views' => 0,
|
||||
'follow_count' => 0,
|
||||
'last_reply' => '',
|
||||
'last_post' => '',
|
||||
'moderator_count' => count($moderators),
|
||||
'pending_application_count' => count(array_filter($applications, static function ($item): bool {
|
||||
return (string) ($item['status'] ?? '') === AKSRT_Forum::APPLICATION_PENDING;
|
||||
})),
|
||||
'url' => !is_wp_error($board_link) ? (string) $board_link : '',
|
||||
'author_id' => 0,
|
||||
'parent_id' => (int) $term->parent,
|
||||
'created_at' => '',
|
||||
'thumbnail_url' => '',
|
||||
];
|
||||
}
|
||||
|
||||
return $boards;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建层级板块树(子板块嵌套)。
|
||||
*/
|
||||
private function build_hierarchical_boards(array $boards): array {
|
||||
$by_id = [];
|
||||
foreach ($boards as $board) {
|
||||
$by_id[$board['id']] = $board;
|
||||
$by_id[$board['id']]['children'] = [];
|
||||
}
|
||||
|
||||
$roots = [];
|
||||
foreach ($boards as $board) {
|
||||
if ($board['parent_id'] > 0 && isset($by_id[$board['parent_id']])) {
|
||||
$by_id[$board['parent_id']]['children'][] = &$by_id[$board['id']];
|
||||
} else {
|
||||
$roots[] = &$by_id[$board['id']];
|
||||
}
|
||||
}
|
||||
|
||||
return $roots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create board (统一入口,自动选择 CPT/taxonomy).
|
||||
*/
|
||||
public function create_board(array $data): int {
|
||||
if ($this->forum->is_plate_cpt_active()) {
|
||||
return $this->create_plate($data);
|
||||
}
|
||||
|
||||
// Fallback: taxonomy
|
||||
$name = sanitize_text_field((string) ($data['name'] ?? ''));
|
||||
if ($name === '') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$result = wp_insert_term($name, 'aksrt_forum_board', [
|
||||
'description' => sanitize_textarea_field((string) ($data['description'] ?? '')),
|
||||
]);
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$term_id = (int) $result['term_id'];
|
||||
$icon = sanitize_text_field((string) ($data['icon'] ?? ''));
|
||||
$sort_order = (int) ($data['sort_order'] ?? $term_id);
|
||||
|
||||
if ($icon !== '') {
|
||||
update_term_meta($term_id, '_aksrt_icon', $icon);
|
||||
}
|
||||
|
||||
update_term_meta($term_id, '_aksrt_sort_order', $sort_order);
|
||||
|
||||
return $term_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update board (统一入口,自动选择 CPT/taxonomy).
|
||||
*/
|
||||
public function update_board(int $board_id, array $data): bool {
|
||||
if ($this->forum->is_plate_cpt_active()) {
|
||||
return $this->update_plate($board_id, $data);
|
||||
}
|
||||
|
||||
// Fallback: taxonomy
|
||||
$term = get_term($board_id, 'aksrt_forum_board');
|
||||
if (!$term || is_wp_error($term)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$update = ['taxonomy' => 'aksrt_forum_board'];
|
||||
|
||||
if (isset($data['name'])) {
|
||||
$name = sanitize_text_field((string) $data['name']);
|
||||
if ($name !== '') {
|
||||
$update['name'] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['description'])) {
|
||||
$update['description'] = sanitize_textarea_field((string) $data['description']);
|
||||
}
|
||||
|
||||
$result = wp_update_term($board_id, 'aksrt_forum_board', $update);
|
||||
if (is_wp_error($result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($data['icon'])) {
|
||||
update_term_meta($board_id, '_aksrt_icon', sanitize_text_field((string) $data['icon']));
|
||||
}
|
||||
|
||||
if (isset($data['sort_order'])) {
|
||||
update_term_meta($board_id, '_aksrt_sort_order', (int) $data['sort_order']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete board (统一入口,自动选择 CPT/taxonomy).
|
||||
*/
|
||||
public function delete_board(int $board_id): bool {
|
||||
if ($this->forum->is_plate_cpt_active()) {
|
||||
return $this->delete_plate($board_id);
|
||||
}
|
||||
|
||||
// Fallback: taxonomy
|
||||
$term = get_term($board_id, 'aksrt_forum_board');
|
||||
if (!$term || is_wp_error($term)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = wp_delete_term($board_id, 'aksrt_forum_board');
|
||||
return !is_wp_error($result) && !empty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder boards (统一入口).
|
||||
*/
|
||||
public function reorder_boards(array $order_map): bool {
|
||||
if ($this->forum->is_plate_cpt_active()) {
|
||||
return $this->reorder_plates($order_map);
|
||||
}
|
||||
|
||||
foreach ($order_map as $term_id => $sort_order) {
|
||||
$term_id = (int) $term_id;
|
||||
if ($term_id <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
update_term_meta($term_id, '_aksrt_sort_order', (int) $sort_order);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// §7.0 Plate CPT methods —板块 CPT 化 CRUD
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Get all plates (板块 CPT posts).
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function get_plates(array $args = []): array {
|
||||
$query_args = [
|
||||
'post_type' => 'aksrt_forum_plate',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => (int) ($args['limit'] ?? 100),
|
||||
'orderby' => 'menu_order',
|
||||
'order' => 'ASC',
|
||||
];
|
||||
|
||||
if (!empty($args['parent'])) {
|
||||
$query_args['post_parent'] = (int) $args['parent'];
|
||||
}
|
||||
|
||||
if (!empty($args['plate_cat'])) {
|
||||
$query_args['tax_query'] = [[
|
||||
'taxonomy' => 'aksrt_plate_cat',
|
||||
'field' => 'term_id',
|
||||
'terms' => (int) $args['plate_cat'],
|
||||
]];
|
||||
}
|
||||
|
||||
$posts = get_posts($query_args);
|
||||
$plates = [];
|
||||
|
||||
foreach ($posts as $post) {
|
||||
$plates[] = $this->build_plate_payload($post);
|
||||
}
|
||||
|
||||
return $plates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single plate by ID.
|
||||
*/
|
||||
public function get_plate(int $plate_id): ?array {
|
||||
$post = get_post($plate_id);
|
||||
if (!$post || $post->post_type !== 'aksrt_forum_plate') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->build_plate_payload($post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build plate data payload from WP_Post.
|
||||
*/
|
||||
public function build_plate_payload(\WP_Post $post): array {
|
||||
$plate_id = (int) $post->ID;
|
||||
$moderators = get_post_meta($plate_id, '_aksrt_moderators', true);
|
||||
if (!is_array($moderators)) {
|
||||
$moderators = [];
|
||||
}
|
||||
|
||||
$cover_url = (string) get_the_post_thumbnail_url($plate_id, 'medium');
|
||||
if ($cover_url === '') {
|
||||
$config = $this->forum->get_config();
|
||||
$default_thumbs = $config['other']['bbs_term_thumb'] ?? [];
|
||||
if (!empty($default_thumbs) && is_array($default_thumbs)) {
|
||||
$cover_url = $default_thumbs[array_rand($default_thumbs)];
|
||||
}
|
||||
}
|
||||
|
||||
$plate_cats = wp_get_object_terms($plate_id, 'aksrt_plate_cat', ['fields' => 'all']);
|
||||
$plate_cat = (!is_wp_error($plate_cats) && !empty($plate_cats)) ? [
|
||||
'id' => (int) $plate_cats[0]->term_id,
|
||||
'name' => (string) $plate_cats[0]->name,
|
||||
'slug' => (string) $plate_cats[0]->slug,
|
||||
] : null;
|
||||
|
||||
return [
|
||||
'id' => $plate_id,
|
||||
'name' => (string) $post->post_title,
|
||||
'description' => (string) $post->post_excerpt,
|
||||
'content' => (string) $post->post_content,
|
||||
'icon' => (string) get_post_meta($plate_id, '_aksrt_icon', true),
|
||||
'cover_url' => $cover_url,
|
||||
'sort_order' => (int) $post->menu_order,
|
||||
'parent_id' => (int) $post->post_parent,
|
||||
'author_id' => (int) $post->post_author,
|
||||
'post_count' => (int) get_post_meta($plate_id, '_aksrt_posts_count', true),
|
||||
'reply_count' => (int) get_post_meta($plate_id, '_aksrt_reply_count', true),
|
||||
'today_reply_count' => (int) get_post_meta($plate_id, '_aksrt_today_reply_count', true),
|
||||
'views' => (int) get_post_meta($plate_id, '_aksrt_views', true),
|
||||
'follow_count' => (int) get_post_meta($plate_id, '_aksrt_follow_count', true),
|
||||
'last_reply' => (string) get_post_meta($plate_id, '_aksrt_last_reply', true),
|
||||
'last_post' => (string) get_post_meta($plate_id, '_aksrt_last_post', true),
|
||||
'moderator_count' => count($moderators),
|
||||
'moderators' => $moderators,
|
||||
'url' => (string) get_permalink($plate_id),
|
||||
'created_at' => (string) $post->post_date,
|
||||
'allow_view' => (string) (get_post_meta($plate_id, '_aksrt_allow_view', true) ?: 'public'),
|
||||
'add_limit' => (string) (get_post_meta($plate_id, '_aksrt_add_limit', true) ?: 'all'),
|
||||
'is_hot' => $this->forum->is_hot_plate($plate_id),
|
||||
'plate_cat' => $plate_cat,
|
||||
// Alias fields for backward compat with get_board_view consumer
|
||||
'topic_count' => (int) get_post_meta($plate_id, '_aksrt_posts_count', true),
|
||||
'thumbnail_url' => $cover_url,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create plate (CPT post).
|
||||
*/
|
||||
}
|
||||
Reference in new issue
Block a user