Files
wordpress-theme-aksrt/src/AKSRT/Settings/Settings.php
T

1008 lines
27 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* @package AKSRT
*/
namespace AKSRT\Settings;
defined('ABSPATH') || exit;
class Settings {
use DomainGroups;
use DisplayPageGroups;
use CreditsPaymentGroups;
use CategoryIntegrationGroups;
use AuthReader;
use HomepageReader;
private static $instance = null;
use FacadeBulk;
/**
* Per-request memoization of merged settings.
*
* 同一请求内多次调用 get_all() 仅读 1 次 option。
* 后端写入 option 时通过 updated_option hook 失效。
*
* @var array|null
*/
private static $cached_all = null;
/**
* 所有独立 option key(非 aksrt_settings)。
* 用于导入导出完整性检查。
*/
public const STANDALONE_OPTION_KEYS = [
'aksrt_mail_smtp',
'aksrt_oauth',
'aksrt_captcha_config',
'aksrt_moderation_config',
'aksrt_footer_settings',
'aksrt_footer_tabbar',
'aksrt_floating_buttons',
'aksrt_credit_settings',
'aksrt_notification_settings',
'aksrt_friend_links',
'aksrt_banners',
'aksrt_category_recommend',
'aksrt_identity_secrets',
];
/**
* 包含 secret 字段的 option key — 空值保留旧值策略。
*/
public const SECRET_OPTION_KEYS = [
'aksrt_mail_smtp',
'aksrt_oauth',
'aksrt_identity_secrets',
];
private function __construct() {}
public static function get_instance(): self {
if (null === self::$instance) self::$instance = new self();
return self::$instance;
}
public function init(): void {
// 注册设置API(可选)
add_action('customize_register', [$this, 'customizer']);
add_filter('get_site_icon_url', [self::class, 'filter_site_icon_url'], 10, 3);
add_action('init', [self::class, 'maybe_sync_native_site_icon'], 20);
// 搜索结果排除(search_no_page / search_exclude_cats)
add_action('pre_get_posts', [self::class, 'filter_search_query']);
// 全局列表默认排序(list_orderby)
add_action('pre_get_posts', [self::class, 'apply_list_orderby']);
// 全局列表每页数量(post_list_per_page)
add_action('pre_get_posts', [self::class, 'apply_list_per_page']);
// 文章发布/更新/删除时清理分类推荐缓存
add_action('save_post', [self::class, 'on_post_changed']);
add_action('delete_post', [self::class, 'on_post_changed']);
// 设置变更时清理 per-request memo
add_action('updated_option', [self::class, 'on_option_updated'], 10, 1);
add_action('added_option', [self::class, 'on_option_updated'], 10, 1);
add_action('deleted_option', [self::class, 'on_option_updated'], 10, 1);
}
/**
* Option 变更时失效缓存(响应所有主题相关 option key)。
*/
public static function on_option_updated(string $option_name): void {
$tracked = array_merge(
['aksrt_settings'],
self::STANDALONE_OPTION_KEYS
);
if (in_array($option_name, $tracked, true)) {
self::$cached_all = null;
}
}
/**
* 文章变更时清理分类推荐缓存
*/
public static function on_post_changed(int $post_id): void {
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) return;
$post = get_post($post_id);
if (!$post || $post->post_type !== 'post') return;
self::flush_category_recommend_cache();
}
// ============================================
// 设置读取方法
// ============================================
/** 获取全部设置(per-request memo) */
public static function get_all(): array {
if (self::$cached_all !== null) {
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', []);
if (!is_array($settings)) {
$settings = [];
}
self::$cached_all = $settings;
return $settings;
}
/**
* 显式刷新缓存(外部直接修改 option 后可调用)。
*/
public static function flush_settings_cache(): void {
self::$cached_all = null;
}
/**
* 读取指定 domain/section 的配置(委托 Schema Provider)。
*
* @param string $domain 域名 (global, page_display, post_list, ...)
* @param string $section 分区名 (可为空,读取整个 domain)
* @return array
*/
public static function read_domain(string $domain, string $section = ''): array {
$provider = \AKSRT\Admin\SchemaProvider::get_instance();
return $provider->read_settings($domain, $section);
}
/**
* 写入指定 domain/section 的配置(委托 Schema Provider)。
*
* 仅写入当前 section allowlist 中的字段,不会覆盖同 option 中其它 section 的字段。
* 写入后自动刷新 memo cache 并触发 action。
*
* @param string $domain 域名
* @param string $section 分区名
* @param array $data 要写入的数据
* @return bool
*/
public static function write_domain(string $domain, string $section, array $data): bool {
$provider = \AKSRT\Admin\SchemaProvider::get_instance();
$result = $provider->write_settings($domain, $data, $section);
if ($result) {
self::flush_settings_cache();
$option_key = $provider->get_option_key($domain, $section);
do_action('aksrt_settings_domain_saved', $domain, $section, $option_key);
}
return $result;
}
/**
* 获取指定 domain/section 的默认值。
*/
public static function get_domain_defaults(string $domain, string $section = ''): array {
$provider = \AKSRT\Admin\SchemaProvider::get_instance();
return $provider->get_defaults($domain, $section);
}
/**
* 重置指定 domain/section 到默认值。
*/
public static function reset_domain(string $domain, string $section = ''): bool {
$provider = \AKSRT\Admin\SchemaProvider::get_instance();
$result = $provider->reset_to_defaults($domain, $section);
if ($result) {
self::flush_settings_cache();
do_action('aksrt_settings_domain_reset', $domain, $section);
}
return $result;
}
public static function get_value(string $key, $default = null) {
$settings = self::get_all();
return array_key_exists($key, $settings) ? $settings[$key] : $default;
}
/** 获取搜索框占位文案 */
public static function search_placeholder(): string {
return ThemeSearch::search_placeholder();
}
/** 获取搜索模式 */
public static function search_mode(): string {
return ThemeSearch::search_mode();
}
/** 是否启用搜索历史 */
public static function search_history_enabled(): bool {
return ThemeSearch::search_history_enabled();
}
/** 是否启用热门搜索 */
public static function hot_search_enabled(): bool {
return ThemeSearch::hot_search_enabled();
}
/** 获取热门搜索关键词 */
public static function hot_search_keywords(): array {
return ThemeSearch::hot_search_keywords();
}
/** 热门搜索标题(留空使用默认) */
public static function search_popular_title(): string {
return ThemeSearch::search_popular_title();
}
/** 置顶搜索词(始终显示在最前面) */
public static function search_popular_sticky(): array {
return ThemeSearch::search_popular_sticky();
}
/** 是否启用搜索建议 */
public static function search_suggestions_enabled(): bool {
return ThemeSearch::search_suggestions_enabled();
}
/** 是否在搜索面板显示热门文章 */
public static function search_posts_enabled(): bool {
return ThemeSearch::search_posts_enabled();
}
/** 搜索结果是否排除页面 */
public static function search_no_page(): bool {
return ThemeSearch::search_no_page();
}
/** 获取搜索排除分类 ID 列表 */
public static function search_exclude_cats(): array {
return ThemeSearch::search_exclude_cats();
}
/** 是否启用分类搜索选择器 */
public static function search_cat_enabled(): bool {
return ThemeSearch::search_cat_enabled();
}
/** 获取默认搜索分类 */
public static function search_cat_in(): string {
return ThemeSearch::search_cat_in();
}
/** 是否显示更多分类 */
public static function search_more_cat_obj(): bool {
return ThemeSearch::search_more_cat_obj();
}
/** 是否启用自定义搜索匹配范围 */
public static function search_custom_key_enabled(): bool {
return ThemeSearch::search_custom_key_enabled();
}
/** 获取自定义搜索匹配字段列表 */
public static function search_custom_key(): array {
return ThemeSearch::search_custom_key();
}
/** 是否启用搜索结果 taxonomy 筛选 */
public static function search_facets_enabled(): bool {
return ThemeSearch::search_facets_enabled();
}
/** 获取搜索结果筛选 taxonomy 排序列表 */
public static function search_facets_order(): array {
return ThemeSearch::search_facets_order();
}
/**
* Meilisearch integration configuration.
*
* @return array{enabled:bool,api_url:string,api_key:string,index_prefix:string,synonyms:array}
*/
public static function get_meilisearch_config(): array {
return ThemeSearch::get_meilisearch_config();
}
/**
* pre_get_posts 过滤:应用搜索排除配置
* - search_no_page: 排除页面
* - search_exclude_cats: 排除指定分类
*/
public static function filter_search_query($query): void {
ThemeSearch::filter_search_query($query);
}
/**
* pre_get_posts: apply global list_orderby on archive/tag/category/search pages.
*
* Only fires when no explicit orderby is set by URL params or other hooks.
*/
public static function apply_list_orderby($query): void {
PostDisplay::apply_list_orderby($query);
}
/**
* 获取搜索内容类型配置
*
* @return array{types: string[], default: string}
*/
public static function get_search_content_types(): array {
return ThemeSearch::get_search_content_types();
}
/** 默认主题模式 (white-theme / dark-theme / time-auto) */
public static function theme_mode(): string {
return ThemeSearch::theme_mode();
}
/** 主题模式 → JS 可消费的简化值 (light / dark / time-auto) */
public static function theme_mode_js_value(): string {
return ThemeSearch::theme_mode_js_value();
}
/** time-auto:对齐 zibll 早晚 8 点自动切换语义。 */
public static function time_auto_theme_mode(): string {
return ThemeSearch::time_auto_theme_mode();
}
/** 首屏主题模式:优先消费 zibll 兼容 cookie,回退后台默认值。 */
public static function initial_theme_mode(): string {
return ThemeSearch::initial_theme_mode();
}
/** 获取主题色 */
public static function primary_color(): string {
return ThemeSearch::primary_color();
}
/** 获取主题皮肤预设 hex(解析 palette 选项为 #hex 格式) */
public static function theme_skin(): string {
return ThemeSearch::theme_skin();
}
/** 获取暗色模式独立主题色 */
public static function dark_primary_color(): string {
return ThemeSearch::dark_primary_color();
}
/** 获取主题切换按钮显示位置列表 */
public static function get_theme_mode_button_positions(): array {
return ThemeSearch::get_theme_mode_button_positions();
}
/** 获取最终生效的主题色(skin 优先于 custom primary_color) */
public static function resolved_primary_color(): string {
return ThemeSearch::resolved_primary_color();
}
/** 获取全局圆角 */
public static function border_radius(): int {
return ThemeSearch::border_radius();
}
/** 获取卡片圆角值(独立设置优先,否则 border_radius + 4) */
public static function card_radius(): int {
return ThemeSearch::card_radius();
}
/** 全站加载动画开关 */
public static function is_qj_loading_enabled(): bool {
return ThemeSearch::is_qj_loading_enabled();
}
/** 加载动画样式 (no1–no10) */
public static function get_qj_loading_style(): string {
return ThemeSearch::get_qj_loading_style();
}
/** 获取内容最大宽度 */
public static function container_max_width(): int {
return ThemeSearch::container_max_width();
}
/** 获取全局字体方案 */
public static function font_family(): string {
return ThemeSearch::font_family();
}
/**
* 获取代码高亮配置
*
* @return array
*/
public static function get_code_highlight_config(): array {
return ThemeSearch::get_code_highlight_config();
}
/**
* 获取系统公告配置
*
* @return array
*/
public static function get_system_notice_config(): array {
return ThemeSearch::get_system_notice_config();
}
/**
* 获取侧边栏配置
*
* @return array
*/
public static function get_sidebar_config(): array {
return ThemeSearch::get_sidebar_config();
}
/**
* 获取多语言翻译配置
*
* @return array
*/
public static function get_i18n_config(): array {
return ThemeSearch::get_i18n_config();
}
/**
* Public user-home display settings.
*
* @return array
*/
public static function get_user_home_settings(): array {
return UserRuntime::get_user_home_settings();
}
/**
* Private user-center display settings.
*
* @return array{tabs:string[],avatar_upload:bool,cover_upload:bool,social_links:bool}
*/
public static function get_user_center_settings(): array {
return UserRuntime::get_user_center_settings();
}
/**
* User identity, level, badge, and report governance settings.
*
* @return array{
* verify:array{enabled:bool,public_display:bool,badge_text:string,accept_email_verified:bool,require_manual_review:bool},
* level:array{enabled:bool,public_display:bool,source:string,label_prefix:string,thresholds:array<int,int>},
* badge:array{enabled:bool,public_display:bool,limit:int,dictionary:array<int,array{slug:string,label:string,tone:string}>},
* report:array{enabled:bool,public_entry:bool,public_notice:bool,ban_notice_text:string,categories:array<int,array{slug:string,label:string}>}
* }
*/
public static function get_user_identity_settings(): array {
return UserRuntime::get_user_identity_settings();
}
/** @return array<string,mixed> */
public static function get_identity_verification_settings(): array {
return \AKSRT\Identity\SettingsRuntime::get();
}
/** @return array<string,string> */
public static function get_identity_provider_secrets(string $provider): array {
return \AKSRT\Identity\SecretStore::get($provider);
}
/** @param array<string,string|null> $changes */
public static function update_identity_provider_secrets(string $provider, array $changes): bool {
return \AKSRT\Identity\SecretStore::update($provider, $changes);
}
/** @return array<string,array{configured:bool,fingerprint:string}> */
public static function get_identity_provider_secret_status(string $provider): array {
return \AKSRT\Identity\SecretStore::status($provider);
}
/**
* Remove secrets from settings export and backup payloads.
*
* @param array<string,mixed> $payload
* @return array<string,mixed>
*/
public static function redact_sensitive_settings(array $payload): array {
if (isset($payload['standalone']) && is_array($payload['standalone'])) {
foreach (self::SECRET_OPTION_KEYS as $option_key) {
unset($payload['standalone'][$option_key]);
}
}
return $payload;
}
/**
* Ignore secret options and redacted placeholders during import.
*
* @param array<string,mixed> $standalone
* @return array<string,mixed>
*/
public static function filter_sensitive_import(array $standalone): array {
foreach (self::SECRET_OPTION_KEYS as $option_key) {
unset($standalone[$option_key]);
}
return $standalone;
}
/**
* Post-list card style and meta display settings.
*
* @return array{card_style:string,render_mode:string,show_author:bool,show_date:bool,show_views:bool,show_category:bool,show_comments:bool,show_likes:bool,excerpt_length:int}
*/
public static function get_post_list_style_settings(): array {
return PostDisplay::get_post_list_style_settings();
}
/**
* Post-list thumbnail policy settings.
*
* @return array{priority:string[],fallback:string,aspect_ratio:string,multi_enabled:bool,multi_count:int,lazy:bool}
*/
public static function get_post_thumb_settings(): array {
return PostDisplay::get_post_thumb_settings();
}
/**
* Post-list filter toolbar settings.
*
* @return array{enabled:bool,categories:bool,tags:bool,sort:bool}
*/
public static function get_post_filter_settings(): array {
return PostDisplay::get_post_filter_settings();
}
/**
* Get custom filter definitions for a specific category.
* Finds the matching cat_custom_filter binding, falls back to global custom_filter.
*
* @param int $cat_id Category term ID.
* @return array{dimensions: array, show_cat: bool, show_tag: bool, show_topics: bool, show_orderby: bool}
*/
public static function get_filter_config_for_category(int $cat_id): array {
return PostDisplay::get_filter_config_for_category($cat_id);
}
/**
* Front submit settings.
*
* @return array{enabled:bool,btn_text:string,title_min:int,title_max:int}
*/
public static function get_submit_settings(): array {
return PostDisplay::get_submit_settings();
}
/**
* Comment display and behavior settings.
*
* @return array{order:string,pagination_mode:string,nested_depth:int,require_login:bool,allow_reply:bool,avatar_size:int,empty_text:string}
*/
public static function get_comment_display_settings(): array {
return PostDisplay::get_comment_display_settings();
}
public static function get_withdrawal_settings(): array {
return PaymentRuntime::get_withdrawal_settings();
}
/**
* pre_get_posts: apply post_list_per_page on archive/tag/category/search/home pages.
*
* Overrides WP Settings > Reading "posts per page" for list views.
*/
public static function apply_list_per_page($query): void {
PostDisplay::apply_list_per_page($query);
}
/** 获取Banner列表 */
public static function get_banners(string $position = ''): array {
return DisplayRuntime::get_banners($position);
}
/** 保存Banner */
public static function save_banner(array $data): int {
return DisplayRuntime::save_banner($data);
}
/** 删除Banner */
public static function delete_banner(string $id): void {
DisplayRuntime::delete_banner($id);
}
/** 获取友链列表 */
public static function get_friend_links(): array {
return DisplayRuntime::get_friend_links();
}
/** 保存友链 */
public static function save_friend_links(array $links): void {
DisplayRuntime::save_friend_links($links);
}
/** 私信邮件接收组限制 (all/vip/vip2/admin) */
public static function get_email_private_receive_limit(): string {
return Integration::get_email_private_receive_limit();
}
/** 获取OAuth配置 */
public static function get_oauth(): array {
return Integration::get_oauth();
}
/** 检查OAuth平台是否已配置 */
public static function oauth_configured(string $provider): bool {
return Integration::oauth_configured($provider);
}
// ============================================
// OAuth 代理登录 & 自动创建用户
// ============================================
/** OAuth 代理登录模式: 'off' | 'server' | 'client' (schema 存 'close'→映射为 'off') */
public static function oauth_proxy_mode(): string {
return Integration::oauth_proxy_mode();
}
/** OAuth 代理登录 HMAC 密钥 */
public static function oauth_proxy_secret(): string {
return Integration::oauth_proxy_secret();
}
/** OAuth 代理登录服务端地址(客户端模式使用) */
public static function oauth_proxy_server_url(): string {
return Integration::oauth_proxy_server_url();
}
/** OAuth 代理登录允许的平台列表(服务端模式使用) */
public static function oauth_proxy_allowed_providers(): array {
return Integration::oauth_proxy_allowed_providers();
}
/** OAuth 代理登录启用的平台列表(客户端模式使用) */
public static function oauth_proxy_client_providers(): array {
return Integration::oauth_proxy_client_providers();
}
/**
* 获取微信公众号登录完整配置
*
* @return array{gzh_type:string,token:string,token_nocheck:bool,encoding_aes_key:string,appid:string,appsecret:string,code_qrcode:string,code_keyword:string,code_reply:string,code_subscribe_reply:string,subscribe_msg:string,new_subscribe_msg:string,scan_msg:string,auto_reply_text:string,auto_reply_search:string,auto_reply_image:string,auto_reply_voice:string,auto_reply_default:string,gzh_menu:string,priority:bool,auto:bool,auto_expires:int}
*/
public static function get_weixingzh_settings(): array {
return Integration::get_weixingzh_settings();
}
/**
* 获取 OAuth 代理登录完整配置(aksrt_settings 优先,BC fallback aksrt_oauth)
*
* @return array{mode:string,secret:string,server_url:string,server_providers:array,client_providers:array,gzh_type:string}
*/
public static function get_oauth_proxy_settings(): array {
return Integration::get_oauth_proxy_settings();
}
// ============================================
// 底部信息配置
// ============================================
/**
* 获取底部信息完整配置(统一 aksrt_footer_settings + aksrt_settings page-display footer 字段)
* @return array
*/
public static function get_footer_settings(): array {
return HomeCms::get_footer_settings();
}
/** 获取联系图标列表(仅返回启用的) */
public static function get_footer_contacts(): array {
return HomeCms::get_footer_contacts();
}
/** 获取快速链接列表(仅返回启用的,按排序) */
public static function get_quick_links(): array {
return HomeCms::get_quick_links();
}
/** 获取更多链接列表(仅返回启用的,按排序) */
public static function get_more_links(): array {
return HomeCms::get_more_links();
}
/** 获取热门分类显示数量 */
public static function get_hot_categories_count(): int {
return HomeCms::get_hot_categories_count();
}
/** 获取版权文字 */
public static function get_copyright_text(): string {
return HomeCms::get_copyright_text();
}
/**
* 获取页脚品牌列(第一列)配置
* @return array {m_s, img, img_dark, title, custom_code}
*/
public static function get_footer_brand_settings(): array {
return HomeCms::get_footer_brand_settings();
}
/**
* 获取页脚扩展联系方式配置
* @return array {m_s, wechat_img, qq, weibo, email, more, code_1, code_2}
*/
public static function get_footer_contact_extended_settings(): array {
return HomeCms::get_footer_contact_extended_settings();
}
/**
* 获取页脚二维码图片组(第三列)
* @return array {m_s, items: [{text, img}]}
*/
public static function get_footer_mini_img_settings(): array {
return HomeCms::get_footer_mini_img_settings();
}
/**
* 获取页脚底部自定义代码
*/
public static function get_footer_customize_code(): string {
return HomeCms::get_footer_customize_code();
}
/** 获取审核配置 */
public static function get_moderation(): array {
return ExtensionRuntime::get_moderation();
}
// ============================================
// 文章布局配置
// ============================================
/**
* 获取归档布局模式。
*
* 从 post_list.list schema 的 render_mode 字段读取。
* 后台可在 /post-list/list 页面配置。
*
* @return string grid-cms|list|compact
*/
public static function get_archive_layout(): string {
return PostDisplay::get_archive_layout();
}
/**
* 获取文章列表分页模式
* @return string numbered|load_more|infinite
*/
public static function get_post_pagination_mode(): string {
return PostDisplay::get_post_pagination_mode();
}
/**
* 获取评论列表分页模式
* @return string numbered|load_more|infinite
*/
public static function get_comment_pagination_mode(): string {
return PostDisplay::get_comment_pagination_mode();
}
// ============================================
// CMS 配置
// ============================================
/**
* 获取站点全局风格。
*
* v4 起主题统一为 CMS / 资源站形态,恒返回 'cms'。
* 保留方法签名以兼容旧调用。
*
* @return string 始终为 'cms'
*/
public static function get_site_profile(): string {
return HomeCms::get_site_profile();
}
/**
* CMS 功能开关(合并默认值)。
* @return array
*/
public static function get_cms_features(): array {
return HomeCms::get_cms_features();
}
/**
* 单项 CMS 功能开关读取。
*/
public static function cms_feature(string $key, $default = null) {
return HomeCms::cms_feature($key, $default);
}
}