refactor(settings): collapse get_all to aksrt_settings and drop migration UI

Make aksrt_settings the sole theme settings store for get_all(), remove
aksrt_seo_settings/aksrt_basic_settings merge paths, point global.logo
schema at aksrt_settings, and delete the retired settings migration page,
route, REST endpoint, and related SPA surface.
This commit is contained in:
2026-07-11 16:55:27 +08:00
parent b4da8cc1f4
commit 91b083b2b0
15 changed files with 16 additions and 471 deletions
@@ -71,13 +71,6 @@ class AKSRT_Admin_Import_Export_Controller extends AKSRT_Admin_Controller_Base {
'permission_callback' => [$this, 'check_permission'],
]);
// Migration status
register_rest_route(self::API_NAMESPACE, '/settings/migration-status', [
'methods' => 'GET',
'callback' => [$this, 'rest_migration_status'],
'permission_callback' => [$this, 'check_permission'],
]);
// Schema introspection (for frontend to discover available fields)
register_rest_route(self::API_NAMESPACE, '/settings/schema/(?P<domain>[a-z_]+)', [
'methods' => 'GET',
@@ -401,8 +394,4 @@ class AKSRT_Admin_Import_Export_Controller extends AKSRT_Admin_Controller_Base {
return $this->success(['checks' => $checks]);
}
/**
* Migration status — reports schema version and pending migrations.
*/
}
@@ -3,17 +3,6 @@ defined('ABSPATH') || exit;
trait AKSRT_Admin_Import_Export_Controller_Part_1 {
public function rest_migration_status(WP_REST_Request $request): WP_REST_Response {
// Settings migration UI/runtime has been removed. Keep the route for old SPA chunks
// until the next full admin rebuild, but return an empty retired payload.
return $this->success([
'schema_version' => get_option('aksrt_db_schema_version', '0.0.0'),
'migration_version' => 'retired',
'migration_log' => [],
'retired' => true,
]);
}
/**
* Get the schema definition for a domain (for frontend introspection).
*/
@@ -43,7 +43,7 @@ class AKSRT_Admin_Schema_Global {
'key' => 'logo',
'title' => 'LOGO图像',
'version' => '1.0.0',
'option_key' => 'aksrt_seo_settings',
'option_key' => 'aksrt_settings',
'groups' => [
['key' => 'logo', 'title' => 'Logo 设置', 'fields' => [
['key' => 'site_logo', 'label' => '站点 Logo', 'type' => 'media', 'default' => ''],
@@ -1,27 +0,0 @@
<?php
/**
* AKSRT_Admin_Schema_Tools_Migration section schema.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_Admin_Schema_Tools_Migration {
public static function build(): array {
return [
'key' => 'migration',
'title' => '数据迁移',
'version' => '1.0.0',
'option_key' => 'aksrt_settings',
'groups' => [
['key' => 'status', 'title' => '迁移状态', 'fields' => [
['key' => 'current_version', 'label' => '当前版本', 'type' => 'display'],
['key' => 'pending_migrations', 'label' => '待执行迁移', 'type' => 'display'],
['key' => 'run_migration', 'label' => '执行迁移', 'type' => 'button', 'help' => '手动触发数据库迁移'],
]],
],
];
}
}
@@ -1,262 +0,0 @@
<?php
/**
* AKSRT Settings Migration
*
* Handles AKSRT's own schema evolution.
* This migration layer no longer backfills or mirrors deprecated option aliases.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_Settings_Migration {
private static $instance = null;
/**
* Current migration schema version.
*/
const MIGRATION_VERSION = '1.3.0';
/**
* Option key that stores the current migration version.
*/
const VERSION_KEY = 'aksrt_settings_migration_version';
/**
* Option key that stores migration log entries.
*/
const LOG_KEY = 'aksrt_settings_migration_log';
public static function get_instance(): self {
if (null === self::$instance) self::$instance = new self();
return self::$instance;
}
/**
* Run pending migrations.
* Called on theme activation and admin_init.
*/
public function maybe_migrate(): void {
$current = get_option(self::VERSION_KEY, '0.0.0');
if (version_compare($current, self::MIGRATION_VERSION, '>=')) {
return; // Already up to date
}
$log = $this->get_log();
$schema_provider = AKSRT_Admin_Schema_Provider::get_instance();
// Run migrations in order
$this->migrate_v1_0_0($schema_provider, $log);
$this->migrate_v1_2_0($log);
$this->migrate_v1_3_0($log);
// Update version
update_option(self::VERSION_KEY, self::MIGRATION_VERSION);
$log[] = [
'version' => self::MIGRATION_VERSION,
'timestamp' => gmdate('Y-m-d H:i:s'),
'action' => 'migration_complete',
];
update_option(self::LOG_KEY, $log);
}
/**
* Get the migration log.
*
* @return array
*/
public function get_log(): array {
$log = get_option(self::LOG_KEY, []);
return is_array($log) ? $log : [];
}
/**
* Get current migration version.
*
* @return string
*/
public function get_version(): string {
return get_option(self::VERSION_KEY, '0.0.0');
}
/* ------------------------------------------------------------------ */
/* Migration: v1.0.0 */
/* Maps old option keys to new schema-managed domains. */
/* ------------------------------------------------------------------ */
private function migrate_v1_0_0(AKSRT_Admin_Schema_Provider $schema_provider, array &$log): void {
// 1. Migrate aksrt_basic_settings fields into the new global domain
$this->migrate_basic_to_global($schema_provider, $log);
// 2. Migrate aksrt_seo_settings to the new seo domain (already a standalone key)
// No action needed — it's already stored under aksrt_seo_settings.
// 3. Ensure all domain options exist with defaults
foreach ($schema_provider->get_domain_keys() as $domain) {
$option_key = $schema_provider->get_option_key($domain);
$existing = get_option($option_key);
if ($existing === false) {
$defaults = $schema_provider->get_defaults($domain);
if (!empty($defaults)) {
add_option($option_key, $defaults);
$log[] = [
'version' => '1.0.0',
'action' => 'created_domain_defaults',
'domain' => $domain,
];
}
}
}
}
/**
* Migrate fields from aksrt_basic_settings to the new global domain.
*
* The old aksrt_basic_settings contains many fields from different domains
* (auth, comment, avatar, etc.). We selectively map them to the new structure
* without deleting the original option.
*/
private function migrate_basic_to_global(AKSRT_Admin_Schema_Provider $schema_provider, array &$log): void {
$old = get_option('aksrt_basic_settings', []);
if (!is_array($old) || empty($old)) return;
// Map old keys to new global domain keys
$field_map = [
'comment_enabled' => 'comment_enabled',
'comments_per_page' => 'comments_per_page',
'comment_requires_registration' => 'comment_requires_registration',
'lazy_load' => 'lazy_load',
'avatar_source' => 'avatar_source',
'icp_filing' => 'icp_filing',
'footer_text' => 'footer_text',
'copyright_year' => 'copyright_year',
'registration_enabled' => 'registration_enabled',
'email_verification' => 'email_verification',
];
$new_data = [];
foreach ($field_map as $old_key => $new_key) {
if (isset($old[$old_key])) {
$new_data[$new_key] = $old[$old_key];
}
}
if (!empty($new_data)) {
$existing = get_option('aksrt_basic_settings', []);
if (!is_array($existing)) $existing = [];
// Merge: new mapped values take precedence only if not already set
$merged = wp_parse_args($existing, $new_data);
update_option('aksrt_basic_settings', $merged);
$log[] = [
'version' => '1.0.0',
'action' => 'migrated_basic_to_global',
'fields' => array_keys($new_data),
'migrated' => count($new_data),
];
}
}
private function migrate_v1_2_0(array &$log): void {
$settings = get_option('aksrt_settings', []);
if (!is_array($settings) || empty($settings)) {
return;
}
$map = [
'header_slider_search' => 'header_components_search_enabled',
'header_slider_cards' => 'header_components_cards_enabled',
'header_slider_nav_color' => 'header_components_nav_color',
'header_slider_show' => 'header_components_show_on',
'header_slider_show_type' => 'header_components_device_visibility',
'header_slider_filter_blur' => 'header_components_filter_blur_devices',
'header_slider_card_show' => 'header_components_card_show_devices',
'header_card_shared_bg' => 'header_components_card_shared_bg',
'header_card_blur' => 'header_components_card_blur',
'header_card_icon_shape' => 'header_components_card_icon_shape',
'header_icon_cards' => 'header_components_icon_cards',
'header_slider_search_pc' => 'header_components_search_pc',
'header_slider_search_mobile' => 'header_components_search_mobile',
'header_slider_search_show_keywords' => 'header_components_search_show_keywords',
'header_slider_search_popular_limit' => 'header_components_search_popular_limit',
'header_slider_search_show_input_cat' => 'header_components_search_show_input_cat',
'header_slider_search_show_type' => 'header_components_search_show_type',
];
$migrated = [];
foreach ($map as $old_key => $new_key) {
if (array_key_exists($old_key, $settings) && !array_key_exists($new_key, $settings)) {
$settings[$new_key] = $settings[$old_key];
$migrated[] = $old_key;
}
if (array_key_exists($old_key, $settings)) {
unset($settings[$old_key]);
}
}
if (!empty($migrated)) {
update_option('aksrt_settings', $settings);
$log[] = [
'version' => '1.2.0',
'action' => 'renamed_header_components_keys',
'migrated' => $migrated,
];
}
}
private function migrate_v1_3_0(array &$log): void {
$settings = get_option('aksrt_settings', []);
if (!is_array($settings) || empty($settings)) {
return;
}
$map = [
'homepage_hero_enabled' => 'homepage_module_hero_enabled',
'homepage_banner_enabled' => 'homepage_module_banner_enabled',
];
$migrated = [];
foreach ($map as $old_key => $new_key) {
if (array_key_exists($old_key, $settings) && !array_key_exists($new_key, $settings)) {
$settings[$new_key] = $settings[$old_key];
$migrated[] = $old_key;
}
if (array_key_exists($old_key, $settings)) {
unset($settings[$old_key]);
}
}
if (!empty($migrated)) {
update_option('aksrt_settings', $settings);
$log[] = [
'version' => '1.3.0',
'action' => 'renamed_homepage_module_toggle_keys',
'migrated' => $migrated,
];
}
}
public function map_legacy_key(string $option_key): ?array {
$map = [
'aksrt_basic_settings' => ['domain' => 'global', 'key' => 'aksrt_basic_settings'],
'aksrt_seo_settings' => ['domain' => 'seo', 'key' => 'aksrt_seo_settings'],
'aksrt_mail_smtp' => ['domain' => 'global', 'key' => 'aksrt_mail_smtp'],
'aksrt_oauth' => ['domain' => 'users', 'key' => 'aksrt_oauth'],
'aksrt_moderation_config' => ['domain' => 'permissions', 'key' => 'aksrt_moderation_config'],
'aksrt_captcha_config' => ['domain' => 'permissions', 'key' => 'aksrt_captcha_config'],
'aksrt_credit_settings' => ['domain' => 'users', 'key' => 'aksrt_credit_settings'],
'aksrt_notification_settings' => ['domain' => 'users', 'key' => 'aksrt_notification_settings'],
'aksrt_footer_settings' => ['domain' => 'page_display', 'key' => 'aksrt_footer_settings'],
'aksrt_footer_tabbar' => ['domain' => 'page_display', 'key' => 'aksrt_footer_tabbar'],
'aksrt_floating_buttons' => ['domain' => 'global', 'key' => 'aksrt_floating_buttons'],
'aksrt_friend_links' => ['domain' => 'page_display', 'key' => 'aksrt_friend_links'],
'aksrt_banners' => ['domain' => 'page_display', 'key' => 'aksrt_banners'],
'aksrt_category_recommend' => ['domain' => 'page_display', 'key' => 'aksrt_category_recommend'],
];
return $map[$option_key] ?? null;
}
}
+9 -15
View File
@@ -66,7 +66,7 @@ class AKSRT_Settings {
*/
public static function on_option_updated(string $option_name): void {
$tracked = array_merge(
['aksrt_settings', 'aksrt_basic_settings'],
['aksrt_settings'],
self::STANDALONE_OPTION_KEYS
);
@@ -95,19 +95,14 @@ class AKSRT_Settings {
return self::$cached_all;
}
// Canonical theme settings live only in aksrt_settings.
// Operational configs (captcha/moderation/oauth/footer/etc.) stay standalone.
$settings = get_option('aksrt_settings', []);
$seo = get_option('aksrt_seo_settings', []);
$basic = get_option('aksrt_basic_settings', []);
$merged = array_merge(
is_array($settings) ? $settings : [],
is_array($seo) ? $seo : [],
is_array($basic) ? $basic : []
);
if (!is_array($merged)) $merged = [];
self::$cached_all = $merged;
return $merged;
if (!is_array($settings)) {
$settings = [];
}
self::$cached_all = $settings;
return $settings;
}
/**
@@ -126,7 +121,6 @@ class AKSRT_Settings {
* 用于导入导出完整性检查。
*/
public const STANDALONE_OPTION_KEYS = [
'aksrt_seo_settings',
'aksrt_mail_smtp',
'aksrt_oauth',
'aksrt_captcha_config',
@@ -267,7 +261,7 @@ class AKSRT_Settings {
}
}
/** 启动时对齐原生 site_icon,兼容历史已保存的 SEO favicon。 */
/** 启动时对齐原生 site_icon,同步自定义 site_favicon 到原生 site_icon。 */
public static function maybe_sync_native_site_icon(): void {
$custom = self::custom_favicon_url();
if ($custom === '') {
@@ -86,7 +86,7 @@ trait AKSRT_Settings_Credits_Payment_Groups {
/**
* 邀请注册功能总开关(独立于积分系统)。
* 控制邀请链接、注册页邀请码字段、用户中心邀请卡片的显示。
* 存储在 aksrt_basic_settings['invite_registration_enabled']。
* 存储在 aksrt_settings(invit_code_s / invite_registration_enabled)。
*/
public static function invite_registration_enabled(): bool {
return AKSRT_Settings_Credits_Runtime::invite_registration_enabled();
@@ -232,7 +232,7 @@ class AKSRT_Settings_Credits_Runtime {
/**
* 邀请注册功能总开关(独立于积分系统)。
* 控制邀请链接、注册页邀请码字段、用户中心邀请卡片的显示。
* 存储在 aksrt_basic_settings['invite_registration_enabled']。
* 存储在 aksrt_settings(invit_code_s / invite_registration_enabled)。
*/
public static function invite_registration_enabled(): bool {
return !empty(self::get_invite_registration_config()['enabled']);
@@ -10,7 +10,7 @@ defined('ABSPATH') || exit;
trait AKSRT_Settings_Display_Page_Groups {
/**
* 获取 SEO 设置(从 aksrt_seo_settings option 读取)
* 获取 SEO 设置(从 aksrt_settings 读取)
*/
public static function get_seo_settings(): array {
$s = self::get_all();