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:
@@ -24,5 +24,4 @@ export const toolsApiMethods = {
|
|||||||
resetDomain(domain) { return this.request(`/settings/reset/${domain}`, { method: 'POST' }) },
|
resetDomain(domain) { return this.request(`/settings/reset/${domain}`, { method: 'POST' }) },
|
||||||
resetAllSettings() { return this.request('/settings/reset-all', { method: 'POST' }) },
|
resetAllSettings() { return this.request('/settings/reset-all', { method: 'POST' }) },
|
||||||
getHealthCheck() { return this.request('/settings/health') },
|
getHealthCheck() { return this.request('/settings/health') },
|
||||||
getMigrationStatus() { return this.request('/settings/migration-status') },
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,9 +135,8 @@ const message = useMessage()
|
|||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
|
|
||||||
// 基础设置(aksrt_basic_settings)
|
// 基础设置(canonical: aksrt_settings)
|
||||||
// 后端 /settings/basic 已经做了部分合并,本接口只发送基础字段;
|
// 后端 /settings/basic 返回基础字段;auth 相关字段由 /settings/auth 独立维护。
|
||||||
// auth 相关字段由 /settings/auth 独立维护,互不影响。
|
|
||||||
const basic = reactive({
|
const basic = reactive({
|
||||||
comment_enabled: true,
|
comment_enabled: true,
|
||||||
comment_requires_registration: false,
|
comment_requires_registration: false,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="aksrt-page-container">
|
<div class="aksrt-page-container">
|
||||||
<PageHeader title="主题信息" desc="主题版本、运行环境、已启用模块、迁移状态和关键系统信息。" />
|
<PageHeader title="主题信息" desc="主题版本、运行环境、已启用模块和关键系统信息。" />
|
||||||
|
|
||||||
<div v-if="loading" class="aksrt-theme-info__loading">
|
<div v-if="loading" class="aksrt-theme-info__loading">
|
||||||
<n-spin size="medium" />
|
<n-spin size="medium" />
|
||||||
@@ -24,9 +24,6 @@
|
|||||||
<n-descriptions-item label="数据库 Schema">
|
<n-descriptions-item label="数据库 Schema">
|
||||||
<n-tag type="info" size="small">{{ info.dbSchemaVersion }}</n-tag>
|
<n-tag type="info" size="small">{{ info.dbSchemaVersion }}</n-tag>
|
||||||
</n-descriptions-item>
|
</n-descriptions-item>
|
||||||
<n-descriptions-item label="设置迁移版本">
|
|
||||||
<n-tag type="info" size="small">{{ info.settingsMigrationVersion || '未迁移' }}</n-tag>
|
|
||||||
</n-descriptions-item>
|
|
||||||
<n-descriptions-item label="邮箱验证回填">
|
<n-descriptions-item label="邮箱验证回填">
|
||||||
<n-tag :type="info.emailBackfillDone ? 'success' : 'default'" size="small">
|
<n-tag :type="info.emailBackfillDone ? 'success' : 'default'" size="small">
|
||||||
{{ info.emailBackfillDone ? '已完成' : '未触发' }}
|
{{ info.emailBackfillDone ? '已完成' : '未触发' }}
|
||||||
@@ -135,7 +132,6 @@ const info = ref({
|
|||||||
wpVersion: '',
|
wpVersion: '',
|
||||||
phpVersion: '',
|
phpVersion: '',
|
||||||
dbSchemaVersion: '',
|
dbSchemaVersion: '',
|
||||||
settingsMigrationVersion: '',
|
|
||||||
emailBackfillDone: false,
|
emailBackfillDone: false,
|
||||||
siteUrl: '',
|
siteUrl: '',
|
||||||
apiUrl: '',
|
apiUrl: '',
|
||||||
@@ -181,7 +177,6 @@ onMounted(async () => {
|
|||||||
wpVersion: data.wp_version || '',
|
wpVersion: data.wp_version || '',
|
||||||
phpVersion: data.php_version || '',
|
phpVersion: data.php_version || '',
|
||||||
dbSchemaVersion: data.db_schema_version || '',
|
dbSchemaVersion: data.db_schema_version || '',
|
||||||
settingsMigrationVersion: data.settings_migration_version || '',
|
|
||||||
emailBackfillDone: !!data.email_backfill_done,
|
emailBackfillDone: !!data.email_backfill_done,
|
||||||
siteUrl: data.site_url || window.aksrtAdminData?.siteUrl || '',
|
siteUrl: data.site_url || window.aksrtAdminData?.siteUrl || '',
|
||||||
apiUrl: data.api_url || window.aksrtAdminData?.apiUrl || '',
|
apiUrl: data.api_url || window.aksrtAdminData?.apiUrl || '',
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="aksrt-page-container">
|
|
||||||
<PageHeader
|
|
||||||
title="迁移状态"
|
|
||||||
desc="查看数据库 schema 版本、设置迁移版本和迁移日志,方便发布前确认历史兼容层状态。"
|
|
||||||
>
|
|
||||||
<template #actions>
|
|
||||||
<n-space>
|
|
||||||
<n-button quaternary @click="go('/tools/health')">健康检查</n-button>
|
|
||||||
<n-button quaternary @click="go('/tools/import-export')">导入导出</n-button>
|
|
||||||
</n-space>
|
|
||||||
</template>
|
|
||||||
</PageHeader>
|
|
||||||
|
|
||||||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
|
||||||
<n-card class="aksrt-section-card">
|
|
||||||
<div class="aksrt-section-header">
|
|
||||||
<h3>版本摘要</h3>
|
|
||||||
</div>
|
|
||||||
<n-space>
|
|
||||||
<n-tag round type="info">DB Schema:{{ status.schema_version || '0.0.0' }}</n-tag>
|
|
||||||
<n-tag round type="info">Settings Migration:{{ status.migration_version || '0.0.0' }}</n-tag>
|
|
||||||
<n-tag round :type="logItems.length ? 'success' : 'default'">迁移日志:{{ logItems.length }} 条</n-tag>
|
|
||||||
</n-space>
|
|
||||||
</n-card>
|
|
||||||
|
|
||||||
<n-card class="aksrt-section-card">
|
|
||||||
<n-alert type="info" :show-icon="false">
|
|
||||||
迁移说明文档位于 `docs/migration-map.md`。如果这里的 schema/version 与文档记录不一致,发布前应先补齐说明。
|
|
||||||
</n-alert>
|
|
||||||
</n-card>
|
|
||||||
|
|
||||||
<n-card class="aksrt-section-card">
|
|
||||||
<div class="aksrt-section-header">
|
|
||||||
<h3>迁移日志</h3>
|
|
||||||
</div>
|
|
||||||
<div v-if="logItems.length" class="aksrt-migration-log">
|
|
||||||
<div v-for="(item, index) in logItems" :key="index" class="aksrt-migration-log__item">
|
|
||||||
<pre>{{ stringifyItem(item) }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<n-empty v-else description="暂无迁移日志" />
|
|
||||||
</n-card>
|
|
||||||
</n-spin>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { computed, onMounted, ref } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { useMessage } from 'naive-ui'
|
|
||||||
import api from '@/api'
|
|
||||||
import PageHeader from '@/components/PageHeader.vue'
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const message = useMessage()
|
|
||||||
|
|
||||||
const loading = ref(true)
|
|
||||||
const status = ref({})
|
|
||||||
|
|
||||||
const logItems = computed(() => {
|
|
||||||
return Array.isArray(status.value.migration_log) ? status.value.migration_log : []
|
|
||||||
})
|
|
||||||
|
|
||||||
function go(path) {
|
|
||||||
router.push(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractData(response) {
|
|
||||||
return response?.data ?? response ?? {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringifyItem(item) {
|
|
||||||
if (typeof item === 'string') {
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
return JSON.stringify(item, null, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function load() {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
status.value = extractData(await api.getMigrationStatus())
|
|
||||||
} catch (error) {
|
|
||||||
message.error(error.message || '加载迁移状态失败')
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(load)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.aksrt-migration-log {
|
|
||||||
display: grid;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aksrt-migration-log__item pre {
|
|
||||||
margin: 0;
|
|
||||||
padding: 12px 14px;
|
|
||||||
border-radius: 12px;
|
|
||||||
background: #101828;
|
|
||||||
color: #d0d7e2;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
export const toolsPageLoaders = {
|
export const toolsPageLoaders = {
|
||||||
ToolsImportExport: () => import('@/pages/tools/ToolsImportExport.vue'),
|
ToolsImportExport: () => import('@/pages/tools/ToolsImportExport.vue'),
|
||||||
ToolsHealth: () => import('@/pages/tools/ToolsHealth.vue'),
|
ToolsHealth: () => import('@/pages/tools/ToolsHealth.vue'),
|
||||||
ToolsMigration: () => import('@/pages/tools/ToolsMigration.vue'),
|
|
||||||
ToolsEmailRollback: () => import('@/pages/tools/ToolsEmailRollback.vue'),
|
ToolsEmailRollback: () => import('@/pages/tools/ToolsEmailRollback.vue'),
|
||||||
ToolsUpdate: () => import('@/pages/tools/ToolsUpdate.vue'),
|
ToolsUpdate: () => import('@/pages/tools/ToolsUpdate.vue'),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
export const migrationSchema = {
|
|
||||||
key: 'tools.migration',
|
|
||||||
title: '数据迁移',
|
|
||||||
icon: 'fas fa-database',
|
|
||||||
description: '数据库结构迁移和版本升级。',
|
|
||||||
defaults: {},
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
key: 'status',
|
|
||||||
title: '迁移状态',
|
|
||||||
icon: 'fas fa-info-circle',
|
|
||||||
fields: [
|
|
||||||
{ key: 'current_version', label: '当前版本', type: 'display' },
|
|
||||||
{ key: 'pending_migrations', label: '待执行迁移', type: 'display' },
|
|
||||||
{ key: 'run_migration', label: '执行迁移', type: 'button', help: '手动触发数据库迁移' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
@@ -71,13 +71,6 @@ class AKSRT_Admin_Import_Export_Controller extends AKSRT_Admin_Controller_Base {
|
|||||||
'permission_callback' => [$this, 'check_permission'],
|
'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)
|
// Schema introspection (for frontend to discover available fields)
|
||||||
register_rest_route(self::API_NAMESPACE, '/settings/schema/(?P<domain>[a-z_]+)', [
|
register_rest_route(self::API_NAMESPACE, '/settings/schema/(?P<domain>[a-z_]+)', [
|
||||||
'methods' => 'GET',
|
'methods' => 'GET',
|
||||||
@@ -401,8 +394,4 @@ class AKSRT_Admin_Import_Export_Controller extends AKSRT_Admin_Controller_Base {
|
|||||||
|
|
||||||
return $this->success(['checks' => $checks]);
|
return $this->success(['checks' => $checks]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Migration status — reports schema version and pending migrations.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
-11
@@ -3,17 +3,6 @@ defined('ABSPATH') || exit;
|
|||||||
|
|
||||||
trait AKSRT_Admin_Import_Export_Controller_Part_1 {
|
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).
|
* Get the schema definition for a domain (for frontend introspection).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class AKSRT_Admin_Schema_Global {
|
|||||||
'key' => 'logo',
|
'key' => 'logo',
|
||||||
'title' => 'LOGO图像',
|
'title' => 'LOGO图像',
|
||||||
'version' => '1.0.0',
|
'version' => '1.0.0',
|
||||||
'option_key' => 'aksrt_seo_settings',
|
'option_key' => 'aksrt_settings',
|
||||||
'groups' => [
|
'groups' => [
|
||||||
['key' => 'logo', 'title' => 'Logo 设置', 'fields' => [
|
['key' => 'logo', 'title' => 'Logo 设置', 'fields' => [
|
||||||
['key' => 'site_logo', 'label' => '站点 Logo', 'type' => 'media', 'default' => ''],
|
['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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -66,7 +66,7 @@ class AKSRT_Settings {
|
|||||||
*/
|
*/
|
||||||
public static function on_option_updated(string $option_name): void {
|
public static function on_option_updated(string $option_name): void {
|
||||||
$tracked = array_merge(
|
$tracked = array_merge(
|
||||||
['aksrt_settings', 'aksrt_basic_settings'],
|
['aksrt_settings'],
|
||||||
self::STANDALONE_OPTION_KEYS
|
self::STANDALONE_OPTION_KEYS
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -95,19 +95,14 @@ class AKSRT_Settings {
|
|||||||
return self::$cached_all;
|
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', []);
|
$settings = get_option('aksrt_settings', []);
|
||||||
$seo = get_option('aksrt_seo_settings', []);
|
if (!is_array($settings)) {
|
||||||
$basic = get_option('aksrt_basic_settings', []);
|
$settings = [];
|
||||||
|
}
|
||||||
$merged = array_merge(
|
self::$cached_all = $settings;
|
||||||
is_array($settings) ? $settings : [],
|
return $settings;
|
||||||
is_array($seo) ? $seo : [],
|
|
||||||
is_array($basic) ? $basic : []
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!is_array($merged)) $merged = [];
|
|
||||||
self::$cached_all = $merged;
|
|
||||||
return $merged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,7 +121,6 @@ class AKSRT_Settings {
|
|||||||
* 用于导入导出完整性检查。
|
* 用于导入导出完整性检查。
|
||||||
*/
|
*/
|
||||||
public const STANDALONE_OPTION_KEYS = [
|
public const STANDALONE_OPTION_KEYS = [
|
||||||
'aksrt_seo_settings',
|
|
||||||
'aksrt_mail_smtp',
|
'aksrt_mail_smtp',
|
||||||
'aksrt_oauth',
|
'aksrt_oauth',
|
||||||
'aksrt_captcha_config',
|
'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 {
|
public static function maybe_sync_native_site_icon(): void {
|
||||||
$custom = self::custom_favicon_url();
|
$custom = self::custom_favicon_url();
|
||||||
if ($custom === '') {
|
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 {
|
public static function invite_registration_enabled(): bool {
|
||||||
return AKSRT_Settings_Credits_Runtime::invite_registration_enabled();
|
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 {
|
public static function invite_registration_enabled(): bool {
|
||||||
return !empty(self::get_invite_registration_config()['enabled']);
|
return !empty(self::get_invite_registration_config()['enabled']);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ defined('ABSPATH') || exit;
|
|||||||
trait AKSRT_Settings_Display_Page_Groups {
|
trait AKSRT_Settings_Display_Page_Groups {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 SEO 设置(从 aksrt_seo_settings option 读取)
|
* 获取 SEO 设置(从 aksrt_settings 读取)
|
||||||
*/
|
*/
|
||||||
public static function get_seo_settings(): array {
|
public static function get_seo_settings(): array {
|
||||||
$s = self::get_all();
|
$s = self::get_all();
|
||||||
|
|||||||
Reference in New Issue
Block a user