admin = $admin; } public function register_routes(): void { // Banners (generic CRUD — hero, banner kinds) register_rest_route(self::API_NAMESPACE, '/banners', [ 'methods' => 'GET', 'callback' => [$this, 'rest_get_banners'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/banners', [ 'methods' => 'POST', 'callback' => [$this, 'rest_create_banner'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/banners/(?P[\w-]+)', [ 'methods' => ['PUT', 'DELETE'], 'callback' => [$this, 'rest_handle_banner_item'], 'permission_callback' => [$this, 'check_permission'], ]); } private function normalize_banner_kind($kind): string { return in_array($kind, ['hero', 'banner'], true) ? $kind : 'hero'; } private function get_banner_kind_query(string $kind): array { if ('banner' === $kind) { return [ [ 'key' => '_aksrt_kind', 'value' => 'banner', ], ]; } return [ 'relation' => 'OR', [ 'key' => '_aksrt_kind', 'value' => 'hero', ], [ 'key' => '_aksrt_kind', 'compare' => 'NOT EXISTS', ], ]; } public function rest_get_banners(WP_REST_Request $request): WP_REST_Response { $kind = $this->normalize_banner_kind($request->get_param('kind') ?: 'hero'); $args = [ 'post_type' => 'aksrt_banner', 'posts_per_page' => 100, 'post_status' => 'any', 'orderby' => 'menu_order', 'order' => 'ASC', 'meta_query' => $this->get_banner_kind_query($kind), ]; $posts = get_posts($args); $banners = array_map(function ($post) { $layers_json = get_post_meta($post->ID, '_layers', true); return [ 'id' => $post->ID, 'title' => $post->post_title, 'subtitle' => get_post_meta($post->ID, '_subtitle', true), 'description' => get_post_meta($post->ID, '_description', true), 'image_url' => get_post_meta($post->ID, '_image_url', true), 'video_url' => get_post_meta($post->ID, '_video_url', true), 'link_url' => get_post_meta($post->ID, '_link_url', true), 'link_target' => get_post_meta($post->ID, '_link_target', true) ?: '_self', 'text_align' => get_post_meta($post->ID, '_text_align', true) ?: 'left', 'device_visibility' => get_post_meta($post->ID, '_device_visibility', true) ?: 'all', 'enabled' => get_post_meta($post->ID, '_enabled', true) === '1', 'show_text' => get_post_meta($post->ID, '_show_text', true) !== '0', 'show_meta' => get_post_meta($post->ID, '_show_meta', true) === '1', 'kind' => get_post_meta($post->ID, '_aksrt_kind', true) ?: 'hero', 'sort_order' => $post->menu_order, 'text_size_pc' => get_post_meta($post->ID, '_text_size_pc', true) ?: '', 'text_size_m' => get_post_meta($post->ID, '_text_size_m', true) ?: '', 'text_parallax' => get_post_meta($post->ID, '_text_parallax', true) === '1', 'layers' => is_string($layers_json) && $layers_json !== '' ? json_decode($layers_json, true) : [], ]; }, $posts); return rest_ensure_response(['code' => 'success', 'data' => $banners]); } public function rest_create_banner(WP_REST_Request $request): WP_REST_Response { $params = $this->get_json_params($request); $kind = $this->normalize_banner_kind($params['kind'] ?? 'hero'); $title = sanitize_text_field($params['title'] ?? ''); $post_id = wp_insert_post([ 'post_title' => '' !== $title ? $title : ('banner' === $kind ? 'Banner Slide' : 'Hero Slide'), 'post_type' => 'aksrt_banner', 'post_status' => 'publish', 'menu_order' => (int) ($params['sort_order'] ?? 0), ]); if (is_wp_error($post_id)) { return new WP_REST_Response(['code' => 'error', 'message' => $post_id->get_error_message()], 400); } update_post_meta($post_id, '_image_url', esc_url_raw($params['image_url'] ?? '')); update_post_meta($post_id, '_link_url', esc_url_raw($params['link_url'] ?? '')); update_post_meta($post_id, '_link_target', in_array($params['link_target'] ?? '', ['_self', '_blank'], true) ? $params['link_target'] : '_self'); update_post_meta($post_id, '_subtitle', sanitize_text_field($params['subtitle'] ?? '')); update_post_meta($post_id, '_description', sanitize_textarea_field($params['description'] ?? '')); update_post_meta($post_id, '_video_url', esc_url_raw($params['video_url'] ?? '')); update_post_meta($post_id, '_text_align', in_array($params['text_align'] ?? '', ['left', 'center', 'right'], true) ? $params['text_align'] : 'left'); update_post_meta($post_id, '_device_visibility', in_array($params['device_visibility'] ?? '', ['all', 'pc', 'mobile'], true) ? $params['device_visibility'] : 'all'); update_post_meta($post_id, '_enabled', !array_key_exists('enabled', $params) || !empty($params['enabled']) ? '1' : '0'); update_post_meta($post_id, '_show_text', !array_key_exists('show_text', $params) || !empty($params['show_text']) ? '1' : '0'); update_post_meta($post_id, '_show_meta', !empty($params['show_meta']) ? '1' : '0'); update_post_meta($post_id, '_aksrt_kind', $kind); update_post_meta($post_id, '_text_size_pc', sanitize_text_field($params['text_size_pc'] ?? '')); update_post_meta($post_id, '_text_size_m', sanitize_text_field($params['text_size_m'] ?? '')); update_post_meta($post_id, '_text_parallax', !empty($params['text_parallax']) ? '1' : '0'); if (isset($params['layers']) && is_array($params['layers'])) { update_post_meta($post_id, '_layers', wp_json_encode($params['layers'])); } return rest_ensure_response(['code' => 'success', 'data' => ['id' => $post_id], 'message' => __('幻灯片已创建', 'aksrt')]); } public function rest_handle_banner_item(WP_REST_Request $request): WP_REST_Response { $id = absint($request['id']); if (!$id || get_post_type($id) !== 'aksrt_banner') { return new WP_REST_Response(['code' => 'not_found', 'message' => __('幻灯片不存在', 'aksrt')], 404); } if ($request->get_method() === 'DELETE') { wp_delete_post($id, true); return rest_ensure_response(['code' => 'success', 'message' => __('幻灯片已删除', 'aksrt')]); } $params = $this->get_json_params($request); $kind = $this->normalize_banner_kind($params['kind'] ?? get_post_meta($id, '_aksrt_kind', true) ?: 'hero'); $title = sanitize_text_field($params['title'] ?? ''); if ($title === '') { $existing = get_the_title($id); $title = is_string($existing) && $existing !== '' ? $existing : ('banner' === $kind ? 'Banner Slide' : 'Hero Slide'); } wp_update_post([ 'ID' => $id, 'post_title' => $title, ]); update_post_meta($id, '_aksrt_kind', $kind); update_post_meta($id, '_subtitle', sanitize_text_field($params['subtitle'] ?? '')); update_post_meta($id, '_description', sanitize_textarea_field($params['description'] ?? '')); update_post_meta($id, '_image_url', esc_url_raw($params['image_url'] ?? '')); update_post_meta($id, '_video_url', esc_url_raw($params['video_url'] ?? '')); update_post_meta($id, '_link_url', esc_url_raw($params['link_url'] ?? '')); update_post_meta($id, '_link_target', in_array($params['link_target'] ?? '', ['_blank', '_self'], true) ? $params['link_target'] : '_self'); update_post_meta($id, '_text_align', in_array($params['text_align'] ?? '', ['left', 'center', 'right'], true) ? $params['text_align'] : 'left'); update_post_meta($id, '_device_visibility', in_array($params['device_visibility'] ?? '', ['all', 'pc', 'mobile'], true) ? $params['device_visibility'] : 'all'); update_post_meta($id, '_enabled', !empty($params['enabled']) ? '1' : '0'); update_post_meta($id, '_show_text', !isset($params['show_text']) || !empty($params['show_text']) ? '1' : '0'); update_post_meta($id, '_show_meta', !empty($params['show_meta']) ? '1' : '0'); update_post_meta($id, '_text_size_pc', sanitize_text_field($params['text_size_pc'] ?? '')); update_post_meta($id, '_text_size_m', sanitize_text_field($params['text_size_m'] ?? '')); update_post_meta($id, '_text_parallax', !empty($params['text_parallax']) ? '1' : '0'); if (isset($params['layers']) && is_array($params['layers'])) { update_post_meta($id, '_layers', wp_json_encode(array_values($params['layers']))); } else { delete_post_meta($id, '_layers'); } if (isset($params['sort_order'])) { wp_update_post([ 'ID' => $id, 'menu_order' => (int) $params['sort_order'], ]); } return rest_ensure_response(['code' => 'success', 'message' => __('幻灯片已更新', 'aksrt')]); } }