refactor: rename the theme brand and every identifier from AKSRT to Jio

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>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-11-01 20:05:04 +08:00
1 parent 5b16bc6e15
commit 35bb96e82f
997 files changed
+28216 -28188

No files matched your search

+51 -51
View File
@@ -4,19 +4,19 @@ declare(strict_types=1);
require __DIR__ . '/bootstrap.php';
use AKSRT\WidgetSystem\FieldSchema;
use AKSRT\WidgetSystem\FormRenderer;
use AKSRT\WidgetSystem\PostQuery;
use AKSRT\WidgetSystem\RestController;
use AKSRT\WidgetSystem\SchemaWidget;
use AKSRT\WidgetSystem\WidgetDefinition;
use AKSRT\WidgetSystem\WidgetRegistry;
use AKSRT\WidgetSystem\WidgetTransfer;
use AKSRT\WidgetSystem\WidgetVisibility;
use AKSRT\WidgetSystem\WidgetSchemas;
use AKSRT\WidgetSystem\Renderers\ContentRenderer;
use AKSRT\WidgetSystem\Renderers\GeneralRenderer;
use AKSRT\WidgetSystem\Renderers\SliderRenderer;
use Jio\WidgetSystem\FieldSchema;
use Jio\WidgetSystem\FormRenderer;
use Jio\WidgetSystem\PostQuery;
use Jio\WidgetSystem\RestController;
use Jio\WidgetSystem\SchemaWidget;
use Jio\WidgetSystem\WidgetDefinition;
use Jio\WidgetSystem\WidgetRegistry;
use Jio\WidgetSystem\WidgetTransfer;
use Jio\WidgetSystem\WidgetVisibility;
use Jio\WidgetSystem\WidgetSchemas;
use Jio\WidgetSystem\Renderers\ContentRenderer;
use Jio\WidgetSystem\Renderers\GeneralRenderer;
use Jio\WidgetSystem\Renderers\SliderRenderer;
if (!function_exists('current_datetime')) {
function current_datetime(): DateTimeImmutable {
@@ -114,7 +114,7 @@ final class WidgetSystemTest {
$this->same('1,-2,3', $reference['cat'], 'reference cat preserves cleaned signed IDs for WP_Query descendant semantics');
$this->false(isset($reference['category__in']) || isset($reference['category__not_in']), 'reference cat does not narrow matches to direct categories');
$this->false(isset($reference['tax_query']), 'topic filters are removed with the topics feature');
$this->same('aksrt_post_views', $reference['meta_key'], 'reference view ordering uses numeric view meta');
$this->same('jio_post_views', $reference['meta_key'], 'reference view ordering uses numeric view meta');
$this->false(isset($reference['meta_query']), 'modern reference queries do not apply commerce filters by default');
$this->same(1, $reference['paged'], 'no-pagination queries stay on first page');
$this->same('2026-06-08 12:30:00', $reference['date_query'][0]['after'], 'limit_day subtracts days in the WordPress site timezone');
@@ -260,31 +260,31 @@ final class WidgetSystemTest {
$this->false(WidgetVisibility::should_render(['show_id_type' => 'show', 'show_ids' => '3,8'], 0, false), 'show list rejects archives');
$this->false(WidgetVisibility::should_render(['show_id_type' => 'hide', 'show_ids' => '3,8'], 3, true), 'hide list suppresses matching ID');
$this->true(WidgetVisibility::should_render(['show_id_type' => 'hide', 'show_ids' => '3,8'], 0, false), 'hide list keeps archives');
$this->same('aksrt-widget--only-pc', WidgetVisibility::device_class(['show_type' => 'only_pc']), 'PC device class is stable');
$this->same('aksrt-widget--only-mobile', WidgetVisibility::device_class(['show_type' => 'only_sm']), 'mobile device class is stable');
$this->same('jio-widget--only-pc', WidgetVisibility::device_class(['show_type' => 'only_pc']), 'PC device class is stable');
$this->same('jio-widget--only-mobile', WidgetVisibility::device_class(['show_type' => 'only_sm']), 'mobile device class is stable');
$this->same('', WidgetVisibility::device_class(['show_type' => 'invalid']), 'invalid device rule adds no class');
}
private function transfer_round_trip(): void {
aksrt_test_reset_state();
jio_test_reset_state();
$GLOBALS['wp_registered_sidebars'] = ['home_sidebar' => [], 'single_sidebar' => []];
update_option('widget_aksrt_widget_posts', [2 => ['title' => '<b>课程列表</b>', 'count' => 999, 'style' => 'mini'], '_multiwidget' => 1]);
$GLOBALS['aksrt_test_state']['sidebars'] = ['home_sidebar' => ['text-1', 'aksrt_widget_posts-2']];
update_option('widget_jio_widget_posts', [2 => ['title' => '<b>课程列表</b>', 'count' => 999, 'style' => 'mini'], '_multiwidget' => 1]);
$GLOBALS['jio_test_state']['sidebars'] = ['home_sidebar' => ['text-1', 'jio_widget_posts-2']];
$payload = WidgetTransfer::export('home_sidebar');
$this->same(WidgetTransfer::FORMAT, $payload['format'], 'export format is versioned');
$this->same(1, count($payload['sidebars']['home_sidebar']), 'export ignores non-schema widgets');
$this->same(20, $payload['sidebars']['home_sidebar'][0]['settings']['count'], 'export normalizes saved settings');
update_option('widget_aksrt_widget_posts', []);
$GLOBALS['aksrt_test_state']['sidebars']['single_sidebar'] = ['text-9'];
update_option('widget_jio_widget_posts', []);
$GLOBALS['jio_test_state']['sidebars']['single_sidebar'] = ['text-9'];
$result = WidgetTransfer::import($payload, 'append', 'single_sidebar');
$this->same(['sidebars' => 1, 'widgets' => 1], $result, 'append import reports changes');
$this->same(['text-9', 'aksrt_widget_posts-1'], $GLOBALS['aksrt_test_state']['sidebars']['single_sidebar'], 'append import preserves existing widgets');
$this->same(['text-9', 'jio_widget_posts-1'], $GLOBALS['jio_test_state']['sidebars']['single_sidebar'], 'append import preserves existing widgets');
$round_trip = WidgetTransfer::export('single_sidebar');
$this->same($payload['sidebars']['home_sidebar'][0], $round_trip['sidebars']['single_sidebar'][0], 'export/import round trip preserves normalized module');
$replacement = WidgetTransfer::template_payload('links_navigation');
$result = WidgetTransfer::import($replacement, 'replace', 'single_sidebar');
$this->same(3, $result['widgets'], 'targeted template import combines template areas');
$this->false(in_array('text-9', $GLOBALS['aksrt_test_state']['sidebars']['single_sidebar'], true), 'replace import removes previous assignment');
$this->false(in_array('text-9', $GLOBALS['jio_test_state']['sidebars']['single_sidebar'], true), 'replace import removes previous assignment');
try {
WidgetTransfer::import(['format' => 'legacy.widgets', 'sidebars' => []]);
$this->failures[] = 'transfer rejects legacy formats: no exception thrown';
@@ -294,45 +294,45 @@ final class WidgetSystemTest {
}
private function rest_contract(): void {
aksrt_test_reset_state();
jio_test_reset_state();
$controller = new RestController();
$controller->register_routes();
$this->same(1, count($GLOBALS['aksrt_test_state']['routes']), 'REST registers only the widget items route');
$items_route = 'aksrt/v1/widgets/(?P<widget>[a-z][a-z0-9_]*)/items';
$route = $GLOBALS['aksrt_test_state']['routes'][$items_route] ?? [];
$this->true(isset($GLOBALS['aksrt_test_state']['routes'][$items_route]), 'items route remains registered');
$this->false(isset($GLOBALS['aksrt_test_state']['routes']['aksrt/v1/widgets/quote']), 'obsolete quote REST route is removed');
$this->same(1, count($GLOBALS['jio_test_state']['routes']), 'REST registers only the widget items route');
$items_route = 'jio/v1/widgets/(?P<widget>[a-z][a-z0-9_]*)/items';
$route = $GLOBALS['jio_test_state']['routes'][$items_route] ?? [];
$this->true(isset($GLOBALS['jio_test_state']['routes'][$items_route]), 'items route remains registered');
$this->false(isset($GLOBALS['jio_test_state']['routes']['jio/v1/widgets/quote']), 'obsolete quote REST route is removed');
$this->false(method_exists($controller, 'get_quote'), 'obsolete quote REST callback is removed');
$this->same('__return_true', $route['permission_callback'], 'public items route is read-only accessible');
$this->true($controller->validate_widget('posts'), 'known widget validates');
$this->false($controller->validate_widget('shop_products'), 'unknown/shop widget is rejected');
$error = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'aksrt_widget_posts-1', 'page' => 1, 'query' => 'arbitrary']));
$this->error('aksrt_widget_unknown_parameter', $error, 'REST rejects arbitrary query parameters');
$error = $controller->get_items(new WP_REST_Request(['widget' => 'search', 'instance' => 'aksrt_widget_search-1', 'page' => 1]));
$this->error('aksrt_widget_items_unsupported', $error, 'REST rejects non-dynamic widgets');
$error = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'aksrt_widget_posts-1', 'page' => 1]));
$this->error('aksrt_widget_instance_not_registered', $error, 'REST requires an assigned instance');
$GLOBALS['aksrt_test_state']['sidebars'] = ['home_top_content' => ['aksrt_widget_posts-1']];
update_option('widget_aksrt_widget_posts', [1 => ['title' => 'Saved only', 'count' => 2, 'style' => 'list', 'paginate' => 'ajax'], '_multiwidget' => 1]);
$response = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'aksrt_widget_posts-1', 'page' => 2, 'segment' => '']));
$error = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'jio_widget_posts-1', 'page' => 1, 'query' => 'arbitrary']));
$this->error('jio_widget_unknown_parameter', $error, 'REST rejects arbitrary query parameters');
$error = $controller->get_items(new WP_REST_Request(['widget' => 'search', 'instance' => 'jio_widget_search-1', 'page' => 1]));
$this->error('jio_widget_items_unsupported', $error, 'REST rejects non-dynamic widgets');
$error = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'jio_widget_posts-1', 'page' => 1]));
$this->error('jio_widget_instance_not_registered', $error, 'REST requires an assigned instance');
$GLOBALS['jio_test_state']['sidebars'] = ['home_top_content' => ['jio_widget_posts-1']];
update_option('widget_jio_widget_posts', [1 => ['title' => 'Saved only', 'count' => 2, 'style' => 'list', 'paginate' => 'ajax'], '_multiwidget' => 1]);
$response = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'jio_widget_posts-1', 'page' => 2, 'segment' => '']));
$this->true($response instanceof WP_REST_Response, 'registered instance returns REST response');
$data = $response->get_data();
$this->true($data['success'], 'REST success envelope is stable');
$this->same(2, $data['page'], 'REST page reaches saved-query pipeline');
$this->contains('暂无内容', $data['html'], 'REST returns deterministic empty state');
$this->same(4, end($GLOBALS['aksrt_test_state']['query_args'])['posts_per_page'], 'REST reloads saved normalized configuration');
$response = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'aksrt_widget_posts-1', 'page' => 1, 'rest_route' => '/aksrt/v1/widgets/posts/items']));
$this->same(4, end($GLOBALS['jio_test_state']['query_args'])['posts_per_page'], 'REST reloads saved normalized configuration');
$response = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'jio_widget_posts-1', 'page' => 1, 'rest_route' => '/jio/v1/widgets/posts/items']));
$this->true($response instanceof WP_REST_Response, 'plain permalink transport parameter is accepted');
$error = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'aksrt_widget_hot_posts-1', 'page' => 1]));
$this->error('aksrt_widget_invalid_instance', $error, 'REST binds instance ID to requested widget');
$error = $controller->get_items(new WP_REST_Request(['widget' => 'posts', 'instance' => 'jio_widget_hot_posts-1', 'page' => 1]));
$this->error('jio_widget_invalid_instance', $error, 'REST binds instance ID to requested widget');
}
private function payment_states(): void {
aksrt_test_reset_state();
$GLOBALS['aksrt_test_state']['current_post'] = new WP_Post(77, 5);
jio_test_reset_state();
$GLOBALS['jio_test_state']['current_post'] = new WP_Post(77, 5);
$method = new ReflectionMethod(ContentRenderer::class, 'post_pay');
$render = static fn(): string => (string) $method->invoke(null, ['theme' => 'jb-red']);
$GLOBALS['aksrt_test_state']['pay_meta'] = ['pay_type' => 'no', 'price' => 0];
$GLOBALS['jio_test_state']['pay_meta'] = ['pay_type' => 'no', 'price' => 0];
$this->same('', $render(), 'unconfigured article renders nothing and aborts the widget');
$authorized = [
@@ -341,15 +341,15 @@ final class WidgetSystemTest {
'vip' => ['pay_type' => 'vip', 'price' => 0],
];
foreach ($authorized as $label => $meta) {
$GLOBALS['aksrt_test_state']['pay_meta'] = $meta;
$GLOBALS['aksrt_test_state']['paid_access'] = true;
$GLOBALS['jio_test_state']['pay_meta'] = $meta;
$GLOBALS['jio_test_state']['paid_access'] = true;
$this->contains('内容已解锁', $render(), $label . ' authorization delegates to existing access service');
}
$GLOBALS['aksrt_test_state']['pay_meta'] = ['pay_type' => 'video', 'price' => 49];
$GLOBALS['aksrt_test_state']['paid_access'] = false;
$GLOBALS['aksrt_test_state']['logged_in'] = false;
$GLOBALS['jio_test_state']['pay_meta'] = ['pay_type' => 'video', 'price' => 49];
$GLOBALS['jio_test_state']['paid_access'] = false;
$GLOBALS['jio_test_state']['logged_in'] = false;
$this->contains('guest-locked', $render(), 'guest unauthorized state delegates to paywall');
$GLOBALS['aksrt_test_state']['logged_in'] = true;
$GLOBALS['jio_test_state']['logged_in'] = true;
$this->contains('member-locked', $render(), 'logged-in unauthorized state delegates to paywall');
}