Files
wordpress-theme-aksrt/inc/classes/forum/board-service-traits/trait-aksrt-forum-board-service-part-1.php
T

420 lines
15 KiB
PHP

<?php
defined('ABSPATH') || exit;
trait AKSRT_Forum_Board_Service_Part_1 {
public function create_plate(array $data): int {
$title = sanitize_text_field((string) ($data['name'] ?? ''));
if ($title === '') {
return 0;
}
$plate_id = wp_insert_post([
'post_type' => 'aksrt_forum_plate',
'post_title' => $title,
'post_content' => wp_kses_post((string) ($data['content'] ?? '')),
'post_excerpt' => sanitize_textarea_field((string) ($data['description'] ?? '')),
'post_status' => 'publish',
'post_parent' => (int) ($data['parent_id'] ?? 0),
'post_author' => (int) ($data['author_id'] ?? get_current_user_id()),
'menu_order' => (int) ($data['sort_order'] ?? 0),
], true);
if (is_wp_error($plate_id)) {
return 0;
}
$icon = sanitize_text_field((string) ($data['icon'] ?? ''));
if ($icon !== '') {
update_post_meta($plate_id, '_aksrt_icon', $icon);
}
update_post_meta($plate_id, '_aksrt_sort_order', (int) ($data['sort_order'] ?? 0));
update_post_meta($plate_id, '_aksrt_posts_count', 0);
update_post_meta($plate_id, '_aksrt_reply_count', 0);
update_post_meta($plate_id, '_aksrt_follow_count', 0);
update_post_meta($plate_id, '_aksrt_plate_views', 0);
if (!empty($data['plate_cat'])) {
wp_set_object_terms($plate_id, [(int) $data['plate_cat']], 'aksrt_plate_cat');
}
// Also create a corresponding taxonomy term for backward compat
$term_result = wp_insert_term($title, 'aksrt_forum_board', [
'description' => sanitize_textarea_field((string) ($data['description'] ?? '')),
]);
if (!is_wp_error($term_result)) {
$term_id = (int) $term_result['term_id'];
update_term_meta($term_id, '_aksrt_sort_order', (int) ($data['sort_order'] ?? 0));
if ($icon !== '') {
update_term_meta($term_id, '_aksrt_icon', $icon);
}
update_post_meta($plate_id, '_aksrt_migrated_from_term', $term_id);
}
return $plate_id;
}
/**
* Update plate.
*/
public function update_plate(int $plate_id, array $data): bool {
$post = get_post($plate_id);
if (!$post || $post->post_type !== 'aksrt_forum_plate') {
return false;
}
$update = ['ID' => $plate_id];
if (isset($data['name'])) {
$name = sanitize_text_field((string) $data['name']);
if ($name !== '') {
$update['post_title'] = $name;
}
}
if (isset($data['description'])) {
$update['post_excerpt'] = sanitize_textarea_field((string) $data['description']);
}
if (isset($data['content'])) {
$update['post_content'] = wp_kses_post((string) $data['content']);
}
if (isset($data['parent_id'])) {
$update['post_parent'] = (int) $data['parent_id'];
}
if (isset($data['sort_order'])) {
$update['menu_order'] = (int) $data['sort_order'];
update_post_meta($plate_id, '_aksrt_sort_order', (int) $data['sort_order']);
}
if (isset($data['author_id'])) {
$update['post_author'] = (int) $data['author_id'];
}
$result = wp_update_post($update, true);
if (is_wp_error($result)) {
return false;
}
if (isset($data['icon'])) {
update_post_meta($plate_id, '_aksrt_icon', sanitize_text_field((string) $data['icon']));
}
if (isset($data['allow_view'])) {
$allowed_views = ['public', 'login', 'role', 'follow'];
$view = in_array($data['allow_view'], $allowed_views, true) ? $data['allow_view'] : 'public';
update_post_meta($plate_id, '_aksrt_allow_view', $view);
}
// Sync to legacy taxonomy term if exists
$term_id = (int) get_post_meta($plate_id, '_aksrt_migrated_from_term', true);
if ($term_id > 0) {
$term_update = [];
if (isset($update['post_title'])) {
$term_update['name'] = $update['post_title'];
}
if (isset($update['post_excerpt'])) {
$term_update['description'] = $update['post_excerpt'];
}
if (!empty($term_update)) {
wp_update_term($term_id, 'aksrt_forum_board', $term_update);
}
if (isset($data['icon'])) {
update_term_meta($term_id, '_aksrt_icon', sanitize_text_field((string) $data['icon']));
}
if (isset($data['sort_order'])) {
update_term_meta($term_id, '_aksrt_sort_order', (int) $data['sort_order']);
}
}
return true;
}
/**
* Delete plate (with cascade option).
*/
public function delete_plate(int $plate_id, string $cascade = 'trash', int $move_to = 0): bool {
$post = get_post($plate_id);
if (!$post || $post->post_type !== 'aksrt_forum_plate') {
return false;
}
$topic_ids = get_posts([
'post_type' => 'aksrt_forum_topic',
'meta_key' => '_aksrt_plate_id',
'meta_value' => $plate_id,
'posts_per_page' => -1,
'fields' => 'ids',
'post_status' => 'any',
]);
if (!empty($topic_ids)) {
if ($cascade === 'move' && $move_to > 0 && $move_to !== $plate_id) {
$target = get_post($move_to);
if ($target && $target->post_type === 'aksrt_forum_plate') {
foreach ($topic_ids as $tid) {
update_post_meta((int) $tid, '_aksrt_plate_id', $move_to);
}
$this->forum->sync_plate_counts($move_to);
}
} else {
foreach ($topic_ids as $tid) {
wp_trash_post((int) $tid);
}
}
}
// Handle child plates (move to top-level)
$children = get_posts([
'post_type' => 'aksrt_forum_plate',
'post_parent' => $plate_id,
'posts_per_page' => -1,
'fields' => 'ids',
'post_status' => 'any',
]);
foreach ($children as $child_id) {
wp_update_post(['ID' => (int) $child_id, 'post_parent' => 0]);
}
// Remove legacy taxonomy term if linked
$term_id = (int) get_post_meta($plate_id, '_aksrt_migrated_from_term', true);
if ($term_id > 0) {
wp_delete_term($term_id, 'aksrt_forum_board');
}
wp_delete_post($plate_id, true);
return true;
}
/**
* Reorder plates.
*/
public function reorder_plates(array $order_map): bool {
foreach ($order_map as $plate_id => $sort_order) {
$plate_id = (int) $plate_id;
if ($plate_id <= 0) continue;
wp_update_post(['ID' => $plate_id, 'menu_order' => (int) $sort_order]);
update_post_meta($plate_id, '_aksrt_sort_order', (int) $sort_order);
}
return true;
}
/**
* Resolve plate_id for a topic (reads _aksrt_plate_id meta, falls back to taxonomy).
*/
public function get_topic_plate_id(int $topic_id): int {
$plate_id = (int) get_post_meta($topic_id, '_aksrt_plate_id', true);
if ($plate_id > 0) {
return $plate_id;
}
// Fallback: find plate via legacy taxonomy term
$terms = get_the_terms($topic_id, 'aksrt_forum_board');
if (!$terms || is_wp_error($terms)) {
return 0;
}
$term = $terms[0];
// Look up plate post by migrated_from_term meta
$plates = get_posts([
'post_type' => 'aksrt_forum_plate',
'meta_key' => '_aksrt_migrated_from_term',
'meta_value' => (string) $term->term_id,
'numberposts' => 1,
'fields' => 'ids',
'post_status' => 'publish',
]);
if (!empty($plates)) {
$resolved = (int) $plates[0];
update_post_meta($topic_id, '_aksrt_plate_id', $resolved);
return $resolved;
}
return 0;
}
/**
* Check if a user is a plate moderator (CPT-based).
*/
public function is_plate_moderator(int $user_id, int $plate_id): bool {
if ($user_id <= 0 || $plate_id <= 0) {
return false;
}
if ($this->forum->is_forum_admin($user_id)) {
return true;
}
$post = get_post($plate_id);
if ($post && (int) $post->post_author === $user_id) {
return true;
}
$moderators = get_post_meta($plate_id, '_aksrt_moderators', true);
if (is_array($moderators) && in_array($user_id, $moderators, true)) {
return true;
}
return false;
}
/**
* Get plate view (topics + moderators + pagination) for frontend.
*/
public function get_plate_view(int $plate_id, array $args = []): array {
$plate = $this->get_plate($plate_id);
if (!$plate) {
return [
'plate' => null,
'topics' => [],
'sticky_topics' => [],
'moderators' => [],
'pagination' => ['page' => 1, 'max_pages' => 1, 'total' => 0],
'permissions' => [],
'children' => [],
];
}
$user_id = (int) ($args['user_id'] ?? get_current_user_id());
$paged = max(1, (int) ($args['paged'] ?? 1));
$topics = $this->forum->get_topic_list([
'plate_id' => $plate_id,
'page' => $paged,
'limit' => 20,
]);
// Global + super + plate sticky
$sticky_topics = $this->get_sticky_topics_for_plate($plate_id);
$children = get_posts([
'post_type' => 'aksrt_forum_plate',
'post_parent' => $plate_id,
'post_status' => 'publish',
'posts_per_page' => 50,
'orderby' => 'menu_order',
'order' => 'ASC',
]);
$child_plates = [];
foreach ($children as $child) {
$child_plates[] = $this->build_plate_payload($child);
}
return [
'plate' => $plate,
'topics' => $topics['items'],
'sticky_topics' => $sticky_topics,
'moderators' => $this->get_plate_moderator_profiles($plate_id),
'pagination' => [
'page' => $topics['page'],
'max_pages' => $topics['max_pages'],
'total' => $topics['total'],
],
'permissions' => [
'can_compose' => $user_id > 0 && $this->can_compose_in_plate($user_id, $plate_id),
'can_apply_moderator' => $user_id > 0 && $this->forum->forum_user_can($user_id, 'moderator_apply'),
'can_moderate' => $this->forum->forum_user_can($user_id, 'topic_moderate', $plate_id),
'can_manage_plate' => $this->forum->forum_user_can($user_id, 'plate_manage', $plate_id),
'can_manage_mods' => $this->forum->forum_user_can($user_id, 'moderator_manage', $plate_id),
'user_tier' => $this->forum->get_user_plate_tier($user_id, $plate_id),
],
'children' => $child_plates,
];
}
/**
* Get sticky topics for a plate (global + super + plate-level).
*/
private function get_sticky_topics_for_plate(int $plate_id): array {
$global_sticky = get_posts([
'post_type' => 'aksrt_forum_topic',
'post_status' => 'publish',
'meta_key' => '_aksrt_sticky',
'meta_value' => AKSRT_Forum::STICKY_GLOBAL,
'posts_per_page' => 5,
'orderby' => 'date',
'order' => 'DESC',
]);
$plate_sticky = get_posts([
'post_type' => 'aksrt_forum_topic',
'post_status' => 'publish',
'posts_per_page' => 10,
'orderby' => 'date',
'order' => 'DESC',
'meta_query' => [
'relation' => 'AND',
['key' => '_aksrt_plate_id', 'value' => $plate_id, 'type' => 'NUMERIC'],
['key' => '_aksrt_sticky', 'value' => 0, 'compare' => '>', 'type' => 'NUMERIC'],
['key' => '_aksrt_sticky', 'value' => AKSRT_Forum::STICKY_GLOBAL, 'compare' => '<', 'type' => 'NUMERIC'],
],
]);
$items = [];
$seen = [];
foreach (array_merge($global_sticky, $plate_sticky) as $post) {
if (isset($seen[$post->ID])) continue;
$seen[$post->ID] = true;
$items[] = $this->forum->build_topic_payload($post);
}
return array_slice($items, 0, 10);
}
/**
* Get moderator user profiles for a plate.
*/
private function get_plate_moderator_profiles(int $plate_id): array {
$post = get_post($plate_id);
$profiles = [];
// Author = super moderator
if ($post && $post->post_author > 0) {
$user = get_userdata((int) $post->post_author);
if ($user) {
$profiles[] = [
'id' => (int) $user->ID,
'name' => $user->display_name,
'avatar' => function_exists('aksrt_get_avatar_url') ? aksrt_get_avatar_url($user->ID, 40) : get_avatar_url($user->ID, ['size' => 40]),
'role' => 'plate_author',
];
}
}
$moderators = get_post_meta($plate_id, '_aksrt_moderators', true);
if (!is_array($moderators)) {
return $profiles;
}
$roles = get_post_meta($plate_id, '_aksrt_moderator_roles', true);
if (!is_array($roles)) {
$roles = [];
}
foreach ($moderators as $uid) {
$uid = (int) $uid;
if ($post && $uid === (int) $post->post_author) continue;
$user = get_userdata($uid);
if (!$user) continue;
$profiles[] = [
'id' => $uid,
'name' => $user->display_name,
'avatar' => function_exists('aksrt_get_avatar_url') ? aksrt_get_avatar_url($uid, 40) : get_avatar_url($uid, ['size' => 40]),
'role' => (string) ($roles[$uid] ?? 'moderator'),
];
}
return $profiles;
}
}