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

603 lines
23 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 ThemeSearch {
public static function search_placeholder(): string {
$placeholder = trim((string) Settings::get_value('search_placeholder', ''));
return $placeholder !== '' ? $placeholder : __('开启精彩搜索', 'aksrt');
}
public static function search_history_enabled(): bool {
$settings = Settings::get_all();
return !array_key_exists('search_history', $settings) || !empty($settings['search_history']);
}
public static function hot_search_enabled(): bool {
$settings = Settings::get_all();
return !array_key_exists('search_popular_key', $settings) || !empty($settings['search_popular_key']);
}
public static function hot_search_keywords(): array {
$items = self::search_popular_sticky();
$counts = get_option('search_keywords', []);
if (is_array($counts)) {
$items = array_merge($items, array_keys($counts));
}
$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_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'));
$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',
];
}
}