From 8fddc33156da3d96ba69173b6cb9cd9faabeeb6e Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 11 Jul 2026 15:14:22 +0800 Subject: [PATCH] feat(homepage): align homepage settings with Zibll main-list keys Move /settings/homepage onto a dedicated REST trait that stores Zibll option IDs (home_posts_list_s, index_list_title, home_lists, exclude posts/cats, list1 orderby). Reader exposes both canonical keys and temporary aliases for existing front-end helpers; save path drops superseded AKSRT-only keys. HomepageSettings.vue binds to the new contract while remaining a Vue custom page. --- .../src/pages/content/HomepageSettings.vue | 99 +++--- .../src/schema/sections/page-display/index.js | 20 +- inc/bootstrap.php | 1 + .../class-aksrt-admin-global-controller.php | 1 + ...t-aksrt-admin-global-controller-part-2.php | 122 ------- ...ait-aksrt-admin-homepage-settings-rest.php | 312 ++++++++++++++++++ .../class-aksrt-settings-home-cms.php | 108 ++++-- 7 files changed, 467 insertions(+), 196 deletions(-) create mode 100644 inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-homepage-settings-rest.php diff --git a/assets/admin/src/pages/content/HomepageSettings.vue b/assets/admin/src/pages/content/HomepageSettings.vue index 51ac614a..0ca5bf41 100644 --- a/assets/admin/src/pages/content/HomepageSettings.vue +++ b/assets/admin/src/pages/content/HomepageSettings.vue @@ -41,19 +41,19 @@ - + - - + + - - + + - - + + - + 内联链接 @@ -61,9 +61,9 @@ - + - + - + @@ -112,11 +112,11 @@ -
- 暂无 Tab 配置,点击“添加 Tab”创建首页分类切换。 +
+ 暂无更多栏目,点击“添加栏目”创建分类/专题 Tab。
-
+
(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 diff --git a/assets/admin/src/schema/sections/page-display/index.js b/assets/admin/src/schema/sections/page-display/index.js index 8054bd6c..ee095f94 100644 --- a/assets/admin/src/schema/sections/page-display/index.js +++ b/assets/admin/src/schema/sections/page-display/index.js @@ -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 }, diff --git a/inc/bootstrap.php b/inc/bootstrap.php index 90a036e4..481bd6e4 100644 --- a/inc/bootstrap.php +++ b/inc/bootstrap.php @@ -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'; diff --git a/inc/classes/admin/class-aksrt-admin-global-controller.php b/inc/classes/admin/class-aksrt-admin-global-controller.php index a908023d..b45969fe 100644 --- a/inc/classes/admin/class-aksrt-admin-global-controller.php +++ b/inc/classes/admin/class-aksrt-admin-global-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; diff --git a/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-global-controller-part-2.php b/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-global-controller-part-2.php index 10f9a3e6..492b04d3 100644 --- a/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-global-controller-part-2.php +++ b/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-global-controller-part-2.php @@ -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(); diff --git a/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-homepage-settings-rest.php b/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-homepage-settings-rest.php new file mode 100644 index 00000000..755f642a --- /dev/null +++ b/inc/classes/admin/global-ctrl-traits/trait-aksrt-admin-homepage-settings-rest.php @@ -0,0 +1,312 @@ +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 $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 + */ + 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; + } +} diff --git a/inc/classes/settings/class-aksrt-settings-home-cms.php b/inc/classes/settings/class-aksrt-settings-home-cms.php index 34c874e0..a9e1f397 100644 --- a/inc/classes/settings/class-aksrt-settings-home-cms.php +++ b/inc/classes/settings/class-aksrt-settings-home-cms.php @@ -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)) {