Files
wordpress-theme-aksrt/inc/classes/admin/class-aksrt-admin-controller-base.php
T

174 lines
6.1 KiB
PHP

<?php
/**
* AKSRT Admin Controller Base
*
* 所有后台业务域控制器的基类。
* 提供通用的权限检查、响应格式化、设置读写等基础设施。
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
abstract class AKSRT_Admin_Controller_Base {
/**
* REST API namespace (shared with AKSRT_Admin).
*/
const API_NAMESPACE = 'aksrt/v1';
/**
* Register REST routes for this domain.
* Subclasses must implement this method.
*/
abstract public function register_routes(): void;
/**
* Permission callback — requires manage_options capability.
*/
public function check_permission(): bool {
return current_user_can('manage_options');
}
/**
* Create a standard success response.
*/
protected function success($data = [], int $status = 200): WP_REST_Response {
return new WP_REST_Response(array_merge(['success' => true], $data), $status);
}
/**
* Create a standard error response.
*/
protected function error(string $message, int $status = 400): WP_REST_Response {
return new WP_REST_Response([
'success' => false,
'message' => $message,
], $status);
}
/**
* Read JSON request body safely.
*/
protected function get_json_params(WP_REST_Request $request): array {
$params = $request->get_json_params();
return is_array($params) ? $params : [];
}
/**
* Sanitize a settings array using a whitelist of allowed keys.
*
* @param array $input Raw input data.
* @param array $allowed Allowed keys with their types (string|int|bool|float|array).
* @return array Sanitized data.
*/
protected function sanitize_fields(array $input, array $allowed): array {
$out = [];
foreach ($allowed as $key => $type) {
if (!array_key_exists($key, $input)) continue;
$val = $input[$key];
switch ($type) {
case 'string':
$out[$key] = sanitize_text_field($val);
break;
case 'html':
$out[$key] = wp_kses_post($val);
break;
case 'code':
$out[$key] = is_string($val) ? wp_unslash($val) : '';
break;
case 'url':
$out[$key] = esc_url_raw($val);
break;
case 'int':
$out[$key] = (int) $val;
break;
case 'bool':
$out[$key] = !empty($val);
break;
case 'float':
$out[$key] = (float) $val;
break;
case 'array':
$out[$key] = is_array($val) ? $val : [];
break;
default:
$out[$key] = sanitize_text_field($val);
}
}
return $out;
}
protected function register_section_routes(string $route_slug, string $domain): void {
register_rest_route(self::API_NAMESPACE, '/settings/' . $route_slug . '/(?P<section>[a-z0-9_-]+)', [
'methods' => 'GET',
'callback' => function (WP_REST_Request $request) use ($domain) {
return $this->get_section_settings($request, $domain);
},
'permission_callback' => [$this, 'check_permission'],
]);
register_rest_route(self::API_NAMESPACE, '/settings/' . $route_slug . '/(?P<section>[a-z0-9_-]+)', [
'methods' => 'POST',
'callback' => function (WP_REST_Request $request) use ($domain) {
return $this->save_section_settings($request, $domain);
},
'permission_callback' => [$this, 'check_permission'],
]);
}
protected function get_section_settings(WP_REST_Request $request, string $domain): WP_REST_Response {
$provider = AKSRT_Admin_Schema_Provider::get_instance();
$section = (string) $request->get_param('section');
$schema = $provider->get_section_schema($domain, $section);
if (!$schema) {
return $this->error('未知的设置分组: ' . esc_html($section), 404);
}
return $this->success([
'data' => $provider->read_settings($domain, $section),
'schema' => $schema,
'payload' => [
'domain' => $provider->normalize_domain($domain),
'section' => $provider->normalize_section($section),
'version' => $schema['version'] ?? '1.0.0',
],
]);
}
protected function save_section_settings(WP_REST_Request $request, string $domain): WP_REST_Response {
$provider = AKSRT_Admin_Schema_Provider::get_instance();
$section = (string) $request->get_param('section');
$schema = $provider->get_section_schema($domain, $section);
if (!$schema) {
return $this->error('未知的设置分组: ' . esc_html($section), 404);
}
$params = $this->get_json_params($request);
$payload = $params['data'] ?? $params;
if (!is_array($payload)) {
return $this->error('无效的设置载荷');
}
$sanitized = $this->sanitize_fields($payload, $provider->get_allowed_fields($domain, $section));
$validation = $provider->validate($domain, $sanitized, $section);
if (!$validation['valid']) {
return $this->error(implode('; ', $validation['errors']), 422);
}
$provider->write_settings($domain, $sanitized, $section);
return $this->success([
'message' => sprintf('%s/%s 设置已保存', $provider->normalize_domain($domain), $provider->normalize_section($section)),
'data' => $provider->read_settings($domain, $section),
'payload' => [
'domain' => $provider->normalize_domain($domain),
'section' => $provider->normalize_section($section),
'version' => $schema['version'] ?? '1.0.0',
],
]);
}
}