Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.
Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)
Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
(dropped 3 stale entries, added the 17 missing ones)
Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
when it is empty
Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.
Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
273 lines
12 KiB
PHP
273 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* @package Jio
|
|
*/
|
|
|
|
namespace Jio\Admin;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
class GlobalController extends ControllerBase {
|
|
use GlobalControllerPart1;
|
|
use GlobalControllerPart2;
|
|
|
|
|
|
private static $instance = null;
|
|
|
|
public static function get_instance(): self {
|
|
if (null === self::$instance) self::$instance = new self();
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Register all routes for the global domain.
|
|
*/
|
|
public function register_routes(): void {
|
|
register_rest_route(self::API_NAMESPACE, '/mail/test', [
|
|
'methods' => 'POST',
|
|
'callback' => [$this, 'rest_test_mail'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// Footer Tabbar
|
|
register_rest_route(self::API_NAMESPACE, '/settings/footer-tabbar', [
|
|
'methods' => ['GET', 'POST'],
|
|
'callback' => [$this, 'rest_handle_footer_tabbar'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
register_rest_route(self::API_NAMESPACE, '/settings/footer-tabbar/reorder', [
|
|
'methods' => 'POST',
|
|
'callback' => [$this, 'rest_reorder_footer_tabbar'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// Floating Buttons
|
|
register_rest_route(self::API_NAMESPACE, '/settings/floating-buttons', [
|
|
'methods' => ['GET', 'POST'],
|
|
'callback' => [$this, 'rest_handle_floating_buttons'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// Friend Links
|
|
register_rest_route(self::API_NAMESPACE, '/friend-links', [
|
|
'methods' => ['GET', 'POST'],
|
|
'callback' => [$this, 'rest_handle_friend_links'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
register_rest_route(self::API_NAMESPACE, '/friend-links/(?P<id>\d+)', [
|
|
'methods' => 'DELETE',
|
|
'callback' => [$this, 'rest_delete_friend_link'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
register_rest_route(self::API_NAMESPACE, '/friend-links/reorder', [
|
|
'methods' => 'POST',
|
|
'callback' => [$this, 'rest_reorder_friend_links'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// CMS Features
|
|
register_rest_route(self::API_NAMESPACE, '/settings/cms-features', [
|
|
'methods' => ['GET', 'POST'],
|
|
'callback' => [$this, 'rest_handle_cms_features'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// Category recommend
|
|
register_rest_route(self::API_NAMESPACE, '/settings/category-recommend', [
|
|
'methods' => ['GET', 'POST'],
|
|
'callback' => [$this, 'rest_handle_category_recommend'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// Categories list (for admin selectors)
|
|
register_rest_route(self::API_NAMESPACE, '/categories', [
|
|
'methods' => 'GET',
|
|
'callback' => [$this, 'rest_get_categories'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// Category term meta
|
|
register_rest_route(self::API_NAMESPACE, '/categories/(?P<id>\d+)/meta', [
|
|
'methods' => 'POST',
|
|
'callback' => [$this, 'rest_update_category_meta'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// Homepage categories (for admin tab editor)
|
|
register_rest_route(self::API_NAMESPACE, '/homepage/categories', [
|
|
'methods' => 'GET',
|
|
'callback' => [$this, 'rest_homepage_categories'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
]);
|
|
|
|
// User search (for admin user selectors)
|
|
register_rest_route(self::API_NAMESPACE, '/users/search', [
|
|
'methods' => 'GET',
|
|
'callback' => [$this, 'rest_search_users'],
|
|
'permission_callback' => [$this, 'check_permission'],
|
|
'args' => [
|
|
'search' => ['type' => 'string', 'default' => '', 'sanitize_callback' => 'sanitize_text_field'],
|
|
'number' => ['type' => 'integer', 'default' => 20, 'sanitize_callback' => 'absint'],
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function rest_handle_cms_features(\WP_REST_Request $request): \WP_REST_Response {
|
|
if ($request->get_method() === 'GET') {
|
|
return $this->success(['cms_features' => \Jio\Settings\Settings::get_cms_features()]);
|
|
}
|
|
|
|
$params = $this->get_json_params($request);
|
|
$allowed = [
|
|
'resource_cpt_enabled' => 'bool',
|
|
'search_include_resource' => 'bool',
|
|
];
|
|
$sanitized = $this->sanitize_fields($params, $allowed);
|
|
$settings = \Jio\Settings\Settings::get_all();
|
|
$settings['cms_features'] = array_merge(
|
|
is_array($settings['cms_features'] ?? null) ? $settings['cms_features'] : [],
|
|
$sanitized
|
|
);
|
|
update_option('jio_settings', $settings);
|
|
\Jio\Settings\Settings::flush_settings_cache();
|
|
|
|
return $this->success(['message' => 'CMS 功能已保存', 'cms_features' => \Jio\Settings\Settings::get_cms_features()]);
|
|
}
|
|
|
|
public function rest_test_mail(\WP_REST_Request $request): \WP_REST_Response {
|
|
$params = $this->get_json_params($request);
|
|
$to = sanitize_email($params['to'] ?? '');
|
|
if (!is_email($to)) {
|
|
return $this->error(__('请输入有效的邮箱地址', 'jio'));
|
|
}
|
|
|
|
$result = \Jio\Settings\Mail::send_test_email($to);
|
|
if (is_wp_error($result)) {
|
|
return $this->error(__('邮件发送失败,详细原因已写入服务器错误日志', 'jio'));
|
|
}
|
|
return $this->success(['message' => '测试邮件已发送']);
|
|
}
|
|
|
|
public function rest_homepage_categories(): \WP_REST_Response {
|
|
$data = [];
|
|
|
|
$cats = get_categories(['hide_empty' => false, 'orderby' => 'name', 'order' => 'ASC']);
|
|
foreach ($cats as $cat) {
|
|
$data[] = [
|
|
'id' => (int) $cat->term_id,
|
|
'term_id' => (int) $cat->term_id,
|
|
'name' => $cat->name,
|
|
'slug' => $cat->slug,
|
|
'count' => (int) $cat->count,
|
|
'parent' => (int) $cat->parent,
|
|
'taxonomy' => 'category',
|
|
];
|
|
}
|
|
|
|
return $this->success(['data' => $data]);
|
|
}
|
|
|
|
public function rest_handle_friend_links(\WP_REST_Request $request): \WP_REST_Response {
|
|
if ($request->get_method() === 'GET') {
|
|
$links = jio_get_friend_links();
|
|
return rest_ensure_response(['code' => 'success', 'data' => $links]);
|
|
}
|
|
|
|
$params = $this->get_json_params($request);
|
|
$links = get_option('jio_friend_links', []);
|
|
$new_link = [
|
|
'id' => uniqid('fl_'),
|
|
'name' => sanitize_text_field($params['name'] ?? ''),
|
|
'url' => esc_url_raw($params['url'] ?? ''),
|
|
'logo' => esc_url_raw($params['logo'] ?? ''),
|
|
'description' => sanitize_textarea_field($params['description'] ?? ''),
|
|
'sort_order' => (int) ($params['sort_order'] ?? 0),
|
|
'active' => 1,
|
|
];
|
|
$links[] = $new_link;
|
|
usort($links, function ($a, $b) {
|
|
return ($a['sort_order'] ?? 0) <=> ($b['sort_order'] ?? 0);
|
|
});
|
|
update_option('jio_friend_links', $links);
|
|
do_action('jio_friend_link_submitted', $new_link);
|
|
|
|
return rest_ensure_response(['code' => 'success', 'data' => $new_link, 'message' => __('Friend link added.', 'jio')]);
|
|
}
|
|
|
|
public function rest_delete_friend_link(\WP_REST_Request $request): \WP_REST_Response {
|
|
$id = $request->get_param('id');
|
|
$links = get_option('jio_friend_links', []);
|
|
$links = array_filter($links, function ($link) use ($id) {
|
|
return ($link['id'] ?? '') !== $id;
|
|
});
|
|
$links = array_values($links);
|
|
update_option('jio_friend_links', $links);
|
|
return rest_ensure_response(['code' => 'success', 'message' => __('Friend link deleted.', 'jio')]);
|
|
}
|
|
|
|
public function rest_reorder_friend_links(\WP_REST_Request $request): \WP_REST_Response {
|
|
$ordered_ids = $request->get_param('ids');
|
|
if (!is_array($ordered_ids)) {
|
|
return new \WP_REST_Response(['code' => 'error', 'message' => __('参数错误', 'jio')], 400);
|
|
}
|
|
$links = get_option('jio_friend_links', []);
|
|
$order_map = array_flip($ordered_ids);
|
|
usort($links, function ($a, $b) use ($order_map) {
|
|
$idx_a = $order_map[($a['id'] ?? '')] ?? 999;
|
|
$idx_b = $order_map[($b['id'] ?? '')] ?? 999;
|
|
return $idx_a <=> $idx_b;
|
|
});
|
|
foreach ($links as $index => &$link) {
|
|
$link['sort_order'] = $index;
|
|
}
|
|
update_option('jio_friend_links', $links);
|
|
return rest_ensure_response(['code' => 'success', 'message' => __('Order saved.', 'jio')]);
|
|
}
|
|
|
|
public function rest_handle_footer_tabbar(\WP_REST_Request $request): \WP_REST_Response {
|
|
if ($request->get_method() === 'GET') {
|
|
$settings = class_exists('\Jio\Settings\Settings')
|
|
? \Jio\Settings\Settings::get_footer_tabbar_settings()
|
|
: ['enabled' => true, 'scroll_hide' => false, 'scroll_down_hide' => true, 'items' => []];
|
|
return rest_ensure_response(['code' => 'success', 'data' => $settings]);
|
|
}
|
|
|
|
$params = $this->get_json_params($request);
|
|
$items = isset($params['items']) ? array_map([$this, 'sanitize_tabbar_item'], (array) $params['items']) : [];
|
|
|
|
$max_items = max(3, min(7, (int) ($params['max_items'] ?? 5)));
|
|
if (count($items) > $max_items) {
|
|
return new \WP_REST_Response([
|
|
'code' => 'error',
|
|
'message' => sprintf(__('Footer tabbar supports at most %d items.', 'jio'), $max_items),
|
|
], 400);
|
|
}
|
|
|
|
$tabbar = [
|
|
'enabled' => !empty($params['enabled']),
|
|
'scroll_hide' => !empty($params['scroll_hide']),
|
|
'scroll_down_hide' => !empty($params['scroll_down_hide']),
|
|
'max_items' => $max_items,
|
|
'icon_size' => max(16, min(32, (int) ($params['icon_size'] ?? 22))),
|
|
'text_size' => max(8, min(14, (int) ($params['text_size'] ?? 10))),
|
|
'show_text' => !empty($params['show_text']),
|
|
'active_color' => \Jio\Core\Color::sanitize($params['active_color'] ?? '') ?: '#f04494',
|
|
'bg_color' => \Jio\Core\Color::sanitize($params['bg_color'] ?? '') ?: '',
|
|
'border' => !empty($params['border']),
|
|
'shadow' => !empty($params['shadow']),
|
|
'animation' => !empty($params['animation']),
|
|
'double_click_home' => !empty($params['double_click_home']),
|
|
'badge_dot' => !empty($params['badge_dot']),
|
|
'items' => $items,
|
|
];
|
|
update_option('jio_footer_tabbar', $tabbar);
|
|
|
|
if (class_exists('\Jio\Settings\Settings')) {
|
|
\Jio\Settings\Settings::flush_settings_cache();
|
|
}
|
|
|
|
return rest_ensure_response(['code' => 'success', 'message' => __('Footer tabbar settings saved.', 'jio')]);
|
|
}
|
|
|
|
}
|