Merge pull request 'feat(homepage): align homepage settings with Zibll main-list keys' (#49) from worktree-homepage-zibll-contract into main

Reviewed-on: CYL/wordpress-theme-aksrt#49
This commit is contained in:
2026-07-11 15:19:47 +08:00
7 changed files with 467 additions and 196 deletions
@@ -41,19 +41,19 @@
<template #header><strong>主列表</strong></template>
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form">
<n-form-item label="启用主列表">
<n-switch v-model:value="form.home_posts_list_enabled" />
<n-switch v-model:value="form.home_posts_list_s" />
<template #feedback><span class="aksrt-hint-text">首页主内容区保留 Zibll 式内容流,不建议关闭。</span></template>
</n-form-item>
<n-form-item label="区块标题">
<n-input v-model:value="form.home_list_title" placeholder="最新发布" />
<n-form-item label="显示标题">
<n-input v-model:value="form.index_list_title" placeholder="最新发布" />
</n-form-item>
<n-form-item label="默认排序">
<n-select v-model:value="form.homepage_default_sort" :options="allSortOptions" />
<n-form-item label="主栏目默认排序">
<n-select v-model:value="form.home_list1_orderby_option.orderby" :options="allSortOptions" />
</n-form-item>
<n-form-item label="启用排序栏">
<n-switch v-model:value="form.home_list_sort_enabled" />
<n-form-item label="显示排序方式按钮">
<n-switch v-model:value="form.home_list1_orderby_s" />
</n-form-item>
<n-form-item v-if="form.home_list_sort_enabled" label="排序栏样式">
<n-form-item v-if="form.home_list1_orderby_s" label="排序栏样式">
<n-radio-group v-model:value="form.home_list_sort_dropdown">
<n-space size="large">
<n-radio-button :value="false">内联链接</n-radio-button>
@@ -61,9 +61,9 @@
</n-space>
</n-radio-group>
</n-form-item>
<n-form-item v-if="form.home_list_sort_enabled" label="可用排序选项">
<n-form-item v-if="form.home_list1_orderby_s" label="排序方式选项">
<n-select
v-model:value="form.home_list_sort_options"
v-model:value="form.home_list1_orderby_option.options"
:options="allSortOptions"
multiple
placeholder="选择排序选项"
@@ -75,7 +75,7 @@
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header><strong>排除规则</strong></template>
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form">
<n-form-item label="排除文章 ID">
<n-form-item label="排除文章">
<n-input
v-model:value="excludePostIdsText"
type="textarea"
@@ -84,7 +84,7 @@
/>
<template #feedback><span class="aksrt-hint-text">主列表和首页 Tab 查询均排除这些文章。</span></template>
</n-form-item>
<n-form-item label="排除分类 ID">
<n-form-item label="排除分类">
<n-input
v-model:value="excludeCategoryIdsText"
type="textarea"
@@ -99,8 +99,8 @@
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header>
<div style="display:flex; align-items:center; justify-content:space-between;">
<strong>首页 Tab</strong>
<n-button size="small" @click="addTab">+ 添加 Tab</n-button>
<strong>更多栏目</strong>
<n-button size="small" @click="addTab">+ 添加栏目</n-button>
</div>
</template>
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form" style="margin-bottom:16px;">
@@ -112,11 +112,11 @@
</n-form-item>
</n-form>
<div v-if="form.homepage_tabs.length === 0" class="homepage-settings__empty-tabs">
<n-text depth="3">暂无 Tab 配置,点击“添加 Tab”创建首页分类切换。</n-text>
<div v-if="form.home_lists.length === 0" class="homepage-settings__empty-tabs">
<n-text depth="3">暂无更多栏目,点击“添加栏目”创建分类/专题 Tab。</n-text>
</div>
<div v-for="(tab, index) in form.homepage_tabs" :key="index" class="homepage-settings__tab-row">
<div v-for="(tab, index) in form.home_lists" :key="index" class="homepage-settings__tab-row">
<div class="homepage-settings__tab-fields">
<n-select
:value="tab.term_id"
@@ -242,50 +242,52 @@ const allSortOptions = [
const form = reactive({
homepage_content_model: 'mixed',
homepage_tabs: [],
home_posts_list_s: true,
home_list1_orderby_s: true,
home_list1_orderby_option: {
orderby: 'modified',
options: ['modified', 'date', 'views', 'likes', 'comments'],
},
index_list_title: '最新发布',
home_exclude_posts: [],
home_exclude_cats: [],
home_lists: [],
homepage_card_style: 'default',
homepage_multi_thumb_enabled: true,
homepage_multi_thumb_min_images: 3,
homepage_sidebar_mini_enabled: true,
homepage_default_sort: 'modified',
homepage_default_view: 'list',
homepage_sort_ajax_enabled: true,
homepage_sticky_tabs_enabled: true,
home_posts_list_enabled: true,
home_list_title: '最新发布',
home_list_sort_enabled: true,
home_list_sort_options: ['modified', 'date', 'views', 'likes', 'comments'],
home_list_sort_dropdown: false,
home_exclude_post_ids: [],
home_exclude_category_ids: [],
homepage_tab_posts_per_page: 6,
homepage_tab_limit: 4,
})
const excludePostIdsText = computed({
get: () => (form.home_exclude_post_ids || []).join(','),
get: () => (form.home_exclude_posts || []).join(','),
set: (val) => {
form.home_exclude_post_ids = val.split(',').map(s => parseInt(s.trim(), 10)).filter(n => n > 0)
form.home_exclude_posts = val.split(',').map(s => parseInt(s.trim(), 10)).filter(n => n > 0)
},
})
const excludeCategoryIdsText = computed({
get: () => (form.home_exclude_category_ids || []).join(','),
get: () => (form.home_exclude_cats || []).join(','),
set: (val) => {
form.home_exclude_category_ids = val.split(',').map(s => parseInt(s.trim(), 10)).filter(n => n > 0)
form.home_exclude_cats = val.split(',').map(s => parseInt(s.trim(), 10)).filter(n => n > 0)
},
})
function addTab() {
form.homepage_tabs.push({ term_id: 0, title: '', orderby: 'date', enabled: true })
form.home_lists.push({ term_id: 0, title: '', orderby: 'date', enabled: true })
}
function removeTab(index) {
form.homepage_tabs.splice(index, 1)
form.home_lists.splice(index, 1)
}
function updateTab(index, field, value) {
form.homepage_tabs[index][field] = value
form.home_lists[index][field] = value
}
async function loadCategories() {
@@ -308,27 +310,38 @@ async function loadSettings() {
const d = res?.data || {}
form.homepage_content_model = d.homepage_content_model || 'mixed'
form.homepage_tabs = Array.isArray(d.homepage_tabs) ? d.homepage_tabs : []
form.home_posts_list_s = d.home_posts_list_s !== false && d.home_posts_list_enabled !== false
form.home_list1_orderby_s = d.home_list1_orderby_s !== false && d.home_list_sort_enabled !== false
const orderOpt = d.home_list1_orderby_option && typeof d.home_list1_orderby_option === 'object' ? d.home_list1_orderby_option : {}
form.home_list1_orderby_option = {
orderby: orderOpt.orderby || d.homepage_default_sort || 'modified',
options: Array.isArray(orderOpt.options) && orderOpt.options.length
? orderOpt.options
: (Array.isArray(d.home_list_sort_options) && d.home_list_sort_options.length
? d.home_list_sort_options
: ['modified', 'date', 'views', 'likes', 'comments']),
}
form.index_list_title = d.index_list_title || d.home_list_title || '最新发布'
form.home_exclude_posts = Array.isArray(d.home_exclude_posts)
? d.home_exclude_posts
: (Array.isArray(d.home_exclude_post_ids) ? d.home_exclude_post_ids : [])
form.home_exclude_cats = Array.isArray(d.home_exclude_cats)
? d.home_exclude_cats
: (Array.isArray(d.home_exclude_category_ids) ? d.home_exclude_category_ids : [])
form.home_lists = Array.isArray(d.home_lists)
? d.home_lists
: (Array.isArray(d.homepage_tabs) ? d.homepage_tabs : [])
form.homepage_card_style = d.homepage_card_style || 'default'
form.homepage_multi_thumb_enabled = d.homepage_multi_thumb_enabled !== false
form.homepage_multi_thumb_min_images = d.homepage_multi_thumb_min_images || 3
form.homepage_sidebar_mini_enabled = d.homepage_sidebar_mini_enabled !== false
form.homepage_default_sort = d.homepage_default_sort || 'modified'
form.homepage_default_view = d.homepage_default_view || 'list'
form.homepage_sort_ajax_enabled = d.homepage_sort_ajax_enabled !== false
form.homepage_sticky_tabs_enabled = d.homepage_sticky_tabs_enabled !== false
form.home_posts_list_enabled = d.home_posts_list_enabled !== false
form.home_list_title = d.home_list_title || '最新发布'
form.home_list_sort_enabled = d.home_list_sort_enabled !== false
form.home_list_sort_options = Array.isArray(d.home_list_sort_options) && d.home_list_sort_options.length
? d.home_list_sort_options
: ['modified', 'date', 'views', 'likes', 'comments']
form.home_list_sort_dropdown = !!d.home_list_sort_dropdown
form.home_exclude_post_ids = Array.isArray(d.home_exclude_post_ids) ? d.home_exclude_post_ids : []
form.home_exclude_category_ids = Array.isArray(d.home_exclude_category_ids) ? d.home_exclude_category_ids : []
form.homepage_tab_posts_per_page = d.homepage_tab_posts_per_page || 6
form.homepage_tab_limit = d.homepage_tab_limit || 4
} catch (error) {
} catch (error) {
message.error(error.message || '加载设置失败')
} finally {
loading.value = false
@@ -941,7 +941,7 @@ export const pageDisplaySchemas = {
homepage_default_view: 'list',
homepage_sort_ajax_enabled: true,
homepage_sticky_tabs_enabled: true,
home_posts_list_enabled: true,
home_posts_list_s: true,
home_list_title: '最新发布',
home_list_sort_enabled: true,
home_list_sort_options: ['modified', 'date', 'views', 'likes', 'comments'],
@@ -975,12 +975,12 @@ export const pageDisplaySchemas = {
title: '主列表',
icon: 'fas fa-list',
fields: [
{ key: 'home_posts_list_enabled', label: '启用主列表', type: 'switch', default: true },
{ key: 'home_list_title', label: '区块标题', type: 'input', default: '最新发布', dependsOn: { key: 'home_posts_list_enabled', value: true } },
{ key: 'homepage_default_sort', label: '默认排序', type: 'select', default: 'modified', dependsOn: { key: 'home_posts_list_enabled', value: true }, options: sortOptions },
{ key: 'home_list_sort_enabled', label: '启用排序栏', type: 'switch', default: true, dependsOn: { key: 'home_posts_list_enabled', value: true } },
{ key: 'home_list_sort_dropdown', label: '排序栏下拉模式', type: 'switch', default: false, dependsOn: { key: 'home_list_sort_enabled', value: true } },
{ key: 'home_list_sort_options', label: '可用排序选项', type: 'checkbox', default: ['modified', 'date', 'views', 'likes', 'comments'], dependsOn: { key: 'home_list_sort_enabled', value: true }, options: sortOptions },
{ key: 'home_posts_list_s', label: '启用主列表', type: 'switch', default: true },
{ key: 'index_list_title', label: '区块标题', type: 'input', default: '最新发布', dependsOn: { key: 'home_posts_list_s', value: true } },
{ key: 'home_list1_orderby_option.orderby', label: '默认排序', type: 'select', default: 'modified', dependsOn: { key: 'home_posts_list_s', value: true }, options: sortOptions },
{ key: 'home_list1_orderby_s', label: '启用排序栏', type: 'switch', default: true, dependsOn: { key: 'home_posts_list_s', value: true } },
{ key: 'home_list_sort_dropdown', label: '排序栏下拉模式', type: 'switch', default: false, dependsOn: { key: 'home_list1_orderby_s', value: true } },
{ key: 'home_list1_orderby_option', label: '可用排序选项', type: 'checkbox', default: ['modified', 'date', 'views', 'likes', 'comments'], dependsOn: { key: 'home_list1_orderby_s', value: true }, options: sortOptions },
],
},
{
@@ -988,8 +988,8 @@ export const pageDisplaySchemas = {
title: '排除规则',
icon: 'fas fa-filter',
fields: [
{ key: 'home_exclude_post_ids', label: '排除文章 ID', type: 'array', default: [], help: '主列表和 Tab 查询均排除这些文章。' },
{ key: 'home_exclude_category_ids', label: '排除分类 ID', type: 'array', default: [], help: '主列表排除这些分类。' },
{ key: 'home_exclude_posts', label: '排除文章 ID', type: 'array', default: [], help: '主列表和 Tab 查询均排除这些文章。' },
{ key: 'home_exclude_cats', label: '排除分类 ID', type: 'array', default: [], help: '主列表排除这些分类。' },
],
},
{
@@ -997,7 +997,7 @@ export const pageDisplaySchemas = {
title: '首页 Tab',
icon: 'fas fa-tags',
fields: [
{ key: 'homepage_tabs', label: '首页 Tab', type: 'array', default: [], help: '分类 Tab 由 HomepageSettings.vue 中的可视化编辑器维护。' },
{ key: 'home_lists', label: '首页 Tab', type: 'array', default: [], help: '分类 Tab 由 HomepageSettings.vue 中的可视化编辑器维护。' },
{ key: 'homepage_tab_limit', label: 'Tab 数量上限', type: 'number', default: 4, min: 1, max: 12 },
{ key: 'homepage_tab_posts_per_page', label: '每 Tab 文章数', type: 'number', default: 6, min: 1, max: 20 },
{ key: 'homepage_sticky_tabs_enabled', label: 'Tab 吸顶', type: 'switch', default: true },
+1
View File
@@ -98,6 +98,7 @@ require_once AKSRT_DIR . '/inc/classes/admin/class-aksrt-admin-shop-controller-c
require_once AKSRT_DIR . '/inc/classes/admin/class-aksrt-admin-shop-controller-variant-export-operations.php';
require_once AKSRT_DIR . '/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-global-controller-part-1.php';
require_once AKSRT_DIR . '/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-global-controller-part-2.php';
require_once AKSRT_DIR . '/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-homepage-settings-rest.php';
require_once AKSRT_DIR . '/inc/classes/admin/class-aksrt-admin-global-controller.php';
require_once AKSRT_DIR . '/inc/classes/admin/class-aksrt-admin-page-display-controller.php';
require_once AKSRT_DIR . '/inc/classes/admin/class-aksrt-admin-post-list-controller.php';
@@ -14,6 +14,7 @@ defined('ABSPATH') || exit;
class AKSRT_Admin_Global_Controller extends AKSRT_Admin_Controller_Base {
use AKSRT_Admin_Global_Controller_Part_1;
use AKSRT_Admin_Global_Controller_Part_2;
use AKSRT_Admin_Homepage_Settings_Rest;
private static $instance = null;
@@ -3,128 +3,6 @@ defined('ABSPATH') || exit;
trait AKSRT_Admin_Global_Controller_Part_2 {
public function rest_handle_homepage_settings(WP_REST_Request $request): WP_REST_Response {
$option_key = 'aksrt_settings';
if ($request->get_method() === 'GET') {
$data = AKSRT_Settings::get_homepage_fixed_settings();
return rest_ensure_response([
'code' => 'success',
'data' => $data,
]);
}
$params = $this->get_json_params($request);
if (empty($params)) {
$params = $request->get_params();
}
$allowed_sorts = AKSRT_Settings::homepage_allowed_sorts();
$settings = [
'homepage_card_style' => in_array($params['homepage_card_style'] ?? '', ['default', 'style2', 'style3'], true)
? $params['homepage_card_style']
: 'default',
'homepage_multi_thumb_enabled' => !isset($params['homepage_multi_thumb_enabled']) || !empty($params['homepage_multi_thumb_enabled']),
'homepage_multi_thumb_min_images' => max(2, min(4, (int) ($params['homepage_multi_thumb_min_images'] ?? 3))),
'homepage_sidebar_mini_enabled' => !isset($params['homepage_sidebar_mini_enabled']) || !empty($params['homepage_sidebar_mini_enabled']),
'homepage_default_sort' => in_array($params['homepage_default_sort'] ?? '', $allowed_sorts, true)
? $params['homepage_default_sort']
: 'modified',
'homepage_default_view' => in_array($params['homepage_default_view'] ?? '', ['list', 'card'], true)
? $params['homepage_default_view']
: 'list',
'homepage_sort_ajax_enabled' => !isset($params['homepage_sort_ajax_enabled']) || !empty($params['homepage_sort_ajax_enabled']),
'homepage_sticky_tabs_enabled' => !isset($params['homepage_sticky_tabs_enabled']) || !empty($params['homepage_sticky_tabs_enabled']),
'homepage_content_model' => in_array($params['homepage_content_model'] ?? '', ['post', 'mixed'], true)
? $params['homepage_content_model']
: 'mixed',
'home_posts_list_enabled' => !isset($params['home_posts_list_enabled']) || !empty($params['home_posts_list_enabled']),
'home_list_title' => sanitize_text_field((string) ($params['home_list_title'] ?? __('Latest Posts', 'aksrt'))),
'home_list_sort_enabled' => !isset($params['home_list_sort_enabled']) || !empty($params['home_list_sort_enabled']),
'home_list_sort_dropdown' => !empty($params['home_list_sort_dropdown']),
'homepage_tab_posts_per_page' => max(1, min(20, (int) ($params['homepage_tab_posts_per_page'] ?? 6))),
'homepage_tab_limit' => max(1, min(12, (int) ($params['homepage_tab_limit'] ?? 4))),
];
if (isset($params['home_list_sort_options']) && is_array($params['home_list_sort_options'])) {
$seen = [];
$options = [];
foreach ($params['home_list_sort_options'] as $key) {
$key = sanitize_key((string) $key);
if (in_array($key, $allowed_sorts, true) && !isset($seen[$key])) {
$options[] = $key;
$seen[$key] = true;
}
}
$settings['home_list_sort_options'] = !empty($options) ? $options : ['modified', 'date', 'views', 'likes', 'comments'];
}
if (isset($params['home_exclude_post_ids'])) {
$settings['home_exclude_post_ids'] = array_values(array_filter(
array_map('absint', (array) $params['home_exclude_post_ids']),
static fn($value) => $value > 0
));
}
if (isset($params['home_exclude_category_ids'])) {
$settings['home_exclude_category_ids'] = array_values(array_filter(
array_map('absint', (array) $params['home_exclude_category_ids']),
static fn($value) => $value > 0
));
}
if (isset($params['homepage_tabs']) && is_array($params['homepage_tabs'])) {
$tabs = [];
foreach ($params['homepage_tabs'] as $tab) {
if (!is_array($tab)) {
continue;
}
$term_id = absint($tab['term_id'] ?? 0);
if ($term_id <= 0) {
continue;
}
$term = get_term($term_id, 'category');
if (!$term || is_wp_error($term)) {
continue;
}
$orderby = sanitize_key($tab['orderby'] ?? 'date');
if (!in_array($orderby, $allowed_sorts, true)) {
$orderby = 'date';
}
$tabs[] = [
'term_id' => $term_id,
'title' => sanitize_text_field($tab['title'] ?? ''),
'orderby' => $orderby,
'enabled' => !empty($tab['enabled']),
];
}
$settings['homepage_tabs'] = $tabs;
}
$current = get_option($option_key, []);
if (!is_array($current)) {
$current = [];
}
foreach ($settings as $key => $value) {
$current[$key] = $value;
}
update_option($option_key, $current);
AKSRT_Settings::flush_settings_cache();
update_option('aksrt_homepage_schema_version', gmdate('Y-m-d'));
delete_transient('aksrt_homepage_cached_images');
do_action('aksrt_homepage_settings_changed');
return rest_ensure_response([
'code' => 'success',
'message' => __('Homepage settings saved.', 'aksrt'),
'data' => $settings,
]);
}
public function rest_handle_category_recommend(WP_REST_Request $request): WP_REST_Response {
if ($request->get_method() === 'GET') {
$settings = AKSRT_Settings::get_category_recommend_settings();
@@ -0,0 +1,312 @@
<?php
/**
* Homepage settings REST — Zibll-aligned storage keys for the main list / tabs contract.
*
* Canonical keys (aligned with Zibll option IDs):
* - home_posts_list_s
* - home_list1_orderby_s
* - home_list1_orderby_option
* - index_list_title
* - home_exclude_posts
* - home_exclude_cats
* - home_lists
*
* AKSRT-only presentation keys remain optional (card style, multi-thumb, content model).
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
trait AKSRT_Admin_Homepage_Settings_Rest {
public function rest_handle_homepage_settings(WP_REST_Request $request): WP_REST_Response {
$option_key = 'aksrt_settings';
if ($request->get_method() === 'GET') {
return rest_ensure_response([
'code' => 'success',
'data' => AKSRT_Settings_Home_Cms::get_homepage_fixed_settings(),
]);
}
$params = $this->get_json_params($request);
if (empty($params)) {
$params = $request->get_params();
}
if (!is_array($params)) {
$params = [];
}
$allowed_sorts = AKSRT_Settings_Home_Cms::homepage_allowed_sorts();
$settings = [];
// --- Zibll main list contract ---
if (array_key_exists('home_posts_list_s', $params) || array_key_exists('home_posts_list_enabled', $params)) {
$settings['home_posts_list_s'] = array_key_exists('home_posts_list_s', $params)
? !empty($params['home_posts_list_s'])
: !empty($params['home_posts_list_enabled']);
}
if (array_key_exists('home_list1_orderby_s', $params) || array_key_exists('home_list_sort_enabled', $params)) {
$settings['home_list1_orderby_s'] = array_key_exists('home_list1_orderby_s', $params)
? !empty($params['home_list1_orderby_s'])
: !empty($params['home_list_sort_enabled']);
}
if (isset($params['home_list1_orderby_option']) && is_array($params['home_list1_orderby_option'])) {
$settings['home_list1_orderby_option'] = $this->sanitize_home_list1_orderby_option(
$params['home_list1_orderby_option'],
$allowed_sorts
);
} elseif (isset($params['home_list_sort_options']) && is_array($params['home_list_sort_options'])) {
$settings['home_list1_orderby_option'] = $this->sanitize_home_list1_orderby_option(
[
'orderby' => $params['homepage_default_sort'] ?? 'modified',
'options' => $params['home_list_sort_options'],
],
$allowed_sorts
);
} elseif (isset($params['homepage_default_sort'])) {
$default = sanitize_key((string) $params['homepage_default_sort']);
if (!in_array($default, $allowed_sorts, true)) {
$default = 'modified';
}
$settings['home_list1_orderby_option'] = [
'orderby' => $default,
'options' => array_values(array_unique(array_merge([$default], ['date', 'views', 'likes', 'comments']))),
];
}
if (array_key_exists('index_list_title', $params) || array_key_exists('home_list_title', $params)) {
$title = array_key_exists('index_list_title', $params)
? (string) $params['index_list_title']
: (string) $params['home_list_title'];
$settings['index_list_title'] = sanitize_text_field($title);
}
if (isset($params['home_exclude_posts']) || isset($params['home_exclude_post_ids'])) {
$raw = $params['home_exclude_posts'] ?? $params['home_exclude_post_ids'];
$settings['home_exclude_posts'] = $this->sanitize_id_list($raw);
}
if (isset($params['home_exclude_cats']) || isset($params['home_exclude_category_ids'])) {
$raw = $params['home_exclude_cats'] ?? $params['home_exclude_category_ids'];
$settings['home_exclude_cats'] = $this->sanitize_id_list($raw);
}
if (isset($params['home_lists']) || isset($params['homepage_tabs'])) {
$raw_tabs = $params['home_lists'] ?? $params['homepage_tabs'];
$settings['home_lists'] = $this->sanitize_home_lists($raw_tabs, $allowed_sorts);
}
// --- AKSRT presentation extras (optional, not Zibll dual-write) ---
if (isset($params['homepage_card_style'])) {
$settings['homepage_card_style'] = in_array($params['homepage_card_style'], ['default', 'style2', 'style3'], true)
? $params['homepage_card_style']
: 'default';
}
if (array_key_exists('homepage_multi_thumb_enabled', $params)) {
$settings['homepage_multi_thumb_enabled'] = !empty($params['homepage_multi_thumb_enabled']);
}
if (isset($params['homepage_multi_thumb_min_images'])) {
$settings['homepage_multi_thumb_min_images'] = max(2, min(4, (int) $params['homepage_multi_thumb_min_images']));
}
if (array_key_exists('homepage_sidebar_mini_enabled', $params)) {
$settings['homepage_sidebar_mini_enabled'] = !empty($params['homepage_sidebar_mini_enabled']);
}
if (isset($params['homepage_default_view'])) {
$settings['homepage_default_view'] = in_array($params['homepage_default_view'], ['list', 'card'], true)
? $params['homepage_default_view']
: 'list';
}
if (array_key_exists('homepage_sort_ajax_enabled', $params)) {
$settings['homepage_sort_ajax_enabled'] = !empty($params['homepage_sort_ajax_enabled']);
}
if (array_key_exists('homepage_sticky_tabs_enabled', $params)) {
$settings['homepage_sticky_tabs_enabled'] = !empty($params['homepage_sticky_tabs_enabled']);
}
if (isset($params['homepage_content_model'])) {
$settings['homepage_content_model'] = in_array($params['homepage_content_model'], ['post', 'mixed'], true)
? $params['homepage_content_model']
: 'mixed';
}
if (array_key_exists('home_list_sort_dropdown', $params)) {
$settings['home_list_sort_dropdown'] = !empty($params['home_list_sort_dropdown']);
}
if (isset($params['homepage_tab_posts_per_page'])) {
$settings['homepage_tab_posts_per_page'] = max(1, min(20, (int) $params['homepage_tab_posts_per_page']));
}
if (isset($params['homepage_tab_limit'])) {
$settings['homepage_tab_limit'] = max(1, min(12, (int) $params['homepage_tab_limit']));
}
if (array_key_exists('homepage_module_hero_enabled', $params)) {
$settings['homepage_module_hero_enabled'] = !empty($params['homepage_module_hero_enabled']);
}
if (array_key_exists('homepage_module_banner_enabled', $params)) {
$settings['homepage_module_banner_enabled'] = !empty($params['homepage_module_banner_enabled']);
}
$current = get_option($option_key, []);
if (!is_array($current)) {
$current = [];
}
foreach ($settings as $key => $value) {
$current[$key] = $value;
}
// Drop superseded AKSRT-only keys when canonical Zibll keys are written.
$superseded = [
'home_posts_list_enabled',
'home_list_sort_enabled',
'home_list_sort_options',
'home_list_title',
'home_exclude_post_ids',
'home_exclude_category_ids',
'homepage_tabs',
'homepage_default_sort',
];
foreach ($superseded as $dead_key) {
if (array_key_exists($dead_key, $current) && (
array_key_exists('home_posts_list_s', $settings)
|| array_key_exists('home_list1_orderby_s', $settings)
|| array_key_exists('home_list1_orderby_option', $settings)
|| array_key_exists('index_list_title', $settings)
|| array_key_exists('home_exclude_posts', $settings)
|| array_key_exists('home_exclude_cats', $settings)
|| array_key_exists('home_lists', $settings)
)) {
// Only strip keys we actually replaced in this request.
}
}
if (array_key_exists('home_posts_list_s', $settings)) {
unset($current['home_posts_list_enabled']);
}
if (array_key_exists('home_list1_orderby_s', $settings)) {
unset($current['home_list_sort_enabled']);
}
if (array_key_exists('home_list1_orderby_option', $settings)) {
unset($current['home_list_sort_options'], $current['homepage_default_sort']);
}
if (array_key_exists('index_list_title', $settings)) {
unset($current['home_list_title']);
}
if (array_key_exists('home_exclude_posts', $settings)) {
unset($current['home_exclude_post_ids']);
}
if (array_key_exists('home_exclude_cats', $settings)) {
unset($current['home_exclude_category_ids']);
}
if (array_key_exists('home_lists', $settings)) {
unset($current['homepage_tabs']);
}
update_option($option_key, $current);
if (class_exists('AKSRT_Settings')) {
AKSRT_Settings::flush_settings_cache();
}
update_option('aksrt_homepage_schema_version', gmdate('Y-m-d'));
delete_transient('aksrt_homepage_cached_images');
do_action('aksrt_homepage_settings_changed');
return rest_ensure_response([
'code' => 'success',
'message' => __('首页设置已保存', 'aksrt'),
'data' => AKSRT_Settings_Home_Cms::get_homepage_fixed_settings(),
]);
}
/**
* @param mixed $raw
* @return int[]
*/
private function sanitize_id_list($raw): array {
if (is_string($raw)) {
$parts = preg_split('/[\s,]+/', $raw) ?: [];
$raw = $parts;
}
if (!is_array($raw)) {
return [];
}
return array_values(array_unique(array_filter(array_map('absint', $raw), static fn($id) => $id > 0)));
}
/**
* @param array<string,mixed> $option
* @param string[] $allowed_sorts
* @return array{orderby:string,options:string[]}
*/
private function sanitize_home_list1_orderby_option(array $option, array $allowed_sorts): array {
$orderby = sanitize_key((string) ($option['orderby'] ?? $option['default'] ?? 'modified'));
if (!in_array($orderby, $allowed_sorts, true)) {
$orderby = 'modified';
}
$options = [];
$raw_options = $option['options'] ?? $option['orderby_option'] ?? [];
if (!is_array($raw_options)) {
$raw_options = [];
}
foreach ($raw_options as $key) {
$key = sanitize_key((string) $key);
if (in_array($key, $allowed_sorts, true) && !in_array($key, $options, true)) {
$options[] = $key;
}
}
if ($options === []) {
$options = ['modified', 'date', 'views', 'likes', 'comments'];
}
if (!in_array($orderby, $options, true)) {
array_unshift($options, $orderby);
}
return [
'orderby' => $orderby,
'options' => array_values($options),
];
}
/**
* @param mixed $raw_tabs
* @param string[] $allowed_sorts
* @return array<int, array{term_id:int,title:string,orderby:string,enabled:bool}>
*/
private function sanitize_home_lists($raw_tabs, array $allowed_sorts): array {
if (!is_array($raw_tabs)) {
return [];
}
$tabs = [];
foreach ($raw_tabs as $tab) {
if (!is_array($tab)) {
continue;
}
$term_id = absint($tab['term_id'] ?? 0);
if ($term_id <= 0) {
continue;
}
$term = get_term($term_id);
if (!$term || is_wp_error($term)) {
continue;
}
$taxonomy = (string) $term->taxonomy;
if (!in_array($taxonomy, ['category', 'topics'], true)) {
// Allow category always; topics if registered.
if ($taxonomy !== 'category') {
continue;
}
}
$orderby = sanitize_key((string) ($tab['orderby'] ?? ''));
if ($orderby !== '' && !in_array($orderby, $allowed_sorts, true)) {
$orderby = 'date';
}
$tabs[] = [
'term_id' => $term_id,
'title' => sanitize_text_field((string) ($tab['title'] ?? '')),
'orderby' => $orderby,
'enabled' => !array_key_exists('enabled', $tab) || !empty($tab['enabled']),
];
}
return $tabs;
}
}
@@ -156,28 +156,94 @@ class AKSRT_Settings_Home_Cms {
$s = AKSRT_Settings::get_all();
$allowed_sorts = self::homepage_allowed_sorts();
// Zibll-aligned primary list contract.
$main_list_enabled = array_key_exists('home_posts_list_s', $s)
? !empty($s['home_posts_list_s'])
: (!isset($s['home_posts_list_enabled']) || !empty($s['home_posts_list_enabled']));
$sort_bar_enabled = array_key_exists('home_list1_orderby_s', $s)
? !empty($s['home_list1_orderby_s'])
: (!isset($s['home_list_sort_enabled']) || !empty($s['home_list_sort_enabled']));
$orderby_option = [];
if (isset($s['home_list1_orderby_option']) && is_array($s['home_list1_orderby_option'])) {
$orderby_option = $s['home_list1_orderby_option'];
}
$default_sort = sanitize_key((string) ($orderby_option['orderby'] ?? $s['homepage_default_sort'] ?? 'modified'));
if (!in_array($default_sort, $allowed_sorts, true)) {
$default_sort = 'modified';
}
$sort_options_raw = $orderby_option['options'] ?? $s['home_list_sort_options'] ?? [];
if (!is_array($sort_options_raw)) {
$sort_options_raw = [];
}
$sort_options = self::normalize_sort_options($sort_options_raw);
if (!in_array($default_sort, $sort_options, true)) {
array_unshift($sort_options, $default_sort);
$sort_options = array_values(array_unique($sort_options));
}
$list_title = '';
if (array_key_exists('index_list_title', $s)) {
$list_title = sanitize_text_field((string) $s['index_list_title']);
} elseif (array_key_exists('home_list_title', $s)) {
$list_title = sanitize_text_field((string) $s['home_list_title']);
}
if ($list_title === '') {
$list_title = __('最新发布', 'aksrt');
}
$exclude_posts = self::normalize_int_array(
$s['home_exclude_posts'] ?? $s['home_exclude_post_ids'] ?? []
);
$exclude_cats = self::normalize_int_array(
$s['home_exclude_cats'] ?? $s['home_exclude_category_ids'] ?? []
);
$tabs_raw = [];
if (isset($s['home_lists']) && is_array($s['home_lists'])) {
$tabs_raw = $s['home_lists'];
} elseif (isset($s['homepage_tabs']) && is_array($s['homepage_tabs'])) {
$tabs_raw = $s['homepage_tabs'];
}
$settings = [
'homepage_card_style' => isset($s['homepage_card_style']) ? sanitize_key((string) $s['homepage_card_style']) : 'default',
'homepage_multi_thumb_enabled' => !isset($s['homepage_multi_thumb_enabled']) || !empty($s['homepage_multi_thumb_enabled']),
'homepage_multi_thumb_min_images' => (int) ($s['homepage_multi_thumb_min_images'] ?? 3),
'homepage_sidebar_mini_enabled' => !isset($s['homepage_sidebar_mini_enabled']) || !empty($s['homepage_sidebar_mini_enabled']),
'homepage_default_sort' => isset($s['homepage_default_sort']) && in_array($s['homepage_default_sort'], $allowed_sorts, true) ? $s['homepage_default_sort'] : 'modified',
'homepage_default_view' => isset($s['homepage_default_view']) ? sanitize_key((string) $s['homepage_default_view']) : 'list',
'homepage_sort_ajax_enabled' => !isset($s['homepage_sort_ajax_enabled']) || !empty($s['homepage_sort_ajax_enabled']),
'homepage_sticky_tabs_enabled' => !isset($s['homepage_sticky_tabs_enabled']) || !empty($s['homepage_sticky_tabs_enabled']),
'homepage_content_model' => isset($s['homepage_content_model']) && in_array($s['homepage_content_model'], ['post', 'mixed'], true) ? $s['homepage_content_model'] : 'mixed',
'homepage_tabs' => self::normalize_homepage_tabs(isset($s['homepage_tabs']) && is_array($s['homepage_tabs']) ? $s['homepage_tabs'] : []),
'home_posts_list_enabled' => !isset($s['home_posts_list_enabled']) || !empty($s['home_posts_list_enabled']),
'home_list_title' => isset($s['home_list_title']) ? sanitize_text_field((string) $s['home_list_title']) : __('最新发布', 'aksrt'),
'home_list_sort_enabled' => !isset($s['home_list_sort_enabled']) || !empty($s['home_list_sort_enabled']),
'home_list_sort_options' => self::normalize_sort_options(isset($s['home_list_sort_options']) && is_array($s['home_list_sort_options']) ? $s['home_list_sort_options'] : []),
'home_list_sort_dropdown' => !empty($s['home_list_sort_dropdown']),
'home_exclude_post_ids' => self::normalize_int_array($s['home_exclude_post_ids'] ?? []),
'home_exclude_category_ids' => self::normalize_int_array($s['home_exclude_category_ids'] ?? []),
'homepage_tab_posts_per_page' => max(1, min(20, (int) ($s['homepage_tab_posts_per_page'] ?? 6))),
'homepage_tab_limit' => max(1, min(12, (int) ($s['homepage_tab_limit'] ?? 4))),
'homepage_module_hero_enabled' => !isset($s['homepage_module_hero_enabled']) || !empty($s['homepage_module_hero_enabled']),
'homepage_module_banner_enabled' => !isset($s['homepage_module_banner_enabled']) || !empty($s['homepage_module_banner_enabled']),
// Canonical Zibll keys.
'home_posts_list_s' => $main_list_enabled,
'home_list1_orderby_s' => $sort_bar_enabled,
'home_list1_orderby_option' => [
'orderby' => $default_sort,
'options' => $sort_options,
],
'index_list_title' => $list_title,
'home_exclude_posts' => $exclude_posts,
'home_exclude_cats' => $exclude_cats,
'home_lists' => self::normalize_homepage_tabs($tabs_raw),
// Convenience aliases for existing PHP/Vue callers during cutover of this slice.
'home_posts_list_enabled' => $main_list_enabled,
'home_list_sort_enabled' => $sort_bar_enabled,
'homepage_default_sort' => $default_sort,
'home_list_sort_options' => $sort_options,
'home_list_title' => $list_title,
'home_exclude_post_ids' => $exclude_posts,
'home_exclude_category_ids' => $exclude_cats,
'homepage_tabs' => self::normalize_homepage_tabs($tabs_raw),
// AKSRT presentation extras.
'homepage_card_style' => isset($s['homepage_card_style']) ? sanitize_key((string) $s['homepage_card_style']) : 'default',
'homepage_multi_thumb_enabled' => !isset($s['homepage_multi_thumb_enabled']) || !empty($s['homepage_multi_thumb_enabled']),
'homepage_multi_thumb_min_images' => (int) ($s['homepage_multi_thumb_min_images'] ?? 3),
'homepage_sidebar_mini_enabled' => !isset($s['homepage_sidebar_mini_enabled']) || !empty($s['homepage_sidebar_mini_enabled']),
'homepage_default_view' => isset($s['homepage_default_view']) ? sanitize_key((string) $s['homepage_default_view']) : 'list',
'homepage_sort_ajax_enabled' => !isset($s['homepage_sort_ajax_enabled']) || !empty($s['homepage_sort_ajax_enabled']),
'homepage_sticky_tabs_enabled' => !isset($s['homepage_sticky_tabs_enabled']) || !empty($s['homepage_sticky_tabs_enabled']),
'homepage_content_model' => isset($s['homepage_content_model']) && in_array($s['homepage_content_model'], ['post', 'mixed'], true) ? $s['homepage_content_model'] : 'mixed',
'home_list_sort_dropdown' => !empty($s['home_list_sort_dropdown']),
'homepage_tab_posts_per_page' => max(1, min(20, (int) ($s['homepage_tab_posts_per_page'] ?? 6))),
'homepage_tab_limit' => max(1, min(12, (int) ($s['homepage_tab_limit'] ?? 4))),
'homepage_module_hero_enabled' => !isset($s['homepage_module_hero_enabled']) || !empty($s['homepage_module_hero_enabled']),
'homepage_module_banner_enabled' => !isset($s['homepage_module_banner_enabled']) || !empty($s['homepage_module_banner_enabled']),
];
if (!in_array($settings['homepage_card_style'], ['default', 'style2', 'style3'], true)) {