Move all domain folders from src/AKSRT/{Domain} to src/{Domain}; remap
Composer PSR-4 "AKSRT\\": "src/"; update audit script + README + ADR
paths; remove dead tools/build-psr4-map.php (scanned deleted inc/classes).
516 lines
20 KiB
PHP
516 lines
20 KiB
PHP
<?php
|
||
/**
|
||
* @package AKSRT
|
||
*/
|
||
|
||
namespace AKSRT\Settings;
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
class ThemeSearch {
|
||
|
||
public static function search_placeholder(): string {
|
||
$placeholder = trim((string) Settings::get_value('search_placeholder', ''));
|
||
return $placeholder !== '' ? $placeholder : __('开启精彩搜索', 'aksrt');
|
||
}
|
||
|
||
public static function search_mode(): string {
|
||
$mode = sanitize_key((string) Settings::get_value('search_mode', ''));
|
||
if ($mode === '' || !in_array($mode, ['default', 'ajax', 'redirect'], true)) {
|
||
$mode = sanitize_key((string) Settings::get_value('search_type', 'default'));
|
||
}
|
||
return in_array($mode, ['default', 'ajax', 'redirect'], true) ? $mode : 'default';
|
||
}
|
||
|
||
public static function search_history_enabled(): bool {
|
||
$settings = Settings::get_all();
|
||
return !array_key_exists('search_history_enabled', $settings) || !empty($settings['search_history_enabled']);
|
||
}
|
||
|
||
public static function hot_search_enabled(): bool {
|
||
$settings = Settings::get_all();
|
||
return !array_key_exists('hot_search_enabled', $settings) || !empty($settings['hot_search_enabled']);
|
||
}
|
||
|
||
public static function hot_search_keywords(): array {
|
||
$raw = Settings::get_value('hot_search_keywords', '');
|
||
if (is_array($raw)) {
|
||
$items = $raw;
|
||
} else {
|
||
$items = preg_split('/[\r\n,]+/', (string) $raw) ?: [];
|
||
}
|
||
|
||
$items = array_map(
|
||
static function ($keyword): string {
|
||
return trim(sanitize_text_field((string) $keyword));
|
||
},
|
||
$items
|
||
);
|
||
|
||
$items = array_values(array_filter(array_unique($items), static function (string $keyword): bool {
|
||
return $keyword !== '';
|
||
}));
|
||
|
||
$limit = max(1, min(50, absint(Settings::get_value('search_popular_key_num', 20))));
|
||
|
||
return array_slice($items, 0, $limit);
|
||
}
|
||
|
||
public static function search_popular_title(): string {
|
||
$title = trim((string) Settings::get_value('search_popular_title', ''));
|
||
return $title !== '' ? $title : __('热门搜索', 'aksrt');
|
||
}
|
||
|
||
public static function search_popular_sticky(): array {
|
||
$raw = Settings::get_value('search_popular_sticky', '');
|
||
if (is_array($raw)) {
|
||
$items = $raw;
|
||
} else {
|
||
$items = preg_split('/[\r\n,]+/', (string) $raw) ?: [];
|
||
}
|
||
$items = array_map(static fn($k) => trim(sanitize_text_field((string) $k)), $items);
|
||
return array_values(array_filter(array_unique($items), fn(string $k) => $k !== ''));
|
||
}
|
||
|
||
public static function search_suggestions_enabled(): bool {
|
||
return self::search_mode() === 'ajax' && !empty(Settings::get_value('search_suggestions_enabled', false));
|
||
}
|
||
|
||
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(): bool {
|
||
return !empty(Settings::get_value('search_more_cat_obj', true));
|
||
}
|
||
|
||
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');
|
||
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', 'tag', 'author'];
|
||
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', false));
|
||
}
|
||
|
||
public static function search_facets_order(): array {
|
||
$raw = Settings::get_value('search_facets_order', "category\ntag");
|
||
$items = is_array($raw) ? $raw : (preg_split('/[\r\n]+/', (string) $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();
|
||
|
||
$enabled = !empty($s['search_ms_enabled']);
|
||
$api_url = esc_url_raw(trim((string) ($s['search_ms_api_url'] ?? '')));
|
||
$api_key = sanitize_text_field((string) ($s['search_ms_api_key'] ?? ''));
|
||
$index_prefix = sanitize_key((string) ($s['search_ms_index_prefix'] ?? 'aksrt'));
|
||
$synonyms_raw = trim((string) ($s['search_ms_synonyms'] ?? ''));
|
||
$synonyms = [];
|
||
if ($synonyms_raw !== '') {
|
||
$decoded = json_decode($synonyms_raw, true);
|
||
if (is_array($decoded)) {
|
||
$synonyms = $decoded;
|
||
}
|
||
}
|
||
|
||
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_search_query($query): void {
|
||
if (is_admin() || !$query->is_main_query() || !$query->is_search()) {
|
||
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)) {
|
||
$cat_query = $query->get('cat');
|
||
$negatives = array_map(fn(int $id) => -$id, $exclude_cats);
|
||
if (!empty($cat_query)) {
|
||
$existing = is_array($cat_query) ? $cat_query : explode(',', (string) $cat_query);
|
||
$existing = array_map('intval', $existing);
|
||
$merged = array_merge($existing, $negatives);
|
||
$query->set('cat', implode(',', array_unique($merged)));
|
||
} else {
|
||
$query->set('cat', implode(',', $negatives));
|
||
}
|
||
}
|
||
}
|
||
|
||
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 {
|
||
$all_types = [
|
||
'post' => 'search_type_post',
|
||
'user' => 'search_type_user',
|
||
'category' => 'search_type_category',
|
||
'tag' => 'search_type_tag',
|
||
];
|
||
|
||
$enabled = [];
|
||
$all = Settings::get_all();
|
||
foreach ($all_types as $type => $key) {
|
||
$default_on = in_array($type, ['post', 'category', 'tag'], true);
|
||
$is_enabled = array_key_exists($key, $all)
|
||
? !empty(Settings::get_value($key, $default_on))
|
||
: $default_on;
|
||
|
||
if ($is_enabled) {
|
||
$enabled[] = $type;
|
||
}
|
||
}
|
||
|
||
if (empty($enabled)) {
|
||
$enabled = ['post'];
|
||
}
|
||
|
||
$default = sanitize_key((string) Settings::get_value('search_default_type', 'post'));
|
||
if (!in_array($default, $enabled, true)) {
|
||
$default = $enabled[0];
|
||
}
|
||
|
||
return [
|
||
'types' => $enabled,
|
||
'default' => $default,
|
||
];
|
||
}
|
||
|
||
public static function theme_mode(): string {
|
||
$mode = sanitize_key((string) Settings::get_value('theme_mode', 'time-auto'));
|
||
$map = ['light' => 'white-theme', 'dark' => 'dark-theme', 'auto' => 'time-auto'];
|
||
if (isset($map[$mode])) {
|
||
return $map[$mode];
|
||
}
|
||
$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 '';
|
||
}
|
||
|
||
public static function primary_color(): string {
|
||
$color = trim((string) Settings::get_value('primary_color', '#f04494'));
|
||
return preg_match('/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $color) ? $color : '#f04494';
|
||
}
|
||
|
||
public static function theme_skin(): string {
|
||
$skin = trim((string) Settings::get_value('theme_skin', 'f04494'));
|
||
$skin = ltrim($skin, '#');
|
||
if (preg_match('/^[0-9a-fA-F]{6}$/', $skin)) {
|
||
return '#' . $skin;
|
||
}
|
||
$legacy_map = [
|
||
'pink' => '#f04494',
|
||
'blue' => '#627bf5',
|
||
'green' => '#36af18',
|
||
'purple' => '#ae53f3',
|
||
'custom' => '',
|
||
];
|
||
if (isset($legacy_map[$skin])) {
|
||
return $legacy_map[$skin] !== '' ? $legacy_map[$skin] : self::primary_color();
|
||
}
|
||
return self::primary_color();
|
||
}
|
||
|
||
public static function dark_primary_color(): string {
|
||
$color = trim((string) Settings::get_value('dark_primary_color', ''));
|
||
if (preg_match('/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $color)) {
|
||
return $color;
|
||
}
|
||
return self::primary_color();
|
||
}
|
||
|
||
public static function get_theme_mode_button_positions(): array {
|
||
$raw = Settings::get_value('theme_mode_button', ['pc_nav', 'm_menu']);
|
||
if (is_array($raw)) {
|
||
return array_values(array_filter(array_map('sanitize_text_field', $raw)));
|
||
}
|
||
if (is_bool($raw)) {
|
||
return $raw ? ['pc_nav', 'm_menu'] : [];
|
||
}
|
||
$str = trim((string) $raw);
|
||
if ($str === '' || $str === '0') return [];
|
||
$items = preg_split('/[,|]+/', $str) ?: [];
|
||
return array_values(array_filter(array_map('sanitize_text_field', $items)));
|
||
}
|
||
|
||
public static function resolved_primary_color(): string {
|
||
$skin = self::theme_skin();
|
||
return $skin !== '' ? $skin : self::primary_color();
|
||
}
|
||
|
||
public static function border_radius(): int {
|
||
$radius = (int) Settings::get_value('border_radius', 8);
|
||
return max(0, min(20, $radius));
|
||
}
|
||
|
||
public static function card_radius(): int {
|
||
$main = Settings::get_value('theme_main_radius', null);
|
||
if ($main !== null && $main !== '') {
|
||
return max(0, min(30, (int) $main));
|
||
}
|
||
return self::border_radius() + 4;
|
||
}
|
||
|
||
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);
|
||
if ($width === 0) {
|
||
return 0;
|
||
}
|
||
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';
|
||
}
|
||
|
||
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',
|
||
];
|
||
}
|
||
}
|