namespace = 'aksrt/v1'; $this->rest_base = 'widgets'; } public function register_routes(): void { register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P[a-z][a-z0-9_]*)/items', [ 'methods' => \WP_REST_Server::READABLE, 'callback' => [$this, 'get_items'], 'permission_callback' => '__return_true', 'args' => [ 'widget' => ['type' => 'string', 'required' => true, 'pattern' => '^[a-z][a-z0-9_]*$', 'validate_callback' => [$this, 'validate_widget']], 'instance' => ['type' => 'string', 'required' => true, 'pattern' => '^aksrt_widget_[a-z0-9_]+-[1-9][0-9]*$'], 'page' => ['type' => 'integer', 'default' => 1, 'minimum' => 1, 'maximum' => 1000], 'segment' => ['type' => 'string', 'default' => '', 'pattern' => '^[0-9]{0,2}$'], ], ]); register_rest_route($this->namespace, '/' . $this->rest_base . '/quote', [ 'methods' => \WP_REST_Server::READABLE, 'callback' => [$this, 'get_quote'], 'permission_callback' => '__return_true', 'args' => [], ]); } public function validate_widget($value): bool { return is_string($value) && WidgetRegistry::get($value) !== null; } /** * @param \WP_REST_Request $request Request object. * @return \WP_REST_Response|\WP_Error */ public function get_items($request) { $unknown = array_diff(array_keys($request->get_params()), ['widget', 'instance', 'page', 'segment']); if ($unknown) { return new \WP_Error('aksrt_widget_unknown_parameter', __('请求包含不支持的参数。', 'aksrt'), ['status' => 400, 'parameters' => array_values($unknown)]); } $slug = (string) $request->get_param('widget'); if (!RendererRegistry::supports_items($slug)) { return new \WP_Error('aksrt_widget_items_unsupported', __('该小工具不提供动态列表。', 'aksrt'), ['status' => 404]); } $instance_id = (string) $request->get_param('instance'); $instance = $this->load_instance($slug, $instance_id); if (is_wp_error($instance)) { return $instance; } $page = max(1, (int) $request->get_param('page')); $segment = (string) $request->get_param('segment'); $payload = PostRenderer::payload($instance, $slug, $page, $segment); return rest_ensure_response(['success' => true, 'code' => 'ok'] + $payload); } /** @return \WP_REST_Response|\WP_Error */ public function get_quote(\WP_REST_Request $request) { if ($request->get_params()) { return new \WP_Error('aksrt_widget_unknown_parameter', __('一言接口不接受查询参数。', 'aksrt'), ['status' => 400]); } $cached = get_transient('aksrt_widget_quote'); if (is_array($cached) && !empty($cached['text'])) { return rest_ensure_response($cached); } $fallbacks = [__('保持好奇,持续创造。', 'aksrt'), __('知识因为分享而更有价值。', 'aksrt'), __('把复杂的事,做得清楚而简单。', 'aksrt')]; $data = ['text' => $fallbacks[array_rand($fallbacks)], 'author' => 'AKSRT', 'source' => 'local']; $response = wp_remote_get('https://v1.hitokoto.cn/?encode=json', ['timeout' => 3, 'redirection' => 2, 'user-agent' => 'AKSRT Widget/1.0']); if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { $remote = json_decode((string) wp_remote_retrieve_body($response), true); if (is_array($remote) && !empty($remote['hitokoto'])) { $data = ['text' => sanitize_text_field((string) $remote['hitokoto']), 'author' => sanitize_text_field((string) ($remote['from_who'] ?? $remote['from'] ?? '')), 'source' => 'hitokoto']; } } set_transient('aksrt_widget_quote', $data, 10 * MINUTE_IN_SECONDS); return rest_ensure_response($data); } /** @return array|\WP_Error */ private function load_instance(string $slug, string $instance_id) { $definition = WidgetRegistry::get($slug); if ($definition === null || !preg_match('/^' . preg_quote($definition->id_base(), '/') . '-([1-9][0-9]*)$/', $instance_id, $matches)) { return new \WP_Error('aksrt_widget_invalid_instance', __('小工具实例无效。', 'aksrt'), ['status' => 400]); } $sidebars = wp_get_sidebars_widgets(); $registered = false; foreach ($sidebars as $widgets) { if (is_array($widgets) && in_array($instance_id, $widgets, true)) { $registered = true; break; } } if (!$registered) { return new \WP_Error('aksrt_widget_instance_not_registered', __('小工具实例未挂载。', 'aksrt'), ['status' => 404]); } $widget = new SchemaWidget($definition); $settings = $widget->get_settings(); $number = (int) $matches[1]; if (!is_array($settings) || !isset($settings[$number]) || !is_array($settings[$number])) { return new \WP_Error('aksrt_widget_instance_not_found', __('未找到小工具配置。', 'aksrt'), ['status' => 404]); } return $definition->normalize($settings[$number]); } }