trim(sanitize_text_field((string) $k)), $items); return array_values(array_filter(array_unique($items), fn(string $k) => $k !== '')); } public static function search_posts_enabled(): bool { return !empty(Settings::get_value('search_posts', false)); } public static function search_no_page(): bool { return !empty(Settings::get_value('search_no_page', false)); } public static function search_exclude_cats(): array { $raw = Settings::get_value('search_exclude_cats', ''); if (is_array($raw)) { $items = $raw; } else { $items = preg_split('/[,,\s]+/', (string) $raw) ?: []; } $items = array_map(static fn($id) => absint($id), $items); return array_values(array_filter(array_unique($items), fn(int $id) => $id > 0)); } public static function search_cat_enabled(): bool { return !empty(Settings::get_value('search_cat', false)); } public static function search_cat_in(): string { return trim((string) Settings::get_value('search_cat_in', '')); } public static function search_more_cat_obj(): array { $raw = Settings::get_value('search_more_cat_obj', []); $items = is_array($raw) ? $raw : (preg_split('/[,,\s]+/', (string) $raw) ?: []); return array_values(array_filter(array_unique(array_map('absint', $items)))); } public static function search_custom_key_enabled(): bool { return !empty(Settings::get_value('search_custom_key_s', false)); } public static function search_custom_key(): array { $raw = Settings::get_value('search_custom_key', ['title', 'content', 'excerpt', 'category', 'post_tag']); if (is_array($raw)) { $items = $raw; } else { $items = preg_split('/[,,\s]+/', (string) $raw) ?: []; } $items = array_map(static fn($k) => trim(sanitize_key((string) $k)), $items); $valid = ['title', 'content', 'excerpt', 'category', 'post_tag', 'coment', 'user']; return array_values(array_intersect(array_filter(array_unique($items)), $valid)); } public static function search_facets_enabled(): bool { return !empty(Settings::get_value('search_facets', [])); } public static function search_facets_order(): array { $raw = Settings::get_value('search_facets', []); $items = is_array($raw) ? array_keys($raw) : []; $items = array_map(static fn($s) => trim(sanitize_key((string) $s)), $items); return array_values(array_filter(array_unique($items), fn(string $s) => $s !== '')); } public static function get_meilisearch_config(): array { $s = Settings::get_all(); $opt = is_array($s['search_ms_opt'] ?? null) ? $s['search_ms_opt'] : []; $enabled = !empty($s['search_ms_s']); $api_url = esc_url_raw(trim((string) ($opt['api_url'] ?? 'http://127.0.0.1:7700'))); $api_key = sanitize_text_field((string) ($opt['api_key'] ?? '')); $index_prefix = sanitize_key((string) ($opt['index_prefix'] ?? 'aksrt')); $synonyms_raw = $opt['synonyms'] ?? []; $synonyms = []; foreach ((array) $synonyms_raw as $row) { if (!is_array($row)) { continue; } $key = trim(sanitize_text_field((string) ($row['key'] ?? ''))); $values = array_values(array_filter(array_map('trim', explode(',', sanitize_text_field((string) ($row['val'] ?? '')))))); if ($key !== '' && $values) { $synonyms[$key] = $values; } } return [ 'enabled' => $enabled, 'api_url' => $api_url, 'api_key' => $api_key, 'index_prefix' => $index_prefix !== '' ? $index_prefix : 'aksrt', 'synonyms' => $synonyms, 'index_name' => ($index_prefix !== '' ? $index_prefix : 'aksrt') . '_posts', ]; } public static function filter_posts_search(string $search, \WP_Query $query): string { if (!$query->is_search() || !$query->get('s') || !self::search_custom_key_enabled()) { return $search; } if (sanitize_key((string) $query->get('type')) === 'user') { return ' AND 1=0'; } $config = self::get_meilisearch_config(); if (!empty($config['enabled'])) { return $search; } $keys = self::search_custom_key(); if (!$keys) { return $search; } global $wpdb; $terms = (array) ($query->query_vars['search_terms'] ?? []); if (!$terms) { $terms = [(string) $query->get('s')]; } $groups = []; $taxonomies = ['post_tag', 'category']; foreach ($terms as $term) { $like = (!empty($query->query_vars['exact']) ? '' : '%') . $wpdb->esc_like((string) $term) . (!empty($query->query_vars['exact']) ? '' : '%'); $parts = []; foreach ($keys as $key) { if ($key === 'title') $parts[] = $wpdb->prepare("{$wpdb->posts}.post_title LIKE %s", $like); elseif ($key === 'content') $parts[] = $wpdb->prepare("{$wpdb->posts}.post_content LIKE %s", $like); elseif ($key === 'excerpt') $parts[] = $wpdb->prepare("{$wpdb->posts}.post_excerpt LIKE %s", $like); elseif (in_array($key, $taxonomies, true)) $parts[] = $wpdb->prepare('(aksrt_search_tt.taxonomy = %s AND aksrt_search_terms.name LIKE %s)', $key, $like); elseif ($key === 'coment') $parts[] = $wpdb->prepare('aksrt_search_comments.comment_content LIKE %s', $like); elseif ($key === 'user') $parts[] = $wpdb->prepare('(aksrt_search_users.user_nicename LIKE %s OR aksrt_search_users.display_name LIKE %s)', $like, $like); } if ($parts) { $groups[] = '(' . implode(' OR ', $parts) . ')'; } } if (!$groups) { return $search; } if (!is_user_logged_in()) { $groups[] = "({$wpdb->posts}.post_password = '')"; } return ' AND ' . implode(' AND ', $groups); } public static function filter_posts_search_join(string $join, \WP_Query $query): string { if (!$query->is_search() || !$query->get('s') || !self::search_custom_key_enabled() || !empty(self::get_meilisearch_config()['enabled'])) { return $join; } global $wpdb; $keys = self::search_custom_key(); if (in_array('coment', $keys, true)) { $join .= " LEFT JOIN {$wpdb->comments} AS aksrt_search_comments ON ({$wpdb->posts}.ID = aksrt_search_comments.comment_post_ID)"; } if (in_array('user', $keys, true)) { $join .= " LEFT JOIN {$wpdb->users} AS aksrt_search_users ON ({$wpdb->posts}.post_author = aksrt_search_users.ID)"; } if (array_intersect(['post_tag', 'category'], $keys)) { $join .= " LEFT JOIN {$wpdb->term_relationships} AS aksrt_search_tr ON ({$wpdb->posts}.ID = aksrt_search_tr.object_id)"; $join .= " LEFT JOIN {$wpdb->term_taxonomy} AS aksrt_search_tt ON (aksrt_search_tr.term_taxonomy_id = aksrt_search_tt.term_taxonomy_id)"; $join .= " LEFT JOIN {$wpdb->terms} AS aksrt_search_terms ON (aksrt_search_tt.term_id = aksrt_search_terms.term_id)"; } return $join; } public static function filter_posts_search_distinct(string $distinct, \WP_Query $query): string { return $query->is_search() && $query->get('s') && self::search_custom_key_enabled() ? 'DISTINCT' : $distinct; } public static function filter_search_query($query): void { if (is_admin() || !$query->is_main_query() || !$query->is_search()) { return; } $type = isset($_REQUEST['type']) ? sanitize_key((string) wp_unslash($_REQUEST['type'])) : ''; if (!in_array($type, ['post', 'user'], true)) { $type = self::get_search_content_types()['default']; } $query->set('type', $type); if ($type === 'user') { $query->set('post__in', [0]); return; } if (self::search_no_page()) { $existing = $query->get('post_type'); if (empty($existing)) { $query->set('post_type', 'post'); } } $exclude_cats = self::search_exclude_cats(); if (!empty($exclude_cats)) { foreach ($exclude_cats as $category_id) { $children = get_term_children($category_id, 'category'); if (!is_wp_error($children)) { $exclude_cats = array_merge($exclude_cats, $children); } } $query->set('category__not_in', array_values(array_unique(array_map('absint', $exclude_cats)))); } $term_id = isset($_REQUEST['trem']) ? absint(wp_unslash($_REQUEST['trem'])) : 0; if ($term_id > 0) { $term = get_term($term_id); if ($term instanceof \WP_Term) { $tax_query = (array) $query->get('tax_query'); $tax_query[] = [ 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, ]; $query->set('tax_query', $tax_query); } } $user_id = isset($_REQUEST['user']) ? absint(wp_unslash($_REQUEST['user'])) : 0; if ($user_id > 0) { $query->set('author', $user_id); } $orderby = isset($_REQUEST['orderby']) ? sanitize_key((string) wp_unslash($_REQUEST['orderby'])) : ''; $meta_keys = [ 'views' => 'aksrt_post_views', 'like' => '_aksrt_like_count', 'favorite' => '_aksrt_favorite_count', 'sales_volume' => '_aksrt_sales_volume', ]; if (isset($meta_keys[$orderby])) { $query->set('meta_key', $meta_keys[$orderby]); $query->set('orderby', ['meta_value_num' => 'DESC', 'date' => 'DESC']); $query->set('order', 'DESC'); } elseif ($orderby === 'comment_count') { $query->set('orderby', 'comment_count'); $query->set('order', 'DESC'); } elseif ($orderby === 'date') { $query->set('orderby', 'date'); $query->set('order', 'DESC'); } } public static function apply_list_orderby($query): void { if (is_admin() || !$query->is_main_query()) { return; } if (!$query->is_archive() && !$query->is_search() && !$query->is_home()) { return; } if ($query->get('orderby')) { return; } $s = Settings::get_all(); $key = sanitize_key((string) ($s['list_orderby'] ?? 'modified')); if ($key === '' || $key === 'default') { return; } switch ($key) { case 'modified': $query->set('orderby', 'modified'); $query->set('order', 'DESC'); break; case 'date': $query->set('orderby', 'date'); $query->set('order', 'DESC'); break; case 'comments': $query->set('orderby', 'comment_count'); $query->set('order', 'DESC'); break; } } public static function get_search_content_types(): array { $types = ['post', 'user']; $default = sanitize_key((string) Settings::get_value('search_type_in', 'post')); if (!in_array($default, $types, true)) { $default = 'post'; } return [ 'types' => $types, 'default' => $default, ]; } public static function theme_mode(): string { $mode = sanitize_key((string) Settings::get_value('theme_mode', 'time-auto')); $valid = ['white-theme', 'dark-theme', 'time-auto']; return in_array($mode, $valid, true) ? $mode : 'time-auto'; } public static function theme_mode_js_value(): string { $mode = self::theme_mode(); $map = ['white-theme' => 'light', 'dark-theme' => 'dark', 'time-auto' => 'time-auto']; return $map[$mode] ?? 'time-auto'; } public static function time_auto_theme_mode(): string { $hour = (int) current_time('G'); return ($hour >= 20 || $hour < 8) ? 'dark' : 'light'; } public static function initial_theme_mode(): string { $cookie = isset($_COOKIE['theme_mode']) ? sanitize_key((string) wp_unslash($_COOKIE['theme_mode'])) : ''; $map = [ 'dark-theme' => 'dark', 'white-theme' => 'light', 'dark' => 'dark', 'light' => 'light', ]; if (isset($map[$cookie])) { return $map[$cookie]; } $mode = self::theme_mode(); if ($mode === 'dark-theme') { return 'dark'; } if ($mode === 'white-theme') { return 'light'; } if ($mode === 'time-auto') { return self::time_auto_theme_mode(); } return ''; } /** 全局主题色:theme_skin_custom 优先,清空时使用 theme_skin 预置色(对齐参考主题 zib_head_css)。 */ public static function theme_color(): string { $custom = \AKSRT\Core\Color::sanitize(Settings::get_value('theme_skin_custom', '')); if ($custom !== '') { return $custom; } $skin = ltrim(trim((string) Settings::get_value('theme_skin', 'f04494')), '#'); return preg_match('/^[0-9a-fA-F]{6}$/', $skin) ? '#' . $skin : '#f04494'; } /** 夜间模式主题色;未设置返回空串,夜间沿用全局主题色。 */ public static function dark_theme_color(): string { return \AKSRT\Core\Color::sanitize(Settings::get_value('dark_theme_skin_custom', '')); } public static function get_theme_mode_button_positions(): array { $raw = Settings::get_value('theme_mode_button', ['pc_nav', 'm_menu']); return array_values(array_intersect(array_map('sanitize_key', (array) $raw), ['pc_nav', 'm_menu'])); } /** 卡片圆角 theme_main_radius(0–30,默认 12)→ --main-radius。 */ public static function main_radius(): int { return max(0, min(30, (int) Settings::get_value('theme_main_radius', 12))); } public static function close_backdrop(): bool { return !empty(Settings::get_value('close_backdrop', false)); } /** * 背景图 CSS 声明(不含选择器);无颜色且无图片时返回空串。 * 子键白名单与 GlobalSchema::background_field() / layout.js bgField 一致。 */ public static function background_css(string $key): string { $bg = Settings::get_value($key, []); if (!is_array($bg)) { return ''; } $color = \AKSRT\Core\Color::sanitize($bg['color'] ?? ''); $image = esc_url_raw(trim((string) ($bg['image'] ?? ''))); if ($color === '' && $image === '') { return ''; } $allowed = [ 'position' => ['left top', 'left center', 'left bottom', 'center top', 'center center', 'center bottom', 'right top', 'right center', 'right bottom'], 'repeat' => ['repeat', 'no-repeat', 'repeat-x', 'repeat-y'], 'attachment' => ['scroll', 'fixed'], 'size' => ['100%', 'cover', 'contain', 'auto'], 'origin' => ['padding-box', 'border-box', 'content-box'], ]; $css = $color !== '' ? 'background-color:' . $color . ';' : ''; if ($image !== '') { $css .= 'background-image:url("' . str_replace(['"', '\\', "\n", "\r"], '', $image) . '");'; foreach ($allowed as $prop => $values) { $value = (string) ($bg[$prop] ?? ''); if (in_array($value, $values, true)) { $css .= 'background-' . $prop . ':' . $value . ';'; } } } return $css; } public static function is_qj_loading_enabled(): bool { return (bool) Settings::get_value('qj_loading', false); } public static function get_qj_loading_style(): string { $style = (string) Settings::get_value('qj_dh_xs', 'no1'); if (!preg_match('/^no([1-9]|10)$/', $style)) { return 'no1'; } return $style; } public static function container_max_width(): int { $width = (int) Settings::get_value('container_max_width', 1200); return max(1200, min(2200, $width)); } public static function font_family(): string { $family = sanitize_key((string) Settings::get_value('font_family', 'system')); return in_array($family, ['system', 'noto-sans-sc', 'noto-serif-sc', 'custom'], true) ? $family : 'system'; } /** 自定义 font-family 字体栈,只保留字体名、引号、逗号等安全字符。 */ public static function font_family_custom(): string { $stack = (string) Settings::get_value('font_family_custom', ''); $stack = preg_replace('/[^\p{L}\p{N}\s,"\'\-_.]/u', '', $stack); return trim((string) preg_replace('/\s+/', ' ', (string) $stack), " ,"); } public static function get_code_highlight_config(): array { $s = Settings::get_all(); $light_themes = ['enlighter','bootstrap4','classic','beyond','mowtwo','eclipse','droide','minimal','rowhammer','godzilla','dracula','atomic','monokai']; $dark_themes = ['dracula','atomic','monokai','enlighter','bootstrap4']; $light = sanitize_key((string) ($s['highlight_zt'] ?? 'enlighter')); $dark = sanitize_key((string) ($s['highlight_dark_zt'] ?? 'monokai')); $max_height_raw = $s['highlight_maxheight'] ?? 400; $max_height = absint(is_numeric($max_height_raw) ? $max_height_raw : preg_replace('/[^0-9]/', '', $max_height_raw)); if ($max_height === 0 && !in_array($max_height_raw, [0, '0', '0px'], true)) { $max_height = 400; } return [ 'enabled' => !isset($s['highlight_kg']) || !empty($s['highlight_kg']), 'lightTheme' => in_array($light, $light_themes, true) ? $light : 'enlighter', 'darkTheme' => in_array($dark, $dark_themes, true) ? $dark : 'monokai', 'lineNumbers' => !empty($s['highlight_hh']), 'showButtons' => !isset($s['highlight_btn']) || !empty($s['highlight_btn']), 'maxHeight' => $max_height, ]; } public static function get_system_notice_config(): array { $s = Settings::get_all(); $policy = sanitize_key((string) ($s['system_notice_policy'] ?? '')); if (!in_array($policy, ['', 'signin', 'vip', 'free', 'auth'], true)) { $legacy_map = ['always' => '', 'once' => '', 'daily' => '']; $policy = $legacy_map[$policy] ?? ''; } $size = sanitize_key((string) ($s['system_notice_size'] ?? '')); if (!in_array($size, ['', 'modal-mini', 'modal-sm', 'modal-lg'], true)) { $size = ''; } $radius_raw = $s['system_notice_radius'] ?? '0'; $radius = absint(preg_replace('/[^0-9]/', '', $radius_raw)); $allowed_colors = ['primary', 'success', 'warning', 'danger', 'info', 'purple', 'dark']; $buttons = []; for ($i = 1; $i <= 4; $i++) { $text = trim((string) ($s["system_notice_btn{$i}_text"] ?? '')); $link = esc_url_raw((string) ($s["system_notice_btn{$i}_link"] ?? '')); $color = sanitize_key((string) ($s["system_notice_btn{$i}_color"] ?? 'primary')); if ($i === 1 && $text === '') { $text = trim((string) ($s['system_notice_button'] ?? '')); $link = $link ?: esc_url_raw((string) ($s['system_notice_link'] ?? '')); } if ($text === '') continue; if (!in_array($color, $allowed_colors, true)) { $color = 'primary'; } $buttons[] = [ 'text' => $text, 'link' => $link, 'color' => $color, ]; } return [ 'enabled' => !empty($s['system_notice_enabled']), 'policy' => $policy, 'title' => trim((string) ($s['system_notice_title'] ?? '')), 'content' => trim((string) ($s['system_notice_content'] ?? '')), 'buttons' => $buttons, 'size' => $size, 'radius' => $radius, 'class' => sanitize_html_class((string) ($s['system_notice_class'] ?? '')), 'title_icon' => trim((string) ($s['system_notice_title_icon'] ?? '')), 'title_class' => sanitize_html_class((string) ($s['system_notice_title_class'] ?? '')), 'title_style' => trim((string) ($s['system_notice_title_style'] ?? '')), 'expires' => absint($s['system_notice_expires'] ?? 24), ]; } public static function get_sidebar_config(): array { $s = Settings::get_all(); $position = sanitize_key((string) ($s['sidebar_position'] ?? 'right')); $width = max(200, min(400, (int) ($s['sidebar_width'] ?? 311))); return [ 'enabled' => !isset($s['sidebar_enabled']) || !empty($s['sidebar_enabled']), 'position' => in_array($position, ['left', 'right'], true) ? $position : 'right', 'width' => $width, 'home' => !isset($s['sidebar_home_enabled']) || !empty($s['sidebar_home_enabled']), 'category' => !isset($s['sidebar_category_enabled']) || !empty($s['sidebar_category_enabled']), 'tag' => !isset($s['sidebar_tag_enabled']) || !empty($s['sidebar_tag_enabled']), 'single' => !isset($s['sidebar_single_enabled']) || !empty($s['sidebar_single_enabled']), 'page' => !isset($s['sidebar_page_enabled']) || !empty($s['sidebar_page_enabled']), 'search' => !isset($s['sidebar_search_enabled']) || !empty($s['sidebar_search_enabled']), ]; } public static function get_i18n_config(): array { $s = Settings::get_all(); $enabled = !empty($s['i18n_enabled']) || !empty($s['frontend_translate_enabled']); $source = $s['i18n_default_lang'] ?? $s['frontend_translate_source'] ?? 'zh-CN'; return [ 'enabled' => $enabled, 'autoDetect' => !isset($s['i18n_auto_detect']) || !empty($s['i18n_auto_detect']), 'defaultLang' => $source, 'availableLangs' => $s['i18n_available_langs'] ?? "zh-CN|简体中文\nen|English", 'nomenclature' => $s['i18n_nomenclature'] ?? '', 'switcherPosition' => $s['i18n_switcher_position'] ?? 'footer', 'urlStrategy' => $s['i18n_url_strategy'] ?? 'query', ]; } }