refactor: flatten src/AKSRT → src (drop theme-identifier dir)
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).
This commit is contained in:
1 parent
56f1a8175f
commit
8c5b1555c9
285 files changed
+26
-3600
No files matched your search
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait AuthReader {
|
||||
|
||||
/** 评论是否启用 */
|
||||
public static function comment_enabled(): bool {
|
||||
$s = self::get_all();
|
||||
return !isset($s['comment_enabled']) || !empty($s['comment_enabled']);
|
||||
}
|
||||
|
||||
/** 是否要求注册用户才能评论 */
|
||||
public static function comment_requires_registration(): bool {
|
||||
return !empty(self::get_value('comment_require_login', false)) && self::comment_enabled();
|
||||
}
|
||||
|
||||
/** 是否允许注册 */
|
||||
public static function registration_enabled(): bool {
|
||||
return (bool) get_option('users_can_register');
|
||||
}
|
||||
|
||||
/** 注册是否要求邮箱验证 */
|
||||
public static function registration_requires_email_verification(): bool {
|
||||
$s = self::get_all();
|
||||
return self::registration_enabled() && !empty($s['registration_email_verification_enabled']);
|
||||
}
|
||||
|
||||
/** 注册邮箱验证方式 */
|
||||
public static function registration_verification_method(): string {
|
||||
$s = self::get_all();
|
||||
$method = $s['registration_email_verification_method'] ?? 'link';
|
||||
return in_array($method, ['link', 'code'], true) ? $method : 'link';
|
||||
}
|
||||
|
||||
/** 注册邮箱验证有效期(分钟) */
|
||||
public static function registration_verification_ttl_minutes(): int {
|
||||
$s = self::get_all();
|
||||
$ttl = (int) ($s['registration_verification_ttl_minutes'] ?? 30);
|
||||
return max(5, min(1440, $ttl));
|
||||
}
|
||||
|
||||
/** 验证成功后自动登录 */
|
||||
public static function registration_auto_login_after_verify(): bool {
|
||||
$s = self::get_all();
|
||||
return !isset($s['registration_auto_login_after_verify']) || !empty($s['registration_auto_login_after_verify']);
|
||||
}
|
||||
|
||||
/** 注册邮箱验证功能首次启用时间戳(用于历史账号判定) */
|
||||
public static function registration_verification_enabled_at(): int {
|
||||
$s = self::get_all();
|
||||
return (int) ($s['registration_verification_enabled_at'] ?? 0);
|
||||
}
|
||||
|
||||
/** 主题内置默认图片 URL */
|
||||
private static function default_asset_url(string $filename): string {
|
||||
return get_template_directory_uri() . '/assets/img/' . $filename;
|
||||
}
|
||||
|
||||
/** 获取Logo URL(留空时使用内置默认;zibll别名 logo_src 回退) */
|
||||
public static function logo_url(): string {
|
||||
$url = trim((string) self::get_value('site_logo', ''));
|
||||
if ($url === '') {
|
||||
$url = trim((string) get_option('logo_src', ''));
|
||||
}
|
||||
return $url !== '' ? $url : self::default_asset_url('default-logo.svg');
|
||||
}
|
||||
|
||||
/** 获取暗色模式 Logo URL(留空时跟随浅色模式;zibll别名 logo_src_dark 回退) */
|
||||
public static function logo_dark_url(): string {
|
||||
$url = trim((string) self::get_value('site_logo_dark', ''));
|
||||
if ($url === '') {
|
||||
$url = trim((string) get_option('logo_src_dark', ''));
|
||||
}
|
||||
return $url !== '' ? $url : self::logo_url();
|
||||
}
|
||||
|
||||
/** 获取站点品牌文字 */
|
||||
public static function logo_text(): string {
|
||||
$text = trim((string) self::get_value('logo_text', ''));
|
||||
return $text !== '' ? $text : get_bloginfo('name');
|
||||
}
|
||||
|
||||
// ---- 注册登录 auth 段 getter ----
|
||||
|
||||
/** 一键禁用登录注册总开关(默认 false;含社交登录,不影响后台) */
|
||||
public static function close_sign(): bool {
|
||||
return (bool) self::get_value('close_sign', false);
|
||||
}
|
||||
|
||||
/** 是否关闭注册(受 close_sign 总开关影响;兼容 user_close_signup 别名) */
|
||||
public static function close_signup(): bool {
|
||||
if (self::close_sign()) return true;
|
||||
return (bool) self::get_value('user_close_signup', false);
|
||||
}
|
||||
|
||||
/** 是否关闭账密登录(仅允许社交登录) */
|
||||
public static function close_signin(): bool {
|
||||
if (self::close_sign()) return true;
|
||||
return (bool) self::get_value('close_signin', false);
|
||||
}
|
||||
|
||||
/** 是否关闭登录(受 close_sign 总开关影响;兼容 user_close_login 别名) */
|
||||
public static function close_login(): bool {
|
||||
if (self::close_sign()) return true;
|
||||
return (bool) self::get_value('user_close_login', false);
|
||||
}
|
||||
|
||||
/** 登录注册样式: 'modal' | 'page'(默认 page;modal 运行时未就绪时自动回退 page) */
|
||||
public static function user_sign_type(): string {
|
||||
$type = (string) self::get_value('user_sign_type', 'page');
|
||||
if (!in_array($type, ['modal', 'page'], true)) $type = 'page';
|
||||
return $type;
|
||||
}
|
||||
|
||||
/** 应急登录 Key(空=禁用;管理员通过 ?aksrt_bypass=<key> 绕过 wp-login 替换) */
|
||||
public static function admin_sign_key(): string {
|
||||
return trim((string) self::get_value('admin_sign_key', ''));
|
||||
}
|
||||
|
||||
/** 登录页 UI 配置数组 */
|
||||
public static function sign_page_ui(): array {
|
||||
return [
|
||||
'background' => self::get_value('sign_page_background', []),
|
||||
'theme_mode' => in_array((string) self::get_value('sign_theme_mode', 'default'), ['default', 'light', 'dark'], true)
|
||||
? (string) self::get_value('sign_theme_mode', 'default') : 'default',
|
||||
'show_header' => (bool) self::get_value('sign_show_header', true),
|
||||
'card_position' => in_array((string) self::get_value('sign_card_position', 'center'), ['left', 'center', 'right'], true)
|
||||
? (string) self::get_value('sign_card_position', 'center') : 'center',
|
||||
'show_logo' => (bool) self::get_value('sign_show_logo', true),
|
||||
'footer' => (string) self::get_value('sign_page_footer', ''),
|
||||
];
|
||||
}
|
||||
|
||||
/** 弹窗 UI 配置数组 */
|
||||
public static function modal_ui(): array {
|
||||
return [
|
||||
'background' => self::get_value('sign_modal_background', []),
|
||||
'show_logo' => (bool) self::get_value('sign_modal_show_logo', true),
|
||||
];
|
||||
}
|
||||
|
||||
/** 登录框日间 LOGO URL(空时回退全局 logo_url) */
|
||||
public static function user_logo_url(): string {
|
||||
$ids = self::get_value('user_logo', []);
|
||||
if (is_array($ids) && !empty($ids)) {
|
||||
$url = wp_get_attachment_url((int) $ids[0]);
|
||||
if ($url) return $url;
|
||||
}
|
||||
return self::logo_url();
|
||||
}
|
||||
|
||||
/** 登录框夜间 LOGO URL(空时回退全局 logo_dark_url) */
|
||||
public static function user_logo_dark_url(): string {
|
||||
$ids = self::get_value('user_logo_dark', []);
|
||||
if (is_array($ids) && !empty($ids)) {
|
||||
$url = wp_get_attachment_url((int) $ids[0]);
|
||||
if ($url) return $url;
|
||||
}
|
||||
return self::logo_dark_url();
|
||||
}
|
||||
|
||||
/** 是否允许手机号登录 */
|
||||
public static function signin_phone_enabled(): bool {
|
||||
return (bool) self::get_value('user_signin_phone_s', false);
|
||||
}
|
||||
|
||||
/** 免密登录显示模式 */
|
||||
public static function nopas_active_mode(): string {
|
||||
$mode = (string) self::get_value('user_signin_nopas_active', 'nopas_first');
|
||||
return in_array($mode, ['nopas_first', 'password_first', 'nopas_only'], true) ? $mode : 'nopas_first';
|
||||
}
|
||||
|
||||
/** 绑定提醒类型(兼容旧 bool 值:true→'phone',false→'close') */
|
||||
public static function bind_reminder_type(): string {
|
||||
$val = self::get_value('bind_reminder', 'close');
|
||||
if (is_bool($val)) return $val ? 'phone' : 'close';
|
||||
$val = (string) $val;
|
||||
return in_array($val, ['email', 'phone', 'email_phone', 'close'], true) ? $val : 'close';
|
||||
}
|
||||
|
||||
/** 强制绑定类型(兼容旧 bool 值:true→'phone',false→'close') */
|
||||
public static function mandatory_bind_type(): string {
|
||||
$val = self::get_value('mandatory_bind', 'close');
|
||||
if (is_bool($val)) return $val ? 'phone' : 'close';
|
||||
$val = (string) $val;
|
||||
return in_array($val, ['email', 'phone', 'email_phone', 'close'], true) ? $val : 'close';
|
||||
}
|
||||
|
||||
/** 昵称黑名单关键词数组 */
|
||||
public static function nickname_blacklist(): array {
|
||||
$raw = (string) self::get_value('user_nickname_out', '');
|
||||
if ($raw === '') return [];
|
||||
// 支持逗号分隔和换行分隔
|
||||
$items = preg_split('/[,,\r\n]+/', $raw);
|
||||
return array_values(array_filter(array_map('trim', $items), 'strlen'));
|
||||
}
|
||||
|
||||
/** 邮箱限制配置:['type' => 'black'|'white', 'domains' => [...]] */
|
||||
public static function email_limit(): array {
|
||||
$type = (string) self::get_value('user_email_limit_type', 'black');
|
||||
if (!in_array($type, ['black', 'white'], true)) $type = 'black';
|
||||
$raw = (string) self::get_value('user_email_out', '');
|
||||
$domains = [];
|
||||
if ($raw !== '') {
|
||||
$items = preg_split('/[\r\n]+/', $raw);
|
||||
$domains = array_values(array_filter(array_map('trim', $items), 'strlen'));
|
||||
}
|
||||
return ['type' => $type, 'domains' => $domains];
|
||||
}
|
||||
|
||||
|
||||
/** 用户协议前台配置(enabled / required / page) */
|
||||
public static function user_agreement_settings(): array {
|
||||
return [
|
||||
'enabled' => !isset(self::get_all()['user_agreement_s']) || !empty(self::get_value('user_agreement_s', true)),
|
||||
'required' => !isset(self::get_all()['user_agreement_check']) || !empty(self::get_value('user_agreement_check', true)),
|
||||
'page' => trim((string) self::get_value('user_agreement_page', '')),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class Capabilities {
|
||||
|
||||
/**
|
||||
* Capability definitions registry.
|
||||
*
|
||||
* @return array<string, array{label:string, roles?:string[], exclude_roles?:string[], default?:array<string,mixed>}>
|
||||
*/
|
||||
public static function cap_definitions(): array {
|
||||
return [
|
||||
'user_report' => ['label' => __('举报其它用户', 'aksrt'), 'default' => ['logged' => true]],
|
||||
'balance_transfer' => ['label' => __('余额转账给其他用户', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'points_transfer' => ['label' => __('积分转账给其他用户', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'balance_withdraw' => ['label' => __('余额提现', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'set_user_ban' => ['label' => __('设置用户封禁状态', 'aksrt'), 'roles' => ['cat_moderator'], 'default' => ['cat_moderator' => true]],
|
||||
'medal_manually_set' => ['label' => __('为用户授予徽章', 'aksrt'), 'roles' => ['cat_moderator'], 'default' => ['cat_moderator' => true]],
|
||||
|
||||
'new_post_add' => ['label' => __('发布新文章', 'aksrt'), 'default' => ['logged' => true]],
|
||||
'new_post_audit_no' => ['label' => __('投稿无需审核直接发布', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_audit_no_manual' => ['label' => __('无需人工审核直接发布', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_upload_img' => ['label' => __('投稿允许上传图片', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_upload_video' => ['label' => __('投稿允许上传视频', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_iframe_video' => ['label' => __('投稿允许插入 iframe 视频', 'aksrt'), 'exclude_roles' => ['all'], 'default' => ['logged' => true]],
|
||||
'new_post_upload_file' => ['label' => __('投稿允许上传文件', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_hide' => ['label' => __('投稿允许发布隐藏内容', 'aksrt'), 'default' => ['logged' => true]],
|
||||
'new_post_image_cover' => ['label' => __('发帖允许设置图片封面', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_slide_cover' => ['label' => __('允许设置幻灯片封面', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_video_cover' => ['label' => __('允许设置视频封面', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_pay' => ['label' => __('投稿允许设置付费内容', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_pay_download' => ['label' => __('投稿允许设置付费下载', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'new_post_edit' => ['label' => __('修改自己发布的投稿', 'aksrt'), 'exclude_roles' => ['all'], 'default' => ['logged' => true]],
|
||||
'new_post_delete' => ['label' => __('删除自己发布的投稿', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
|
||||
'comment_view' => ['label' => __('查看评论', 'aksrt'), 'default' => ['all' => true]],
|
||||
'comment_edit' => ['label' => __('修改自己发布的评论', 'aksrt'), 'exclude_roles' => ['all'], 'default' => ['logged' => true]],
|
||||
'comment_delete' => ['label' => __('删除自己发布的评论', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'comment_audit_no' => ['label' => __('评论无需审核直接发布', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'comment_audit_no_manual' => ['label' => __('评论无需人工审核', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'comment_set_topping_my_post' => ['label' => __('置顶自己文章下的评论', 'aksrt'), 'exclude_roles' => ['all'], 'default' => ['moderator' => true, 'plate_author' => true, 'cat_moderator' => true]],
|
||||
'comment_set_topping_other' => ['label' => __('置顶管理帖子下的评论', 'aksrt'), 'roles' => ['moderator', 'plate_author', 'cat_moderator'], 'default' => ['cat_moderator' => true]],
|
||||
'comment_edit_my_post' => ['label' => __('修改自己文章下的评论', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'comment_edit_other' => ['label' => __('修改管理帖子下的评论', 'aksrt'), 'roles' => ['moderator', 'plate_author', 'cat_moderator'], 'default' => ['cat_moderator' => true]],
|
||||
'comment_audit_my_post' => ['label' => __('审核自己文章下的评论', 'aksrt'), 'exclude_roles' => ['all'], 'default' => ['moderator' => true, 'plate_author' => true, 'cat_moderator' => true]],
|
||||
'comment_audit_other' => ['label' => __('审核管理帖子下的评论', 'aksrt'), 'roles' => ['moderator', 'plate_author', 'cat_moderator'], 'default' => ['moderator' => true, 'plate_author' => true, 'cat_moderator' => true]],
|
||||
'comment_delete_my_post' => ['label' => __('删除自己文章下的评论', 'aksrt'), 'exclude_roles' => ['all']],
|
||||
'comment_delete_other' => ['label' => __('删除管理帖子下的评论', 'aksrt'), 'roles' => ['moderator', 'plate_author', 'cat_moderator'], 'default' => ['cat_moderator' => true]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* All role columns in the capability matrix.
|
||||
*/
|
||||
public static function cap_role_columns(): array {
|
||||
return ['all', 'logged', 'level', 'vip', 'auth', 'moderator', 'plate_author', 'cat_moderator'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the user_caps matrix from settings.
|
||||
*
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
public static function get_user_capabilities(): array {
|
||||
$s = Settings::get_all();
|
||||
$stored = is_array($s['user_caps'] ?? null) ? $s['user_caps'] : [];
|
||||
$defs = self::cap_definitions();
|
||||
$cols = self::cap_role_columns();
|
||||
|
||||
$result = [];
|
||||
foreach ($defs as $cap_id => $def) {
|
||||
$defaults = $def['default'] ?? [];
|
||||
$excludes = $def['exclude_roles'] ?? [];
|
||||
$only_roles = $def['roles'] ?? null;
|
||||
|
||||
$row = [];
|
||||
foreach ($cols as $col) {
|
||||
if ($only_roles !== null && !in_array($col, $only_roles, true) && !in_array($col, ['all', 'logged', 'level', 'vip', 'auth'], true)) {
|
||||
$row[$col] = false;
|
||||
continue;
|
||||
}
|
||||
if (in_array($col, $excludes, true)) {
|
||||
$row[$col] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($stored[$cap_id][$col])) {
|
||||
$val = $stored[$cap_id][$col];
|
||||
$row[$col] = in_array($col, ['level', 'vip'], true) ? (int) $val : (bool) $val;
|
||||
} else {
|
||||
$row[$col] = $defaults[$col] ?? (in_array($col, ['level', 'vip'], true) ? -1 : false);
|
||||
}
|
||||
}
|
||||
$result[$cap_id] = $row;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve whether a user has a specific capability.
|
||||
*/
|
||||
public static function user_can(string $cap, int $user_id = 0, ?int $context = null): bool {
|
||||
if ($user_id > 0 && user_can($user_id, 'manage_options')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$caps = self::get_user_capabilities();
|
||||
if (!isset($caps[$cap])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = $caps[$cap];
|
||||
|
||||
if (!empty($row['all'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user_id <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($row['logged'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$level_threshold = (int) ($row['level'] ?? -1);
|
||||
if ($level_threshold >= 0) {
|
||||
$user_level = class_exists('\AKSRT\User\Level') ? \AKSRT\User\Level::get_level($user_id) : 0;
|
||||
if ($user_level >= $level_threshold) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$vip_threshold = (int) ($row['vip'] ?? -1);
|
||||
if ($vip_threshold >= 0) {
|
||||
$user_vip = function_exists('aksrt_get_user_vip_level') ? aksrt_get_user_vip_level($user_id) : 0;
|
||||
if ($user_vip >= $vip_threshold) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($row['auth'])) {
|
||||
if (class_exists('\\AKSRT\\User\\AuthApply') && \AKSRT\User\AuthApply::is_verified($user_id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"网站安全"设置(人机验证见 aksrt_get_captcha_status_summary)。
|
||||
*/
|
||||
public static function get_security_settings(): array {
|
||||
$s = Settings::get_all();
|
||||
|
||||
$captcha = function_exists('aksrt_get_captcha_status_summary')
|
||||
? aksrt_get_captcha_status_summary()
|
||||
: ['enabled' => false, 'provider' => '', 'configured' => false, 'scenes' => []];
|
||||
|
||||
return [
|
||||
'captcha' => $captcha,
|
||||
'brush_limit_post' => [
|
||||
'enabled' => !empty($s['brush_limit_post_enabled']),
|
||||
'minutes_10' => (int) ($s['brush_limit_post_minutes_10'] ?? 20),
|
||||
'day_1' => (int) ($s['brush_limit_post_day_1'] ?? 50),
|
||||
],
|
||||
'brush_limit_comment' => [
|
||||
'enabled' => !empty($s['brush_limit_comment_enabled']),
|
||||
'minutes_10' => (int) ($s['brush_limit_comment_minutes_10'] ?? 20),
|
||||
'day_1' => (int) ($s['brush_limit_comment_day_1'] ?? 100),
|
||||
],
|
||||
'brush_limit_upload' => [
|
||||
'enabled' => !empty($s['brush_limit_upload_enabled']),
|
||||
'minutes_10' => (int) ($s['brush_limit_upload_minutes_10'] ?? 50),
|
||||
'day_1' => (int) ($s['brush_limit_upload_day_1'] ?? 200),
|
||||
],
|
||||
'brush_limit_register' => [
|
||||
'enabled' => !empty($s['brush_limit_register_enabled']),
|
||||
'minutes_10' => (int) ($s['brush_limit_register_minutes_10'] ?? 20),
|
||||
'day_1' => (int) ($s['brush_limit_register_day_1'] ?? 100),
|
||||
],
|
||||
'brush_limit_order' => [
|
||||
'enabled' => !empty($s['brush_limit_order_enabled']),
|
||||
'minutes_10' => (int) ($s['brush_limit_order_minutes_10'] ?? 30),
|
||||
'day_1' => (int) ($s['brush_limit_order_day_1'] ?? 100),
|
||||
],
|
||||
'error_frequency_limit' => !empty($s['error_frequency_limit'] ?? true),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取"系统工具"设置
|
||||
*/
|
||||
public static function get_system_tools_settings(): array {
|
||||
$s = Settings::get_all();
|
||||
$time_format = sanitize_text_field((string) ($s['time_format'] ?? 'n月j日 H:i'));
|
||||
|
||||
return [
|
||||
'remove_emoji' => !empty($s['remove_emoji'] ?? true),
|
||||
'remove_open_sans' => !empty($s['remove_open_sans'] ?? true),
|
||||
'remove_more_wp_head' => !empty($s['remove_more_wp_head'] ?? true),
|
||||
'hide_admin_bar' => !empty($s['hide_admin_bar'] ?? true),
|
||||
'remove_dashboard_widgets' => !empty($s['remove_dashboard_widgets'] ?? true),
|
||||
'admin_frontend_set' => !empty($s['admin_frontend_set'] ?? true),
|
||||
'display_wp_update' => !empty($s['display_wp_update'] ?? true),
|
||||
'close_gutenberg' => !empty($s['close_gutenberg']),
|
||||
'admin_user_del_fields' => !empty($s['admin_user_del_fields'] ?? true),
|
||||
'split_upload_s' => !empty($s['split_upload_s'] ?? true),
|
||||
'split_minimum_size' => max(4, min(100, (int) ($s['split_minimum_size'] ?? 20))),
|
||||
'newfilename' => !empty($s['newfilename']),
|
||||
'newfilename_type' => in_array($s['newfilename_type'] ?? 'time', ['random', 'time'], true)
|
||||
? $s['newfilename_type'] : 'time',
|
||||
'disabled_large_thumbnail' => !empty($s['disabled_large_thumbnail'] ?? true),
|
||||
'disabled_autoembed' => !empty($s['disabled_autoembed'] ?? true),
|
||||
'mce_float_toolbar' => [
|
||||
'pc_s' => !empty($s['mce_float_toolbar_pc_s'] ?? true),
|
||||
'm_s' => !empty($s['mce_float_toolbar_m_s'] ?? true),
|
||||
],
|
||||
'time_ago_s' => !empty($s['time_ago_s'] ?? true),
|
||||
'time_format' => $time_format,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait CategoryIntegrationGroups {
|
||||
|
||||
/**
|
||||
* 获取分类推荐配置(含默认值)
|
||||
* @return array
|
||||
*/
|
||||
public static function get_category_recommend_settings(): array {
|
||||
return CategoryRuntime::get_category_recommend_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类封面图 URL(带优先级回退)
|
||||
*
|
||||
* 优先级:
|
||||
* 1. aksrt_category_cover_id term meta
|
||||
* 2. 该分类最新一篇有缩略图文章的缩略图
|
||||
* 3. 默认占位图
|
||||
*/
|
||||
public static function get_category_cover_url(int $term_id): string {
|
||||
return CategoryRuntime::get_category_cover_url($term_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类推荐描述(带优先级回退)
|
||||
*
|
||||
* 优先级:
|
||||
* 1. aksrt_category_recommend_desc term meta
|
||||
* 2. 原生 category description
|
||||
* 3. 空字符串
|
||||
*/
|
||||
public static function get_category_recommend_desc(int $term_id): string {
|
||||
return CategoryRuntime::get_category_recommend_desc($term_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理分类推荐缓存
|
||||
*/
|
||||
public static function flush_category_recommend_cache(): void {
|
||||
CategoryRuntime::flush_category_recommend_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类推荐渲染数据(带缓存)
|
||||
*
|
||||
* @param array $settings 分类推荐配置
|
||||
* @return array 每项包含 term_id, name, description, count, link, cover, posts
|
||||
*/
|
||||
public static function get_category_recommend_items(array $settings): array {
|
||||
return CategoryRuntime::get_category_recommend_items($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取底部Tab完整配置
|
||||
* @return array {enabled, scroll_hide, scroll_down_hide, items}
|
||||
*/
|
||||
public static function get_footer_tabbar_settings(): array {
|
||||
return Integration::get_footer_tabbar_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取底部Tab项(仅返回启用的,按排序)
|
||||
* @return array
|
||||
*/
|
||||
public static function get_footer_tabbar_items(): array {
|
||||
return Integration::get_footer_tabbar_items();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章页专属Tab模式
|
||||
* @return string 'default' | 'extend'
|
||||
*/
|
||||
public static function get_footer_tabbar_single(): string {
|
||||
return Integration::get_footer_tabbar_single();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通知系统设置
|
||||
* @return array {read_retention_days, unread_retention_days, max_per_user}
|
||||
*/
|
||||
public static function get_notification_settings(): array {
|
||||
return Integration::get_notification_settings();
|
||||
}
|
||||
|
||||
/** 单项通知是否启用 */
|
||||
public static function notification_enabled(string $type): bool {
|
||||
return Integration::notification_enabled($type);
|
||||
}
|
||||
|
||||
/** user 徽标是否启用 */
|
||||
public static function notification_user_badge_enabled(): bool {
|
||||
return Integration::notification_user_badge_enabled();
|
||||
}
|
||||
|
||||
/** user 徽标是否包含即时提醒 */
|
||||
public static function notification_badge_include_stateful(): bool {
|
||||
return Integration::notification_badge_include_stateful();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取右侧浮动按钮完整配置
|
||||
* @return array {enabled, style, position, scroll_hide, scroll_down_hide, filter_blur, items}
|
||||
*/
|
||||
public static function get_floating_buttons_settings(): array {
|
||||
return Integration::get_floating_buttons_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取右侧浮动按钮项(仅返回启用的,按排序)
|
||||
* @return array
|
||||
*/
|
||||
public static function get_floating_buttons_items(): array {
|
||||
return Integration::get_floating_buttons_items();
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizer 注册(可选)
|
||||
*/
|
||||
public function customizer(\WP_Customize_Manager $wp_customize): void {
|
||||
$wp_customize->add_setting('blogname', ['default' => get_bloginfo('name'), 'type' => 'option']);
|
||||
|
||||
$wp_customize->add_setting('aksrt_logo', [
|
||||
'default' => '',
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
'transport' => 'postMessage',
|
||||
]);
|
||||
$wp_customize->add_control(new \WP_Customize_Image_Control(
|
||||
$wp_customize,
|
||||
'aksrt_logo',
|
||||
['label' => __('Logo', 'aksrt'), 'section' => 'title_tagline']
|
||||
));
|
||||
|
||||
$wp_customize->add_setting('aksrt_favicon', [
|
||||
'default' => '',
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
'transport' => 'postMessage',
|
||||
]);
|
||||
$wp_customize->add_control(new \WP_Customize_Upload_Control(
|
||||
$wp_customize,
|
||||
'aksrt_favicon',
|
||||
['label' => __('Favicon', 'aksrt'), 'section' => 'title_tagline']
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class CategoryRuntime {
|
||||
|
||||
/**
|
||||
* 获取分类推荐配置(含默认值)
|
||||
* @return array
|
||||
*/
|
||||
public static function get_category_recommend_settings(): array {
|
||||
$defaults = [
|
||||
'enable_category_recommend' => false,
|
||||
'category_recommend_title' => __('分类推荐', 'aksrt'),
|
||||
'category_recommend_category_ids' => [],
|
||||
'category_recommend_posts_per_category' => 5,
|
||||
'category_recommend_columns' => 2,
|
||||
'category_recommend_show_description' => true,
|
||||
'category_recommend_show_dates' => true,
|
||||
'category_recommend_show_more_link' => true,
|
||||
];
|
||||
$saved = get_option('aksrt_category_recommend', []);
|
||||
return array_merge($defaults, $saved);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类封面图 URL(带优先级回退)
|
||||
*
|
||||
* 优先级:
|
||||
* 1. aksrt_category_cover_id term meta
|
||||
* 2. 该分类最新一篇有缩略图文章的缩略图
|
||||
* 3. 默认占位图
|
||||
*
|
||||
* @param int $term_id
|
||||
* @return string
|
||||
*/
|
||||
public static function get_category_cover_url(int $term_id): string {
|
||||
$cover_id = (int) get_term_meta($term_id, 'aksrt_category_cover_id', true);
|
||||
if ($cover_id > 0) {
|
||||
$url = wp_get_attachment_url($cover_id);
|
||||
if ($url) {
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
$posts = get_posts([
|
||||
'category__in' => [$term_id],
|
||||
'posts_per_page' => 1,
|
||||
'post_status' => 'publish',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'meta_query' => [
|
||||
[
|
||||
'key' => '_thumbnail_id',
|
||||
'compare' => 'EXISTS',
|
||||
],
|
||||
],
|
||||
'fields' => 'ids',
|
||||
]);
|
||||
|
||||
if (!empty($posts)) {
|
||||
$thumb_url = get_the_post_thumbnail_url($posts[0], 'medium_large');
|
||||
if ($thumb_url) {
|
||||
return $thumb_url;
|
||||
}
|
||||
}
|
||||
|
||||
return get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类推荐描述(带优先级回退)
|
||||
*
|
||||
* 优先级:
|
||||
* 1. aksrt_category_recommend_desc term meta
|
||||
* 2. 原生 category description
|
||||
* 3. 空字符串
|
||||
*
|
||||
* @param int $term_id
|
||||
* @return string
|
||||
*/
|
||||
public static function get_category_recommend_desc(int $term_id): string {
|
||||
$description = (string) get_term_meta($term_id, 'aksrt_category_recommend_desc', true);
|
||||
if ($description !== '') {
|
||||
return $description;
|
||||
}
|
||||
|
||||
$term = get_term($term_id, 'category');
|
||||
if ($term && !is_wp_error($term) && $term->description) {
|
||||
return $term->description;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理分类推荐缓存
|
||||
*/
|
||||
public static function flush_category_recommend_cache(): void {
|
||||
$keys = get_option('aksrt_category_recommend_cache_keys', []);
|
||||
if (is_array($keys)) {
|
||||
foreach ($keys as $key) {
|
||||
delete_transient($key);
|
||||
}
|
||||
}
|
||||
delete_option('aksrt_category_recommend_cache_keys');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类推荐渲染数据(带缓存)
|
||||
*
|
||||
* @param array $settings 分类推荐配置
|
||||
* @return array 每项包含 term_id, name, description, count, link, cover, posts
|
||||
*/
|
||||
public static function get_category_recommend_items(array $settings): array {
|
||||
$category_ids = array_map('absint', (array) ($settings['category_recommend_category_ids'] ?? []));
|
||||
$category_ids = array_filter($category_ids, fn($id) => $id > 0);
|
||||
if (empty($category_ids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$per_page = max(1, min(10, (int) ($settings['category_recommend_posts_per_category'] ?? 5)));
|
||||
$show_desc = !empty($settings['category_recommend_show_description']);
|
||||
$show_dates = !empty($settings['category_recommend_show_dates']);
|
||||
$show_more = !empty($settings['category_recommend_show_more_link']);
|
||||
|
||||
$cache_key = 'aksrt_cr_' . md5(implode(',', $category_ids) . '|' . $per_page . '|' . (int) $show_desc . '|' . (int) $show_dates . '|' . (int) $show_more);
|
||||
$cached = get_transient($cache_key);
|
||||
if ($cached !== false) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$items = [];
|
||||
foreach ($category_ids as $term_id) {
|
||||
$term = get_term($term_id, 'category');
|
||||
if (!$term || is_wp_error($term)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$description = $show_desc ? self::get_category_recommend_desc($term_id) : '';
|
||||
|
||||
$recent_posts = get_posts([
|
||||
'category__in' => [$term_id],
|
||||
'posts_per_page' => $per_page,
|
||||
'post_status' => 'publish',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
]);
|
||||
|
||||
$posts = [];
|
||||
foreach ($recent_posts as $post) {
|
||||
$posts[] = [
|
||||
'title' => get_the_title($post->ID),
|
||||
'link' => get_permalink($post->ID),
|
||||
'date' => get_the_date('Y-m-d', $post->ID),
|
||||
];
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'term_id' => (int) $term_id,
|
||||
'name' => $term->name,
|
||||
'description' => $description,
|
||||
'count' => (int) $term->count,
|
||||
'link' => get_category_link($term_id),
|
||||
'cover' => self::get_category_cover_url($term_id),
|
||||
'posts' => $posts,
|
||||
];
|
||||
}
|
||||
|
||||
set_transient($cache_key, $items, 12 * HOUR_IN_SECONDS);
|
||||
|
||||
$keys = get_option('aksrt_category_recommend_cache_keys', []);
|
||||
if (!is_array($keys)) {
|
||||
$keys = [];
|
||||
}
|
||||
$keys[] = $cache_key;
|
||||
update_option('aksrt_category_recommend_cache_keys', array_unique($keys));
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait CreditsPaymentGroups {
|
||||
|
||||
/**
|
||||
* 积分配置(合并默认值)。
|
||||
* @return array
|
||||
*/
|
||||
public static function get_credit_settings(): array {
|
||||
return CreditsRuntime::get_credit_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalized runtime settings for daily sign-in rewards.
|
||||
*
|
||||
* @return array{enabled:bool,base:int,streak:array<int,int>,currency_name:string}
|
||||
*/
|
||||
public static function get_signin_reward_settings(): array {
|
||||
return CreditsRuntime::get_signin_reward_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalized runtime settings for invite rewards and registration gating.
|
||||
*
|
||||
* @return array{
|
||||
* enabled:bool,
|
||||
* inviter_amount:int,
|
||||
* invitee_amount:int,
|
||||
* require_verify:bool,
|
||||
* ip_daily_cap:int,
|
||||
* register_field:string,
|
||||
* reject_invalid:bool,
|
||||
* registration_enabled:bool
|
||||
* }
|
||||
*/
|
||||
public static function get_invite_reward_settings(): array {
|
||||
return CreditsRuntime::get_invite_reward_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonical invite registration config derived from users.invite fields.
|
||||
*
|
||||
* @return array{
|
||||
* enabled:bool,
|
||||
* mode:string,
|
||||
* register_field:string,
|
||||
* reject_invalid:bool,
|
||||
* code_length:int,
|
||||
* open_desc:string,
|
||||
* must_desc:string
|
||||
* }
|
||||
*/
|
||||
public static function get_invite_registration_config(): array {
|
||||
return CreditsRuntime::get_invite_registration_config();
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分功能是否启用(仅积分系统开关)。
|
||||
*/
|
||||
public static function credits_enabled(): bool {
|
||||
return CreditsRuntime::credits_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义货币名称,为空时回退"积分"。
|
||||
*/
|
||||
public static function get_currency_name(): string {
|
||||
return CreditsRuntime::get_currency_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* 邀请系统是否启用(=积分系统启用 && invite_reward.enabled)。
|
||||
* 用于 UI 入口(个人中心邀请 Tab)的展示门禁。
|
||||
*/
|
||||
public static function invite_enabled(): bool {
|
||||
return CreditsRuntime::invite_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 邀请注册功能总开关(独立于积分系统)。
|
||||
* 控制邀请链接、注册页邀请码字段、用户中心邀请卡片的显示。
|
||||
* 存储在 aksrt_settings(invit_code_s / invite_registration_enabled)。
|
||||
*/
|
||||
public static function invite_registration_enabled(): bool {
|
||||
return CreditsRuntime::invite_registration_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册页邀请码字段模式:'hidden' | 'optional' | 'required'
|
||||
*/
|
||||
public static function invite_register_field_mode(): string {
|
||||
return CreditsRuntime::invite_register_field_mode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 必填模式下邀请码无效是否拒绝注册。
|
||||
*/
|
||||
public static function invite_reject_invalid(): bool {
|
||||
return CreditsRuntime::invite_reject_invalid();
|
||||
}
|
||||
|
||||
public static function invite_code_length(): int {
|
||||
return CreditsRuntime::invite_code_length();
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源下载默认积分价(当资源未单独设价时回退使用)。
|
||||
*/
|
||||
public static function download_default_cost(): int {
|
||||
return CreditsRuntime::download_default_cost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unified paid-content and download policy settings.
|
||||
*
|
||||
* @return array{
|
||||
* download_login:bool,
|
||||
* download_credit:bool,
|
||||
* download_captcha:bool,
|
||||
* default_cost:int,
|
||||
* paid_post_types:string[],
|
||||
* vip_free_download:bool,
|
||||
* vip_exempt_roles:string[],
|
||||
* catalog_note:string,
|
||||
* manual_delivery_note:string
|
||||
* }
|
||||
*/
|
||||
public static function get_paid_content_settings(): array {
|
||||
return PaymentRuntime::get_paid_content_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Content coupon global switches.
|
||||
*
|
||||
* @return array{enabled:bool,desc:string}
|
||||
*/
|
||||
public static function get_content_coupon_settings(): array {
|
||||
return PaymentRuntime::get_content_coupon_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{enabled:bool,mode:string,packages_raw:string,package_count:int,help_text:string}
|
||||
*/
|
||||
public static function get_payment_recharge_settings(): array {
|
||||
return PaymentRuntime::get_payment_recharge_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dual-level VIP settings (Zibll pay_user_vip_1 / pay_user_vip_2).
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_payment_vip_settings(): array {
|
||||
return PaymentRuntime::get_payment_vip_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for callers that expect get_vip_settings() (header CTA, float buttons).
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_vip_settings(): array {
|
||||
return self::get_payment_vip_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{enabled:bool,share_ratio:int,settlement_threshold:int,cycle_days:int,note:string}
|
||||
*/
|
||||
public static function get_payment_revenue_settings(): array {
|
||||
return PaymentRuntime::get_payment_revenue_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{enabled:bool,ratio:int,window_days:int,require_paid_order:bool,note:string}
|
||||
*/
|
||||
public static function get_payment_affiliate_settings(): array {
|
||||
return PaymentRuntime::get_payment_affiliate_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{mode:string,test_enabled:bool,manual_review:bool,callback_secret:string,help_text:string}
|
||||
*/
|
||||
public static function get_payment_gateway_settings(): array {
|
||||
return PaymentRuntime::get_payment_gateway_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单设置
|
||||
*
|
||||
* @return array{prefix:string,expiry:int,show_user:bool,show_paycount:bool,no_logged_in:bool,cookie_day:int,no_logged_remind:bool,wait_float:bool,order_max_minutes:int,mark:string,box_position:string,free_logged_show:bool,show_ip:bool,show_device:bool,show_order_no:bool,show_create_time:bool,show_pay_time:bool,status_texts:array,service:array}
|
||||
*/
|
||||
public static function get_order_settings(): array {
|
||||
return PaymentRuntime::get_order_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取充值卡设置
|
||||
*
|
||||
* @return array{enabled:bool,desc:string,type:string,prefix:string,length:int,batch_size:int,max_redeem:int,expiry_days:int,amount:int,vip_days:int,credits:int,redeem_page:string,success_msg:string,fail_msg:string}
|
||||
*/
|
||||
public static function get_card_pass_settings(): array {
|
||||
return PaymentRuntime::get_card_pass_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取提现管理设置
|
||||
*
|
||||
* @return array{min_amount:int,service_charge_rate:int,text:string}
|
||||
*/
|
||||
public static function get_withdrawal_settings(): array {
|
||||
return PaymentRuntime::get_withdrawal_settings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class CreditsRuntime {
|
||||
|
||||
/**
|
||||
* 积分配置(合并默认值)。
|
||||
* @return array
|
||||
*/
|
||||
public static function get_credit_settings(): array {
|
||||
$defaults = [
|
||||
'enabled' => true,
|
||||
'currency_name' => '',
|
||||
|
||||
'register_bonus' => 10,
|
||||
|
||||
'daily_signin' => [
|
||||
'enabled' => true,
|
||||
'base' => 1,
|
||||
'streak' => [
|
||||
3 => 2,
|
||||
7 => 5,
|
||||
30 => 20,
|
||||
],
|
||||
],
|
||||
|
||||
'comment_reward' => [
|
||||
'enabled' => true,
|
||||
'amount' => 1,
|
||||
'daily_cap' => 5,
|
||||
'min_length' => 10,
|
||||
'on_approved' => true,
|
||||
],
|
||||
|
||||
'invite_reward' => [
|
||||
'enabled' => true,
|
||||
'inviter_amount' => 5,
|
||||
'invitee_amount' => 2,
|
||||
'require_verify' => true,
|
||||
'ip_daily_cap' => 3,
|
||||
'register_field' => 'optional',
|
||||
'reject_invalid' => true,
|
||||
],
|
||||
|
||||
'download_default_cost' => 0,
|
||||
];
|
||||
$saved = get_option('aksrt_credit_settings', []);
|
||||
if (!is_array($saved)) {
|
||||
$saved = [];
|
||||
}
|
||||
return array_replace_recursive($defaults, $saved);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalized runtime settings for daily sign-in rewards.
|
||||
*
|
||||
* @return array{enabled:bool,base:int,streak:array<int,int>,currency_name:string}
|
||||
*/
|
||||
public static function get_signin_reward_settings(): array {
|
||||
$config = self::get_credit_settings();
|
||||
$signin = is_array($config['daily_signin'] ?? null) ? $config['daily_signin'] : [];
|
||||
$streak = [];
|
||||
|
||||
foreach ((array) ($signin['streak'] ?? []) as $day => $bonus) {
|
||||
$day = (int) $day;
|
||||
$bonus = (int) $bonus;
|
||||
if ($day <= 0 || $bonus < 0) {
|
||||
continue;
|
||||
}
|
||||
$streak[$day] = $bonus;
|
||||
}
|
||||
|
||||
ksort($streak, SORT_NUMERIC);
|
||||
|
||||
return [
|
||||
'enabled' => !empty($config['enabled']) && !empty($signin['enabled']),
|
||||
'base' => max(0, (int) ($signin['base'] ?? 0)),
|
||||
'streak' => $streak,
|
||||
'currency_name' => self::get_currency_name(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalized runtime settings for invite rewards and registration gating.
|
||||
*
|
||||
* @return array{
|
||||
* enabled:bool,
|
||||
* inviter_amount:int,
|
||||
* invitee_amount:int,
|
||||
* require_verify:bool,
|
||||
* ip_daily_cap:int,
|
||||
* register_field:string,
|
||||
* reject_invalid:bool,
|
||||
* registration_enabled:bool
|
||||
* }
|
||||
*/
|
||||
public static function get_invite_reward_settings(): array {
|
||||
$config = self::get_credit_settings();
|
||||
$invite = is_array($config['invite_reward'] ?? null) ? $config['invite_reward'] : [];
|
||||
$all = Settings::get_all();
|
||||
$register_field = (string) ($invite['register_field'] ?? 'optional');
|
||||
|
||||
if (!in_array($register_field, ['hidden', 'optional', 'required'], true)) {
|
||||
$register_field = 'optional';
|
||||
}
|
||||
|
||||
$inviter_amount = array_key_exists('invit_reward_points', $all)
|
||||
? max(0, (int) $all['invit_reward_points'])
|
||||
: max(0, (int) ($invite['inviter_amount'] ?? 0));
|
||||
$invitee_enabled = array_key_exists('invit_invitee_reward', $all)
|
||||
? !empty($all['invit_invitee_reward'])
|
||||
: max(0, (int) ($invite['invitee_amount'] ?? 0)) > 0;
|
||||
$invitee_amount = $invitee_enabled
|
||||
? max(0, (int) ($invite['invitee_amount'] ?? $inviter_amount))
|
||||
: 0;
|
||||
|
||||
return [
|
||||
'enabled' => !empty($config['enabled']) && !empty($invite['enabled']),
|
||||
'inviter_amount' => $inviter_amount,
|
||||
'invitee_amount' => $invitee_amount,
|
||||
'require_verify' => !empty($invite['require_verify']),
|
||||
'ip_daily_cap' => max(0, (int) ($invite['ip_daily_cap'] ?? 0)),
|
||||
'register_field' => $register_field,
|
||||
'reject_invalid' => !empty($invite['reject_invalid']),
|
||||
'registration_enabled' => self::invite_registration_enabled(),
|
||||
'invit_reward_points' => $inviter_amount,
|
||||
'invit_reward_level' => max(0, (int) ($all['invit_reward_level'] ?? 0)),
|
||||
'invit_reward_vip_days' => max(0, (int) ($all['invit_reward_vip_days'] ?? 0)),
|
||||
'invit_invitee_reward' => $invitee_enabled,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonical invite registration config derived from users.invite fields.
|
||||
*
|
||||
* @return array{
|
||||
* enabled:bool,
|
||||
* mode:string,
|
||||
* register_field:string,
|
||||
* reject_invalid:bool,
|
||||
* code_length:int,
|
||||
* open_desc:string,
|
||||
* must_desc:string
|
||||
* }
|
||||
*/
|
||||
public static function get_invite_registration_config(): array {
|
||||
$all = Settings::get_all();
|
||||
$credit_config = self::get_credit_settings();
|
||||
|
||||
$enabled = array_key_exists('invit_code_s', $all)
|
||||
? !empty($all['invit_code_s'])
|
||||
: (!isset($all['invite_registration_enabled']) || !empty($all['invite_registration_enabled']));
|
||||
|
||||
$mode = isset($all['invit_code_mode']) ? (string) $all['invit_code_mode'] : '';
|
||||
if (!in_array($mode, ['open', 'must', 'close'], true)) {
|
||||
$legacy_mode = (string) ($credit_config['invite_reward']['register_field'] ?? 'optional');
|
||||
if ($legacy_mode === 'required') {
|
||||
$mode = 'must';
|
||||
} elseif ($legacy_mode === 'hidden') {
|
||||
$mode = 'close';
|
||||
} else {
|
||||
$mode = 'open';
|
||||
}
|
||||
}
|
||||
|
||||
$register_field = 'optional';
|
||||
if (!$enabled || $mode === 'close') {
|
||||
$register_field = 'hidden';
|
||||
} elseif ($mode === 'must') {
|
||||
$register_field = 'required';
|
||||
}
|
||||
|
||||
$open_desc = trim((string) ($all['invit_code_open_desc'] ?? ''));
|
||||
if ($open_desc === '') {
|
||||
$open_desc = __('邀请码为选填,没有邀请码也可以注册', 'aksrt');
|
||||
}
|
||||
|
||||
$must_desc = trim((string) ($all['invit_code_must_desc'] ?? ''));
|
||||
if ($must_desc === '') {
|
||||
$must_desc = __('请输入邀请码', 'aksrt');
|
||||
}
|
||||
|
||||
$code_length = isset($all['invit_code_length']) ? (int) $all['invit_code_length'] : 0;
|
||||
if ($code_length <= 0) {
|
||||
$code_length = (int) ($all['invite_code_length'] ?? 6);
|
||||
}
|
||||
$code_length = max(4, min(12, $code_length));
|
||||
|
||||
return [
|
||||
'enabled' => $enabled && $mode !== 'close',
|
||||
'mode' => $mode,
|
||||
'register_field' => $register_field,
|
||||
'reject_invalid' => !empty($credit_config['invite_reward']['reject_invalid']),
|
||||
'code_length' => $code_length,
|
||||
'open_desc' => $open_desc,
|
||||
'must_desc' => $must_desc,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分功能是否启用。
|
||||
* 仅看积分系统开关;不再与 cms_features.download_credit 联合(该开关表示积分购买模式,非按次扣费)。
|
||||
*/
|
||||
public static function credits_enabled(): bool {
|
||||
$config = self::get_credit_settings();
|
||||
return !empty($config['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义货币名称,为空时回退"积分"。
|
||||
*/
|
||||
public static function get_currency_name(): string {
|
||||
$config = self::get_credit_settings();
|
||||
$name = trim((string) ($config['currency_name'] ?? ''));
|
||||
return $name !== '' ? $name : __('积分', 'aksrt');
|
||||
}
|
||||
|
||||
/**
|
||||
* 邀请系统是否启用(=积分系统启用 && invite_reward.enabled)。
|
||||
* 用于 UI 入口(个人中心邀请 Tab)的展示门禁。
|
||||
*/
|
||||
public static function invite_enabled(): bool {
|
||||
$config = self::get_credit_settings();
|
||||
return !empty($config['enabled']) && !empty($config['invite_reward']['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 邀请注册功能总开关(独立于积分系统)。
|
||||
* 控制邀请链接、注册页邀请码字段、用户中心邀请卡片的显示。
|
||||
* 存储在 aksrt_settings(invit_code_s / invite_registration_enabled)。
|
||||
*/
|
||||
public static function invite_registration_enabled(): bool {
|
||||
return !empty(self::get_invite_registration_config()['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册页邀请码字段模式:'hidden' | 'optional' | 'required'
|
||||
*/
|
||||
public static function invite_register_field_mode(): string {
|
||||
$mode = (string) (self::get_invite_registration_config()['register_field'] ?? 'hidden');
|
||||
return in_array($mode, ['hidden', 'optional', 'required'], true) ? $mode : 'hidden';
|
||||
}
|
||||
|
||||
/**
|
||||
* 必填模式下邀请码无效是否拒绝注册。
|
||||
*/
|
||||
public static function invite_reject_invalid(): bool {
|
||||
return !empty(self::get_invite_registration_config()['reject_invalid']);
|
||||
}
|
||||
|
||||
public static function invite_code_length(): int {
|
||||
return max(4, min(12, (int) (self::get_invite_registration_config()['code_length'] ?? 6)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源下载默认积分价(当资源未单独设价时回退使用)。
|
||||
*/
|
||||
public static function download_default_cost(): int {
|
||||
$config = self::get_credit_settings();
|
||||
return max(0, (int) ($config['download_default_cost'] ?? 0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait DisplayPageGroups {
|
||||
|
||||
/**
|
||||
* 获取 SEO 设置(从 aksrt_settings 读取)
|
||||
*/
|
||||
public static function get_seo_settings(): array {
|
||||
$s = self::get_all();
|
||||
return [
|
||||
'seo_enabled' => !isset($s['seo_enabled']) || !empty($s['seo_enabled']),
|
||||
'seo_connector' => trim((string) ($s['seo_connector'] ?? '-')),
|
||||
'seo_title' => $s['seo_title'] ?? '',
|
||||
'seo_description' => $s['seo_description'] ?? '',
|
||||
'seo_keywords' => self::seo_keywords(),
|
||||
'seo_ai_enabled' => !empty($s['seo_ai_enabled']),
|
||||
'ai_seo_title_prompt' => trim((string) ($s['ai_seo_title_prompt'] ?? '')),
|
||||
'ai_seo_keywords_prompt' => trim((string) ($s['ai_seo_keywords_prompt'] ?? '')),
|
||||
'ai_seo_description_prompt' => trim((string) ($s['ai_seo_description_prompt'] ?? '')),
|
||||
'seo_baidu_push' => !empty($s['seo_baidu_push']) || !empty($s['baidu_push_enabled']),
|
||||
'seo_baidu_normal' => !empty($s['seo_baidu_normal']),
|
||||
'seo_baidu_fast' => !empty($s['seo_baidu_fast']),
|
||||
'seo_baidu_token' => (string) (($s['seo_baidu_token'] ?? '') ?: ($s['baidu_push_token'] ?? '')),
|
||||
'seo_image_optimize' => !isset($s['seo_image_optimize']) || !empty($s['seo_image_optimize']),
|
||||
'seo_image_default' => esc_url_raw((string) ($s['seo_image_default'] ?? '')),
|
||||
'seo_image_always_default'=> !empty($s['seo_image_always_default']),
|
||||
'seo_auto_alt' => !isset($s['seo_auto_alt']) || !empty($s['seo_auto_alt']),
|
||||
'seo_go_link' => !isset($s['seo_go_link']) || !empty($s['seo_go_link']),
|
||||
'seo_go_link_nonce' => !isset($s['seo_go_link_nonce']) || !empty($s['seo_go_link_nonce']),
|
||||
'seo_go_link_post' => !isset($s['seo_go_link_post']) || !empty($s['seo_go_link_post']),
|
||||
'seo_go_link_exclude' => trim((string) ($s['seo_go_link_exclude'] ?? '')),
|
||||
'seo_no_category' => !empty($s['seo_no_category']),
|
||||
'seo_jsonld' => !isset($s['seo_jsonld']) || !empty($s['seo_jsonld']),
|
||||
'seo_jsonld_single' => !isset($s['seo_jsonld_single']) || !empty($s['seo_jsonld_single']),
|
||||
'seo_jsonld_page' => !isset($s['seo_jsonld_page']) || !empty($s['seo_jsonld_page']),
|
||||
'head_code' => self::custom_head_code(),
|
||||
'foot_code' => self::custom_footer_code(),
|
||||
'trackcode' => self::trackcode(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶部多功能组件设置
|
||||
*/
|
||||
public static function get_header_components_settings(): array {
|
||||
$s = self::get_all();
|
||||
$allowed_page_types = [
|
||||
'home',
|
||||
'topics',
|
||||
'category',
|
||||
'tag',
|
||||
'author',
|
||||
'single',
|
||||
'search',
|
||||
'page',
|
||||
];
|
||||
$show_on = isset($s['header_components_show_on']) ? (array) $s['header_components_show_on'] : ['home'];
|
||||
$show_on = array_values(array_intersect(
|
||||
array_map('sanitize_key', $show_on),
|
||||
$allowed_page_types
|
||||
));
|
||||
$show_type = $s['header_components_device_visibility'] ?? '';
|
||||
if (!in_array($show_type, ['', 'only_pc', 'only_sm'], true)) {
|
||||
$show_type = '';
|
||||
}
|
||||
return [
|
||||
'search_enabled' => self::header_components_search_enabled(),
|
||||
'search_config' => self::get_header_components_search_config(),
|
||||
'cards_enabled' => self::header_components_cards_enabled(),
|
||||
'show_on_pages' => $show_on,
|
||||
'show_type' => $show_type,
|
||||
'filter_blur' => isset($s['header_components_filter_blur_devices']) ? array_values(array_intersect(array_map('sanitize_key', (array) $s['header_components_filter_blur_devices']), ['pc', 'mobile'])) : [],
|
||||
'card_show' => isset($s['header_components_card_show_devices']) ? array_values(array_intersect(array_map('sanitize_key', (array) $s['header_components_card_show_devices']), ['pc', 'mobile'])) : ['pc', 'mobile'],
|
||||
'slider_config' => self::get_slider_config(),
|
||||
'icon_cards' => self::get_header_components_icon_cards(),
|
||||
'card_columns' => self::get_header_components_card_columns(),
|
||||
'card_bg_enabled' => self::header_components_card_bg_enabled(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"全局&功能"域的合并设置
|
||||
*/
|
||||
public static function get_global_settings(): array {
|
||||
return [
|
||||
'site_logo' => self::logo_url(),
|
||||
'site_logo_dark' => self::logo_dark_url(),
|
||||
'logo_text' => self::logo_text(),
|
||||
'logo_width' => self::logo_width(),
|
||||
'site_favicon' => self::favicon_url(),
|
||||
'icp_filing' => self::icp_filing(),
|
||||
'footer_text' => self::footer_text(),
|
||||
'theme_mode' => self::theme_mode(),
|
||||
'theme_mode_button' => self::get_theme_mode_button_positions(),
|
||||
'primary_color' => self::primary_color(),
|
||||
'border_radius' => self::border_radius(),
|
||||
'theme_main_radius' => self::card_radius(),
|
||||
'qj_loading' => self::is_qj_loading_enabled(),
|
||||
'qj_dh_xs' => self::get_qj_loading_style(),
|
||||
'container_max_width' => self::container_max_width(),
|
||||
'font_family' => self::font_family(),
|
||||
'search_type' => self::search_mode(),
|
||||
'search_placeholder' => self::search_placeholder(),
|
||||
'search_history_enabled' => self::search_history_enabled(),
|
||||
'hot_search_enabled' => self::hot_search_enabled(),
|
||||
'hot_search_keywords' => self::hot_search_keywords(),
|
||||
'search_suggestions_enabled' => self::search_suggestions_enabled(),
|
||||
'search_posts' => self::search_posts_enabled(),
|
||||
'search_no_page' => self::search_no_page(),
|
||||
'search_exclude_cats' => self::search_exclude_cats(),
|
||||
'search_cat' => self::search_cat_enabled(),
|
||||
'search_cat_in' => self::search_cat_in(),
|
||||
'search_more_cat_obj' => self::search_more_cat_obj(),
|
||||
'search_custom_key_s' => self::search_custom_key_enabled(),
|
||||
'search_custom_key' => self::search_custom_key(),
|
||||
'search_facets' => self::search_facets_enabled(),
|
||||
'search_facets_order' => self::search_facets_order(),
|
||||
'custom_css' => self::custom_css(),
|
||||
'head_code' => self::custom_head_code(),
|
||||
'foot_code' => self::custom_footer_code(),
|
||||
'trackcode' => self::trackcode(),
|
||||
'seo' => self::get_seo_settings(),
|
||||
'mail' => self::get_smtp(),
|
||||
'email_events' => self::get_email_event_config(),
|
||||
'email_private_receive_limit' => self::get_email_private_receive_limit(),
|
||||
'footer' => self::get_footer_settings(),
|
||||
'tabbar' => self::get_footer_tabbar_settings(),
|
||||
'floating_buttons' => self::get_floating_buttons_settings(),
|
||||
'header_nav' => self::get_header_nav_settings(),
|
||||
'header_newposts' => self::get_header_newposts_config(),
|
||||
'header_theme' => self::get_header_theme_config(),
|
||||
'friend_links' => self::get_friend_links(),
|
||||
'comment_enabled' => self::comment_enabled(),
|
||||
'cms_features' => self::get_cms_features(),
|
||||
'page_display' => self::get_page_display_settings(),
|
||||
'footer_theme' => self::get_footer_theme_config(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"页面&显示"域的合并设置
|
||||
*/
|
||||
public static function get_page_display_settings(): array {
|
||||
return [
|
||||
'header_components' => self::get_header_components_settings(),
|
||||
'homepage' => self::get_homepage_fixed_settings(),
|
||||
'category_recommend' => self::get_category_recommend_settings(),
|
||||
'category' => self::get_category_page_settings(),
|
||||
'tag' => self::get_tag_page_settings(),
|
||||
'special' => self::get_special_page_settings(),
|
||||
'user_home' => self::get_user_home_settings(),
|
||||
'other' => self::get_other_page_settings(),
|
||||
'background' => self::get_global_background_settings(),
|
||||
'menu_decoration' => function_exists('aksrt_get_menu_decoration_settings')
|
||||
? aksrt_get_menu_decoration_settings()
|
||||
: [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"文章&列表"域的合并设置
|
||||
*/
|
||||
public static function get_post_list_settings(): array {
|
||||
$list = self::get_post_list_style_settings();
|
||||
$thumb = self::get_post_thumb_settings();
|
||||
$filter = self::get_post_filter_settings();
|
||||
|
||||
return [
|
||||
'list' => [
|
||||
'post_card_style' => $list['list_type'] ?? $list['card_style'] ?? 'thumb',
|
||||
'post_list_author' => $list['show_author'],
|
||||
'post_show_date' => $list['show_date'],
|
||||
'post_show_views' => $list['show_views'],
|
||||
'post_show_category' => $list['show_category'],
|
||||
'post_show_comments' => $list['show_comments'],
|
||||
'post_show_likes' => $list['show_likes'],
|
||||
'post_excerpt_length' => $list['excerpt_length'],
|
||||
'paging_ajax_s' => PostDisplay::is_list_paging_ajax() ? '1' : '0',
|
||||
'paging_ajax_ias_s' => PostDisplay::is_list_paging_ajax_ias(),
|
||||
'post_pagination_mode' => self::get_post_pagination_mode(),
|
||||
'render_mode' => $list['render_mode'],
|
||||
'sticky_s' => $list['sticky_pages'],
|
||||
'list_badge_show' => $list['badge_types'],
|
||||
'target_blank' => $list['target_blank'],
|
||||
'item_heading_bold' => $list['heading_bold'],
|
||||
'list_meta_show' => $list['mobile_meta'],
|
||||
'list_show_type' => $list['list_show_type'],
|
||||
'ias_max' => $list['ias_max'],
|
||||
'ajax_trigger' => $list['ajax_trigger_text'],
|
||||
'ajax_nomore' => $list['ajax_nomore_text'],
|
||||
'ajax_nomore_text' => $list['ajax_nomore_text'],
|
||||
'post_list_columns' => $list['columns'],
|
||||
'post_list_per_page' => $list['per_page'],
|
||||
'list_list_style' => $list['list_style'],
|
||||
'list_list_img_position' => $list['list_img_position'],
|
||||
'list_list_scale' => $list['list_scale'],
|
||||
'list_card_style' => $list['card_variant'] ?? '',
|
||||
'list_card_scale' => $list['card_scale'],
|
||||
'list_card_home' => $list['card_home'],
|
||||
'list_card_cat' => $list['card_cat_ids'] ?? [],
|
||||
'list_card_tag' => $list['card_tag'],
|
||||
'list_card_topics' => $list['card_topics'],
|
||||
'list_card_author' => $list['card_author'],
|
||||
],
|
||||
'thumb' => [
|
||||
'thumb_priority' => implode(',', $thumb['priority']),
|
||||
'thumb_fallback' => $thumb['fallback'],
|
||||
'thumb_spare_images' => $thumb['spare_images'],
|
||||
'thumb_lazy' => $thumb['lazy'],
|
||||
'thumb_aspect_ratio' => $thumb['aspect_ratio'],
|
||||
'thumb_multi_enabled' => $thumb['multi_enabled'],
|
||||
'thumb_multi_count' => $thumb['multi_count'],
|
||||
'list_thumb_fit' => $thumb['fit'],
|
||||
'list_thumb_slides_s' => $thumb['slides_s'],
|
||||
'list_thumb_video_s' => $thumb['video_s'],
|
||||
'list_thumb_video_mute_s' => $thumb['video_mute_s'],
|
||||
'thumb_postfirstimg_s' => $thumb['postfirstimg_s'],
|
||||
'thumb_catimg_s' => $thumb['catimg_s'],
|
||||
],
|
||||
'filter' => [
|
||||
'filter_enabled' => $filter['enabled'],
|
||||
'filter_categories' => $filter['categories'],
|
||||
'filter_tags' => $filter['tags'],
|
||||
'filter_sort' => $filter['sort'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"用户&互动"域的合并设置
|
||||
*/
|
||||
public static function get_user_interaction_settings(): array {
|
||||
return [
|
||||
'oauth' => self::get_oauth(),
|
||||
'notifications' => self::get_notification_settings(),
|
||||
'credits' => self::get_credit_settings(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"功能&权限"域的合并设置
|
||||
*/
|
||||
public static function get_permission_settings(): array {
|
||||
return [
|
||||
'moderation' => self::get_moderation(),
|
||||
'capabilities' => self::get_user_capabilities(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"支付&付费"域的合并设置
|
||||
*/
|
||||
public static function get_payment_settings(): array {
|
||||
return [
|
||||
'paid' => self::get_paid_content_settings(),
|
||||
'recharge' => self::get_payment_recharge_settings(),
|
||||
'vip' => self::get_payment_vip_settings(),
|
||||
'revenue' => self::get_payment_revenue_settings(),
|
||||
'affiliate' => self::get_payment_affiliate_settings(),
|
||||
'gateway' => self::get_payment_gateway_settings(),
|
||||
'order' => self::get_order_settings(),
|
||||
'card_pass' => self::get_card_pass_settings(),
|
||||
'withdrawal' => self::get_withdrawal_settings(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 IP 归属地设置
|
||||
*/
|
||||
public static function get_ip_geo_settings(): array {
|
||||
return ExtensionRuntime::get_ip_geo_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容审核设置
|
||||
*/
|
||||
public static function get_content_audit_settings(): array {
|
||||
return ExtensionRuntime::get_content_audit_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取搜索引擎推送设置
|
||||
*/
|
||||
public static function get_search_push_settings(): array {
|
||||
return ExtensionRuntime::get_search_push_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取短信接口设置
|
||||
*/
|
||||
public static function get_sms_settings(): array {
|
||||
return ExtensionRuntime::get_sms_settings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class DisplayRuntime {
|
||||
|
||||
/** 获取Banner列表 */
|
||||
public static function get_banners(string $position = ''): array {
|
||||
$banners = get_option('aksrt_banners', []) ?: [];
|
||||
|
||||
if ($position) {
|
||||
$banners = array_filter($banners, fn($banner) => ($banner['position'] ?? '') === $position);
|
||||
}
|
||||
|
||||
usort($banners, fn($a, $b) => ($a['sort_order'] ?? 0) - ($b['sort_order'] ?? 0));
|
||||
|
||||
return array_filter($banners, fn($banner) => ($banner['status'] ?? 'enabled') === 'enabled');
|
||||
}
|
||||
|
||||
/** 保存Banner */
|
||||
public static function save_banner(array $data): int {
|
||||
$banners = get_option('aksrt_banners', []);
|
||||
if (!empty($data['id'])) {
|
||||
$banners[$data['id']] = $data;
|
||||
} else {
|
||||
$data['id'] = uniqid('banner_');
|
||||
$banners[] = $data;
|
||||
}
|
||||
update_option('aksrt_banners', $banners);
|
||||
return $data['id'];
|
||||
}
|
||||
|
||||
/** 删除Banner */
|
||||
public static function delete_banner(string $id): void {
|
||||
$banners = get_option('aksrt_banners', []);
|
||||
unset($banners[$id]);
|
||||
update_option('aksrt_banners', array_values($banners));
|
||||
}
|
||||
|
||||
/** 获取友链列表 */
|
||||
public static function get_friend_links(): array {
|
||||
$links = get_option('aksrt_friend_links', []) ?: [];
|
||||
|
||||
return array_values(array_filter($links, static function ($link) {
|
||||
return !empty($link['active']);
|
||||
}));
|
||||
}
|
||||
|
||||
/** 保存友链 */
|
||||
public static function save_friend_links(array $links): void {
|
||||
update_option('aksrt_friend_links', $links);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否显示顶部组件搜索覆盖框
|
||||
*/
|
||||
public static function header_components_search_enabled(): bool {
|
||||
$settings = Settings::get_all();
|
||||
return !empty($settings['header_components_search_enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hero 搜索组件详细配置(PC/移动分别 + 子选项)
|
||||
*
|
||||
* @return array{pc:bool,mobile:bool,show:bool,show_keywords:bool,popular_limit:int,show_input_cat:bool,show_type:bool,keywords:string[],categories:array,type_options:array,before_html:string,after_html:string}
|
||||
*/
|
||||
public static function get_header_components_search_config(): array {
|
||||
$settings = Settings::get_all();
|
||||
$master = self::header_components_search_enabled();
|
||||
$is_mobile = function_exists('wp_is_mobile') && wp_is_mobile();
|
||||
|
||||
$pc_on = $master && (!isset($settings['header_components_search_pc']) || !empty($settings['header_components_search_pc']));
|
||||
$mobile_on = $master && (!isset($settings['header_components_search_mobile']) || !empty($settings['header_components_search_mobile']));
|
||||
$show = $is_mobile ? $mobile_on : $pc_on;
|
||||
|
||||
$show_kw = !empty($settings['header_components_search_show_keywords']);
|
||||
$kw_limit = max(1, min(50, (int) ($settings['header_components_search_popular_limit'] ?? 6)));
|
||||
$show_cat = !empty($settings['header_components_search_show_input_cat']);
|
||||
$show_type = !empty($settings['header_components_search_show_type']);
|
||||
$in_cat = sanitize_text_field((string) ($settings['header_components_search_in_cat'] ?? ''));
|
||||
$in_type = sanitize_key((string) ($settings['header_components_search_in_type'] ?? 'post')) ?: 'post';
|
||||
$more_cats = isset($settings['header_components_search_more_cats'])
|
||||
? array_values(array_filter(array_map('absint', (array) $settings['header_components_search_more_cats'])))
|
||||
: [];
|
||||
|
||||
// Mobile: hide hot keywords (zibll).
|
||||
if ($is_mobile) {
|
||||
$show_kw = false;
|
||||
}
|
||||
|
||||
$keywords = [];
|
||||
if ($show && $show_kw) {
|
||||
if (function_exists('aksrt_get_search_hot_keywords')) {
|
||||
$keywords = (array) aksrt_get_search_hot_keywords();
|
||||
} else {
|
||||
$raw = $settings['hot_search_keywords'] ?? '';
|
||||
$keywords = is_array($raw) ? $raw : preg_split('/[\s,]+/', (string) $raw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
$keywords = array_slice(array_map('sanitize_text_field', array_values($keywords)), 0, $kw_limit);
|
||||
}
|
||||
|
||||
$categories = [];
|
||||
if ($show && $show_cat) {
|
||||
$cat_args = ['hide_empty' => true, 'number' => 50];
|
||||
if ($more_cats) {
|
||||
$cat_args['include'] = $more_cats;
|
||||
$cat_args['orderby'] = 'include';
|
||||
$cat_args['hide_empty'] = false;
|
||||
}
|
||||
$cats = get_categories($cat_args);
|
||||
foreach ($cats as $cat) {
|
||||
$categories[] = ['id' => (int) $cat->term_id, 'name' => (string) $cat->name];
|
||||
}
|
||||
}
|
||||
|
||||
$type_options = [];
|
||||
if ($show && $show_type) {
|
||||
$types = Settings::get_search_content_types();
|
||||
$labels = [
|
||||
'post' => __('文章', 'aksrt'),
|
||||
'user' => __('用户', 'aksrt'),
|
||||
'page' => __('页面', 'aksrt'),
|
||||
];
|
||||
$enabled = $types['enabled'] ?? $types;
|
||||
if (is_array($enabled)) {
|
||||
foreach ($enabled as $type_key => $type_value) {
|
||||
// Support both map[key=>bool] and list of keys.
|
||||
if (is_int($type_key) && is_string($type_value)) {
|
||||
$k = $type_value;
|
||||
$on = true;
|
||||
} else {
|
||||
$k = (string) $type_key;
|
||||
$on = (bool) $type_value;
|
||||
}
|
||||
if (!$on || $k === '') {
|
||||
continue;
|
||||
}
|
||||
$type_options[] = [
|
||||
'key' => $k,
|
||||
'label' => $labels[$k] ?? $k,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$before_html = isset($settings['header_components_search_before_html'])
|
||||
? (string) $settings['header_components_search_before_html']
|
||||
: '';
|
||||
$after_html = isset($settings['header_components_search_after_html'])
|
||||
? (string) $settings['header_components_search_after_html']
|
||||
: '';
|
||||
|
||||
return [
|
||||
'pc' => $pc_on,
|
||||
'mobile' => $mobile_on,
|
||||
'show' => $show,
|
||||
'show_keywords' => $show_kw,
|
||||
'popular_limit' => $kw_limit,
|
||||
'show_input_cat' => $show_cat,
|
||||
'show_type' => $show_type,
|
||||
'in_cat' => $in_cat,
|
||||
'in_type' => $in_type,
|
||||
'more_cats' => $more_cats,
|
||||
'keywords' => $keywords,
|
||||
'categories' => $categories,
|
||||
'type_options' => $type_options,
|
||||
'before_html' => $before_html,
|
||||
'after_html' => $after_html,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public static function header_components_cards_enabled(): bool {
|
||||
$settings = Settings::get_all();
|
||||
return !empty($settings['header_components_cards_enabled']);
|
||||
}
|
||||
|
||||
public static function homepage_module_hero_enabled(): bool {
|
||||
$settings = Settings::get_all();
|
||||
return !isset($settings['homepage_module_hero_enabled']) || !empty($settings['homepage_module_hero_enabled']);
|
||||
}
|
||||
|
||||
public static function homepage_module_banner_enabled(): bool {
|
||||
$settings = Settings::get_all();
|
||||
return !isset($settings['homepage_module_banner_enabled']) || !empty($settings['homepage_module_banner_enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Global slider configuration shared by Hero and Banner.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_slider_config(): array {
|
||||
$settings = Settings::get_all();
|
||||
$config = $settings['slider_config'] ?? [];
|
||||
|
||||
return [
|
||||
'effect' => in_array($config['effect'] ?? '', ['fade', 'slide', 'cube', 'coverflow', 'flip'], true) ? $config['effect'] : 'fade',
|
||||
'direction' => in_array($settings['slider_config_direction'] ?? ($config['direction'] ?? ''), ['horizontal', 'vertical'], true)
|
||||
? ($settings['slider_config_direction'] ?? ($config['direction'] ?? 'horizontal')) : 'horizontal',
|
||||
'loop' => !isset($config['loop']) || !empty($config['loop']),
|
||||
'autoplay_interval' => max(1000, min(30000, (int) ($config['autoplay_interval'] ?? 5000))),
|
||||
'pagination' => !isset($config['pagination']) || !empty($config['pagination']),
|
||||
'navigation' => !isset($config['navigation']) || !empty($config['navigation']),
|
||||
'button' => isset($settings['slider_config_button']) ? !empty($settings['slider_config_button']) : (!isset($config['button']) || !empty($config['button'])),
|
||||
'auto_height' => !empty($config['auto_height']),
|
||||
'pc_height' => isset($config['pc_height']) && $config['pc_height'] !== '' ? sanitize_text_field($config['pc_height']) : '',
|
||||
'mobile_height' => isset($config['mobile_height']) && $config['mobile_height'] !== '' ? sanitize_text_field($config['mobile_height']) : '',
|
||||
'max_height' => isset($settings['slider_config_max_height']) && $settings['slider_config_max_height'] !== '' ? sanitize_text_field($settings['slider_config_max_height']) : (isset($config['max_height']) && $config['max_height'] !== '' ? sanitize_text_field($config['max_height']) : ''),
|
||||
'min_height' => isset($settings['slider_config_min_height']) && $settings['slider_config_min_height'] !== '' ? sanitize_text_field($settings['slider_config_min_height']) : (isset($config['min_height']) && $config['min_height'] !== '' ? sanitize_text_field($config['min_height']) : ''),
|
||||
'scale_height' => !empty($settings['slider_config_scale_height'] ?? ($config['scale_height'] ?? false)),
|
||||
'scale' => !empty($settings['slider_config_scale'] ?? ($config['scale'] ?? false)),
|
||||
'speed' => max(100, min(3000, (int) ($settings['slider_config_speed'] ?? ($config['speed'] ?? 300)))),
|
||||
'space_between' => max(0, min(100, (int) ($config['space_between'] ?? 0))),
|
||||
'nav_color' => sanitize_hex_color((string) ($settings['header_components_nav_color'] ?? '')) ?: '',
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_header_components_icon_cards(): array {
|
||||
$settings = Settings::get_all();
|
||||
$cards = $settings['header_components_icon_cards'] ?? [];
|
||||
return is_array($cards) ? array_values($cards) : [];
|
||||
}
|
||||
|
||||
public static function get_header_components_card_columns(): int {
|
||||
$settings = Settings::get_all();
|
||||
$columns = (int) ($settings['header_components_card_columns'] ?? 4);
|
||||
return max(2, min(6, $columns));
|
||||
}
|
||||
|
||||
public static function header_components_card_bg_enabled(): bool {
|
||||
$settings = Settings::get_all();
|
||||
return !empty($settings['header_components_card_bg']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局背景设置
|
||||
*/
|
||||
public static function get_global_background_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$valid_sizes = ['cover', 'contain', 'auto', '100%', '100% 100%'];
|
||||
$size = sanitize_text_field((string) ($settings['bg_size'] ?? '100%'));
|
||||
if (!in_array($size, $valid_sizes, true)) {
|
||||
$size = '100%';
|
||||
}
|
||||
|
||||
$valid_positions = ['center center', 'top center', 'bottom center'];
|
||||
$position = sanitize_text_field((string) ($settings['bg_position'] ?? 'center center'));
|
||||
if (!in_array($position, $valid_positions, true)) {
|
||||
$position = 'center center';
|
||||
}
|
||||
|
||||
$valid_repeats = ['no-repeat', 'repeat', 'repeat-x', 'repeat-y'];
|
||||
$repeat = sanitize_key((string) ($settings['bg_repeat'] ?? 'no-repeat'));
|
||||
if (!in_array($repeat, $valid_repeats, true)) {
|
||||
$repeat = 'no-repeat';
|
||||
}
|
||||
|
||||
$attachment = sanitize_key((string) ($settings['bg_attachment'] ?? 'fixed'));
|
||||
if (!in_array($attachment, ['fixed', 'scroll'], true)) {
|
||||
$attachment = 'fixed';
|
||||
}
|
||||
|
||||
return [
|
||||
'bg_color' => sanitize_hex_color((string) ($settings['bg_color'] ?? '')) ?: '',
|
||||
'bg_image' => esc_url_raw((string) ($settings['bg_image'] ?? '')),
|
||||
'bg_size' => $size,
|
||||
'bg_position' => $position,
|
||||
'bg_repeat' => $repeat,
|
||||
'bg_attachment' => $attachment,
|
||||
'bg_dark_color' => sanitize_hex_color((string) ($settings['bg_dark_color'] ?? '')) ?: '',
|
||||
'bg_dark_image' => esc_url_raw((string) ($settings['bg_dark_image'] ?? '')),
|
||||
'bg_overlay' => !empty($settings['bg_overlay']),
|
||||
'bg_overlay_color' => sanitize_text_field((string) ($settings['bg_overlay_color'] ?? 'rgba(0, 0, 0, 0.3)')),
|
||||
'page_bg_color' => sanitize_hex_color((string) ($settings['page_bg_color'] ?? '')) ?: '',
|
||||
'page_bg_image' => esc_url_raw((string) ($settings['page_bg_image'] ?? '')),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait DomainGroups {
|
||||
|
||||
/**
|
||||
* 获取微信通知设置
|
||||
*
|
||||
* @return array{enabled:bool,app_id:string,app_secret:string,template_id:string}
|
||||
*/
|
||||
public static function get_wechat_settings(): array {
|
||||
return Integration::get_wechat_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新微信通知设置
|
||||
*
|
||||
* @param array $settings 合并后的完整微信配置
|
||||
*/
|
||||
public static function update_wechat_settings(array $settings): void {
|
||||
Integration::update_wechat_settings($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档模式设置
|
||||
*/
|
||||
public static function get_docs_mode_settings(): array {
|
||||
return Integration::get_docs_mode_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局背景设置
|
||||
*/
|
||||
public static function get_global_background_settings(): array {
|
||||
return DisplayRuntime::get_global_background_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页脚布局模板
|
||||
*/
|
||||
public static function get_footer_layout_template(): string {
|
||||
$footer = self::get_footer_settings();
|
||||
$template = sanitize_key((string) ($footer['layout_template'] ?? 'template_1'));
|
||||
// Legacy aliases map onto Zibll template_1 shell.
|
||||
if (in_array($template, ['default', 'compact', 'centered', 'template_1'], true)) {
|
||||
return 'template_1';
|
||||
}
|
||||
return 'template_1';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮件事件配置
|
||||
*
|
||||
* @param string $event 事件类型,留空返回全部
|
||||
* @return array 单个事件配置或全部事件数组
|
||||
*/
|
||||
public static function get_email_event_config(string $event = ''): array {
|
||||
return Mail::get_email_event_config($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮件事件是否启用
|
||||
*/
|
||||
public static function is_email_event_enabled(string $event): bool {
|
||||
return Mail::is_email_event_enabled($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过邮件事件体系发送邮件
|
||||
*/
|
||||
public static function send_event_email(
|
||||
string $event,
|
||||
string $to,
|
||||
string $default_subject,
|
||||
string $default_content,
|
||||
array $placeholders = []
|
||||
): bool {
|
||||
return Mail::send_event_email($event, $to, $default_subject, $default_content, $placeholders);
|
||||
}
|
||||
|
||||
/** 禁封设置 */
|
||||
public static function ban_settings(): array {
|
||||
return UserRuntime::ban_settings();
|
||||
}
|
||||
|
||||
/** 举报设置 */
|
||||
public static function report_settings(): array {
|
||||
return UserRuntime::report_settings();
|
||||
}
|
||||
|
||||
/** 站内通知总开关 */
|
||||
public static function message_enabled(): bool {
|
||||
return Integration::message_enabled();
|
||||
}
|
||||
|
||||
/** 通知基础设置(basic group) */
|
||||
public static function notification_settings(): array {
|
||||
return Integration::notification_settings();
|
||||
}
|
||||
|
||||
/** 已关闭的通知推送类型列表 */
|
||||
public static function notification_closed_types(): array {
|
||||
return Integration::notification_closed_types();
|
||||
}
|
||||
|
||||
/** 自动清理已读消息配置 */
|
||||
public static function auto_clear_settings(): array {
|
||||
return Integration::auto_clear_settings();
|
||||
}
|
||||
|
||||
/** 私信功能配置 */
|
||||
public static function private_message_settings(): array {
|
||||
return Integration::private_message_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单项扩展 meta 字段列表
|
||||
*/
|
||||
public static function get_menu_item_meta_fields(): array {
|
||||
return [
|
||||
'icon_class',
|
||||
'icon_svg',
|
||||
'badge_text',
|
||||
'badge_color',
|
||||
'menu_card_image',
|
||||
'menu_card_desc',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Capability definitions registry.
|
||||
*
|
||||
* @return array<string, array{label:string, roles?:string[], exclude_roles?:string[], default?:array<string,mixed>}>
|
||||
*/
|
||||
public static function cap_definitions(): array {
|
||||
return Capabilities::cap_definitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* All role columns in the capability matrix.
|
||||
*/
|
||||
public static function cap_role_columns(): array {
|
||||
return Capabilities::cap_role_columns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the user_caps matrix from settings.
|
||||
*
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
public static function get_user_capabilities(): array {
|
||||
return Capabilities::get_user_capabilities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve whether a user has a specific capability.
|
||||
*/
|
||||
public static function user_can(string $cap, int $user_id = 0, ?int $context = null): bool {
|
||||
return Capabilities::user_can($cap, $user_id, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"网站安全"设置
|
||||
*/
|
||||
public static function get_security_settings(): array {
|
||||
return Capabilities::get_security_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取"系统工具"设置
|
||||
*/
|
||||
public static function get_system_tools_settings(): array {
|
||||
return Capabilities::get_system_tools_settings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class ExtensionRuntime {
|
||||
|
||||
/** 获取审核配置 */
|
||||
public static function get_moderation(): array {
|
||||
return get_option('aksrt_moderation_config', [
|
||||
'enabled' => false,
|
||||
'akismet_enabled' => false,
|
||||
'akismet_site_url' => '',
|
||||
'akismet_blog_lang' => 'zh-CN',
|
||||
'akismet_api_key' => '',
|
||||
'ai_enabled' => false,
|
||||
'ai_provider' => 'baidu',
|
||||
'baidu_api_key' => '',
|
||||
'baidu_secret_key' => '',
|
||||
'baidu_token_url' => 'https://aip.baidubce.com/oauth/2.0/token',
|
||||
'baidu_censor_url' => 'https://aip.baidubce.com/rest/2.0/solution/v1/text_censor/v2/user_defined',
|
||||
'baidu_img_censor_url' => 'https://aip.baidubce.com/rest/2.0/solution/v1/img_censor/v2/user_defined',
|
||||
'ai_moderate_comments' => true,
|
||||
'ai_moderate_background' => true,
|
||||
'auto_approve_low_risk' => true,
|
||||
'auto_reject_high_risk' => true,
|
||||
'low_risk_max_score' => 35,
|
||||
'high_risk_min_score' => 80,
|
||||
'blocked_keywords' => '',
|
||||
'rate_limit_enabled' => false,
|
||||
'rate_limit_min_interval' => 8,
|
||||
'rate_limit_max_per_hour' => 15,
|
||||
'geoip_enabled' => false,
|
||||
'geoip_provider' => 'ipapi',
|
||||
'geoip_api_key' => '',
|
||||
'geoip_block_countries' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 IP 归属地设置
|
||||
*/
|
||||
public static function get_ip_geo_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$provider = sanitize_key((string) ($settings['ip_addr_sdk'] ?? 'null'));
|
||||
$allowed = ['polling', 'qq', 'amap', 'null'];
|
||||
if (!in_array($provider, $allowed, true)) {
|
||||
$provider = 'null';
|
||||
}
|
||||
|
||||
$allowed_display = ['comment', 'user_home', 'user_center', 'post'];
|
||||
// Only fill defaults when the key was never saved — empty array means "none".
|
||||
if (!array_key_exists('ip_geo_display', $settings)) {
|
||||
$display_norm = $allowed_display;
|
||||
} else {
|
||||
$display_raw = $settings['ip_geo_display'];
|
||||
$display = is_array($display_raw) ? $display_raw : [];
|
||||
$display_norm = [];
|
||||
foreach ($display as $item) {
|
||||
$key = sanitize_key((string) $item);
|
||||
if (in_array($key, $allowed_display, true) && !in_array($key, $display_norm, true)) {
|
||||
$display_norm[] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$format = sanitize_key((string) ($settings['ip_geo_format'] ?? 'province_city'));
|
||||
if (!in_array($format, ['province_city', 'province', 'country_province'], true)) {
|
||||
$format = 'province_city';
|
||||
}
|
||||
|
||||
return [
|
||||
'ip_geo_enabled' => !empty($settings['ip_geo_enabled']),
|
||||
'ip_addr_sdk' => $provider,
|
||||
'ip_geo_cache_ttl' => max(3600, (int) ($settings['ip_geo_cache_ttl'] ?? 86400)),
|
||||
'ip_geo_display' => $display_norm,
|
||||
'ip_geo_format' => $format,
|
||||
'ip_geo_fallback_text' => (string) ($settings['ip_geo_fallback_text'] ?? ''),
|
||||
'ip_addr_sdk_qq_appkey' => (string) ($settings['ip_addr_sdk_qq_appkey'] ?? ''),
|
||||
'ip_addr_sdk_qq_secretkey' => (string) ($settings['ip_addr_sdk_qq_secretkey'] ?? ''),
|
||||
'ip_addr_sdk_amap_appkey' => (string) ($settings['ip_addr_sdk_amap_appkey'] ?? ''),
|
||||
'ip_addr_sdk_amap_secretkey' => (string) ($settings['ip_addr_sdk_amap_secretkey'] ?? ''),
|
||||
'ip_geo_verified' => !empty($settings['ip_geo_verified']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容审核设置
|
||||
*/
|
||||
public static function get_content_audit_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$provider = sanitize_key((string) ($settings['content_audit_provider'] ?? 'baidu'));
|
||||
$allowed = ['baidu', 'null'];
|
||||
if (!in_array($provider, $allowed, true)) {
|
||||
$provider = 'baidu';
|
||||
}
|
||||
|
||||
$on_failure = sanitize_key((string) ($settings['content_audit_on_failure'] ?? 'allow'));
|
||||
if (!in_array($on_failure, ['allow', 'block'], true)) {
|
||||
$on_failure = 'allow';
|
||||
}
|
||||
|
||||
return [
|
||||
'content_audit_enabled' => !empty($settings['content_audit_enabled']),
|
||||
'content_audit_provider' => $provider,
|
||||
'content_audit_api_key' => (string) ($settings['content_audit_api_key'] ?? ''),
|
||||
'content_audit_api_secret' => (string) ($settings['content_audit_api_secret'] ?? ''),
|
||||
'content_audit_text_enabled' => !isset($settings['content_audit_text_enabled']) || !empty($settings['content_audit_text_enabled']),
|
||||
'content_audit_image_enabled' => !empty($settings['content_audit_image_enabled']),
|
||||
'content_audit_on_failure' => $on_failure,
|
||||
'content_audit_log_enabled' => !isset($settings['content_audit_log_enabled']) || !empty($settings['content_audit_log_enabled']),
|
||||
'content_audit_baidu_token_url' => (string) ($settings['content_audit_baidu_token_url'] ?? ''),
|
||||
'content_audit_baidu_text_url' => (string) ($settings['content_audit_baidu_text_url'] ?? ''),
|
||||
'content_audit_baidu_img_url' => (string) ($settings['content_audit_baidu_img_url'] ?? ''),
|
||||
'content_audit_verified' => !empty($settings['content_audit_verified']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取搜索引擎推送设置
|
||||
*/
|
||||
public static function get_search_push_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$enabled = !empty($settings['baidu_push_enabled']) || !empty($settings['seo_baidu_push']);
|
||||
$token = (string) ($settings['baidu_push_token'] ?? '');
|
||||
if ($token === '' && !empty($settings['seo_baidu_token'])) {
|
||||
$token = (string) $settings['seo_baidu_token'];
|
||||
}
|
||||
|
||||
return [
|
||||
'baidu_push_enabled' => $enabled,
|
||||
'baidu_push_token' => $token,
|
||||
'baidu_push_auto' => !isset($settings['baidu_push_auto']) || !empty($settings['baidu_push_auto']),
|
||||
'baidu_push_on_publish' => !isset($settings['baidu_push_on_publish']) || !empty($settings['baidu_push_on_publish']),
|
||||
'baidu_push_on_update' => !empty($settings['baidu_push_on_update']),
|
||||
'baidu_push_batch_size' => max(1, min(500, (int) ($settings['baidu_push_batch_size'] ?? 50))),
|
||||
'baidu_push_log_enabled' => !isset($settings['baidu_push_log_enabled']) || !empty($settings['baidu_push_log_enabled']),
|
||||
'baidu_push_verified' => !empty($settings['baidu_push_verified']),
|
||||
'xzh_on' => !empty($settings['xzh_on']),
|
||||
'xzh_appid' => (string) ($settings['xzh_appid'] ?? ''),
|
||||
'xzh_render_tail' => !isset($settings['xzh_render_tail']) || !empty($settings['xzh_render_tail']),
|
||||
'xzh_jsonld_single' => !isset($settings['xzh_jsonld_single']) || !empty($settings['xzh_jsonld_single']),
|
||||
'xzh_jsonld_page' => !empty($settings['xzh_jsonld_page']),
|
||||
'xzh_jsonld_img' => !empty($settings['xzh_jsonld_img']),
|
||||
'seo_baidu_normal' => !empty($settings['seo_baidu_normal']),
|
||||
'seo_baidu_fast' => !empty($settings['seo_baidu_fast']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取短信接口设置
|
||||
*
|
||||
* 注意:所有供应商共用 sms_access_key / sms_access_secret(通用凭证字段)。
|
||||
* 各供应商特有的额外字段使用各自的命名空间(sms_tencent_*, sms_huawei_*, sms_custom_*)。
|
||||
* sms_sign_name / sms_template_code 为所有供应商共用。
|
||||
*/
|
||||
public static function get_sms_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$provider = sanitize_key((string) ($settings['sms_provider'] ?? 'aliyun'));
|
||||
$allowed_providers = ['aliyun', 'tencent', 'huawei', 'custom'];
|
||||
if (!in_array($provider, $allowed_providers, true)) {
|
||||
$provider = 'aliyun';
|
||||
}
|
||||
|
||||
$ali_api_type = sanitize_key((string) ($settings['sms_ali_api_type'] ?? 'sms'));
|
||||
if (!in_array($ali_api_type, ['sms', 'verify'], true)) {
|
||||
$ali_api_type = 'sms';
|
||||
}
|
||||
|
||||
$code_length = max(4, min(8, (int) ($settings['sms_code_length'] ?? 6)));
|
||||
$code_expire = max(60, min(600, (int) ($settings['sms_code_expire'] ?? 300)));
|
||||
$rate_limit = max(10, (int) ($settings['sms_rate_limit'] ?? 60));
|
||||
$daily_limit = max(1, (int) ($settings['sms_daily_limit'] ?? 10));
|
||||
|
||||
return [
|
||||
'sms_enabled' => !empty($settings['sms_enabled']),
|
||||
'sms_provider' => $provider,
|
||||
'sms_number_limit_ch' => !isset($settings['sms_number_limit_ch']) || !empty($settings['sms_number_limit_ch']),
|
||||
'sms_access_key' => (string) ($settings['sms_access_key'] ?? ''),
|
||||
'sms_access_secret' => (string) ($settings['sms_access_secret'] ?? ''),
|
||||
'sms_sign_name' => (string) ($settings['sms_sign_name'] ?? ''),
|
||||
'sms_template_code' => (string) ($settings['sms_template_code'] ?? ''),
|
||||
'sms_code_length' => $code_length,
|
||||
'sms_code_expire' => $code_expire,
|
||||
'sms_rate_limit' => $rate_limit,
|
||||
'sms_daily_limit' => $daily_limit,
|
||||
'sms_notify_bind' => !isset($settings['sms_notify_bind']) || !empty($settings['sms_notify_bind']),
|
||||
'sms_notify_login' => !empty($settings['sms_notify_login']),
|
||||
'sms_notify_register' => !isset($settings['sms_notify_register']) || !empty($settings['sms_notify_register']),
|
||||
'sms_notify_reset_password' => !isset($settings['sms_notify_reset_password']) || !empty($settings['sms_notify_reset_password']),
|
||||
// 阿里云特有
|
||||
'sms_ali_api_type' => $ali_api_type,
|
||||
'sms_region_id' => (string) ($settings['sms_region_id'] ?? 'cn-hangzhou'),
|
||||
'sms_aliyun_verified' => !empty($settings['sms_aliyun_verified']),
|
||||
// 腾讯云特有
|
||||
'sms_tencent_app_id' => (string) ($settings['sms_tencent_app_id'] ?? ''),
|
||||
'sms_tencent_app_key' => (string) ($settings['sms_tencent_app_key'] ?? ''),
|
||||
'sms_tencent_secret_id' => (string) ($settings['sms_tencent_secret_id'] ?? ''),
|
||||
'sms_tencent_secret_key' => (string) ($settings['sms_tencent_secret_key'] ?? ''),
|
||||
'sms_tencent_region' => (string) ($settings['sms_tencent_region'] ?? 'ap-guangzhou'),
|
||||
'sms_tencent_verified' => !empty($settings['sms_tencent_verified']),
|
||||
// 华为云特有
|
||||
'sms_huawei_sender' => (string) ($settings['sms_huawei_sender'] ?? ''),
|
||||
'sms_huawei_signature' => (string) ($settings['sms_huawei_signature'] ?? ''),
|
||||
'sms_huawei_endpoint' => (string) ($settings['sms_huawei_endpoint'] ?? ''),
|
||||
'sms_huawei_verified' => !empty($settings['sms_huawei_verified']),
|
||||
// 自定义接口特有
|
||||
'sms_custom_url' => (string) ($settings['sms_custom_url'] ?? ''),
|
||||
'sms_custom_method' => (string) ($settings['sms_custom_method'] ?? 'POST'),
|
||||
'sms_custom_auth_type' => (string) ($settings['sms_custom_auth_type'] ?? 'header'),
|
||||
'sms_custom_auth_key' => (string) ($settings['sms_custom_auth_key'] ?? ''),
|
||||
'sms_custom_auth_value' => (string) ($settings['sms_custom_auth_value'] ?? ''),
|
||||
'sms_custom_headers' => (string) ($settings['sms_custom_headers'] ?? ''),
|
||||
'sms_custom_body' => (string) ($settings['sms_custom_body'] ?? ''),
|
||||
'sms_custom_success_rule' => (string) ($settings['sms_custom_success_rule'] ?? ''),
|
||||
'sms_custom_verified' => !empty($settings['sms_custom_verified']),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,576 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait FacadeBulk {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Header navigation display settings.
|
||||
*
|
||||
* @return array{
|
||||
* fixed:bool,search_enabled:bool,user_menu:bool,publish_btn:bool,mobile_drawer:bool,
|
||||
* nav_style:string,max_width:int,scroll_down_hide:bool,layout:string,mobile_layout:string,
|
||||
* mobile_align:string,nav_pay_vip:bool,nav_user_pay_vip:bool
|
||||
* }
|
||||
*/
|
||||
public static function get_header_nav_settings(): array {
|
||||
$settings = self::get_all();
|
||||
$nav_style = sanitize_key((string) ($settings['header_nav_style'] ?? 'default'));
|
||||
$max_width = (int) ($settings['header_max_width'] ?? 1200);
|
||||
$layout = sanitize_key((string) ($settings['header_layout'] ?? '1'));
|
||||
$ml = sanitize_key((string) ($settings['mobile_header_layout'] ?? 'center'));
|
||||
$ma = sanitize_key((string) ($settings['mobile_navbar_align'] ?? 'left'));
|
||||
|
||||
if (!in_array($nav_style, ['default', 'transparent', 'blur'], true)) {
|
||||
$nav_style = 'default';
|
||||
}
|
||||
|
||||
if (!in_array($max_width, [0, 1080, 1200, 1320], true)) {
|
||||
$max_width = 1200;
|
||||
}
|
||||
|
||||
return [
|
||||
'fixed' => !isset($settings['header_fixed']) || !empty($settings['header_fixed']),
|
||||
'search_enabled' => !isset($settings['header_search_enabled']) || !empty($settings['header_search_enabled']),
|
||||
'user_menu' => !isset($settings['header_user_menu']) || !empty($settings['header_user_menu']),
|
||||
// Unified with header_newposts_enabled (zibll nav_newposts).
|
||||
'publish_btn' => !isset($settings['header_newposts_enabled']) || !empty($settings['header_newposts_enabled']),
|
||||
'mobile_drawer' => !isset($settings['header_mobile_drawer']) || !empty($settings['header_mobile_drawer']),
|
||||
'nav_style' => $nav_style,
|
||||
'max_width' => $max_width,
|
||||
// Zibll default: true when fixed.
|
||||
'scroll_down_hide' => !isset($settings['header_scroll_down_hide']) || !empty($settings['header_scroll_down_hide']),
|
||||
'layout' => in_array($layout, ['1', '2', '3'], true) ? $layout : '1',
|
||||
'mobile_layout' => in_array($ml, ['center', 'left'], true) ? $ml : 'center',
|
||||
'mobile_align' => in_array($ma, ['top', 'left', 'right'], true) ? $ma : 'left',
|
||||
'nav_pay_vip' => !isset($settings['header_nav_pay_vip']) || !empty($settings['header_nav_pay_vip']),
|
||||
'nav_user_pay_vip' => !isset($settings['header_nav_user_pay_vip']) || !empty($settings['header_nav_user_pay_vip']),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Header publish button configuration.
|
||||
*
|
||||
* @return array{enabled:bool,text:string,radius:int,class:string,types:string[]}
|
||||
*/
|
||||
public static function get_header_newposts_config(): array {
|
||||
$s = self::get_all();
|
||||
|
||||
$types = [];
|
||||
if (!empty($s['header_newposts_types']) && is_array($s['header_newposts_types'])) {
|
||||
$types = array_values(array_filter(array_map('sanitize_key', $s['header_newposts_types'])));
|
||||
}
|
||||
|
||||
// zibll nav_newposts_radius is bool pill; map true→20px, false→0. Legacy int still accepted once.
|
||||
$raw_radius = $s['header_newposts_radius'] ?? true;
|
||||
if (is_bool($raw_radius) || $raw_radius === '0' || $raw_radius === '1' || $raw_radius === 0 || $raw_radius === 1) {
|
||||
$radius_px = !empty($raw_radius) ? 20 : 0;
|
||||
$radius_pill = !empty($raw_radius);
|
||||
} else {
|
||||
$radius_px = max(0, min(30, (int) $raw_radius));
|
||||
$radius_pill = $radius_px >= 16;
|
||||
}
|
||||
|
||||
return [
|
||||
// Default on like zibll nav_newposts when key unset.
|
||||
'enabled' => !isset($s['header_newposts_enabled']) || !empty($s['header_newposts_enabled']),
|
||||
'text' => trim((string) ($s['header_newposts_text'] ?? '<i class="fa fa-pencil"></i> 发布')),
|
||||
'radius' => $radius_px,
|
||||
'radius_pill' => $radius_pill,
|
||||
'class' => sanitize_html_class((string) (($s['header_newposts_class'] ?? '') !== '' ? $s['header_newposts_class'] : 'jb-blue')),
|
||||
'types' => $types,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Header theme color configuration.
|
||||
*
|
||||
* @return array{custom:bool,bg_custom:string,bg:string,color_custom:string}
|
||||
*/
|
||||
public static function get_header_theme_config(): array {
|
||||
$s = self::get_all();
|
||||
|
||||
return [
|
||||
'custom' => !empty($s['header_theme_custom']),
|
||||
'bg_custom' => sanitize_hex_color((string) ($s['header_theme_bg_custom'] ?? '')) ?: '',
|
||||
'bg' => sanitize_hex_color((string) ($s['header_theme_bg'] ?? '')) ?: '',
|
||||
'color_custom' => sanitize_hex_color((string) ($s['header_theme_color_custom'] ?? '')) ?: '',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Category archive display settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_category_page_settings(): array {
|
||||
$settings = self::get_all();
|
||||
$header_style = sanitize_key((string) ($settings['category_header_style'] ?? 'cover'));
|
||||
$list_mode = sanitize_key((string) ($settings['category_list_mode'] ?? 'grid'));
|
||||
$per_page = (int) ($settings['category_per_page'] ?? 12);
|
||||
$orderby = sanitize_key((string) ($settings['category_orderby'] ?? 'modified'));
|
||||
|
||||
if (!in_array($header_style, ['cover', 'simple', 'none'], true)) {
|
||||
$header_style = 'cover';
|
||||
}
|
||||
|
||||
if (!in_array($list_mode, ['grid', 'list', 'compact'], true)) {
|
||||
$list_mode = 'grid';
|
||||
}
|
||||
|
||||
if (!in_array($orderby, ['modified', 'date', 'views', 'comments', 'likes'], true)) {
|
||||
$orderby = 'modified';
|
||||
}
|
||||
|
||||
return [
|
||||
'header_style' => $header_style,
|
||||
'cover_enabled' => !isset($settings['category_cover_enabled']) || !empty($settings['category_cover_enabled']),
|
||||
'desc_enabled' => !isset($settings['category_desc_enabled']) || !empty($settings['category_desc_enabled']),
|
||||
'default_cover' => esc_url_raw((string) ($settings['category_default_cover'] ?? '')),
|
||||
'list_mode' => $list_mode,
|
||||
'filter_bar' => !isset($settings['category_filter_bar']) || !empty($settings['category_filter_bar']),
|
||||
'sidebar' => !isset($settings['category_sidebar']) || !empty($settings['category_sidebar']),
|
||||
'per_page' => max(4, min(48, $per_page)),
|
||||
'post_count' => !empty($settings['category_post_count']),
|
||||
'orderby' => $orderby,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tag archive display settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_tag_page_settings(): array {
|
||||
$settings = self::get_all();
|
||||
$header_style = sanitize_key((string) ($settings['tag_header_style'] ?? 'simple'));
|
||||
$list_mode = sanitize_key((string) ($settings['tag_list_mode'] ?? 'grid'));
|
||||
$per_page = (int) ($settings['tag_per_page'] ?? 12);
|
||||
$orderby = sanitize_key((string) ($settings['tag_orderby'] ?? 'count'));
|
||||
|
||||
if (!in_array($header_style, ['cover', 'simple', 'none'], true)) {
|
||||
$header_style = 'simple';
|
||||
}
|
||||
|
||||
if (!in_array($list_mode, ['grid', 'list'], true)) {
|
||||
$list_mode = 'grid';
|
||||
}
|
||||
|
||||
if (!in_array($orderby, ['count', 'name', 'modified'], true)) {
|
||||
$orderby = 'count';
|
||||
}
|
||||
|
||||
return [
|
||||
'header_style' => $header_style,
|
||||
'default_cover' => esc_url_raw((string) ($settings['tag_default_cover'] ?? '')),
|
||||
'list_mode' => $list_mode,
|
||||
'sidebar' => !isset($settings['tag_sidebar']) || !empty($settings['tag_sidebar']),
|
||||
'per_page' => max(4, min(48, $per_page)),
|
||||
'post_count' => !empty($settings['tag_post_count']),
|
||||
'orderby' => $orderby,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Misc page display settings (404, search, author).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_other_page_settings(): array {
|
||||
$settings = self::get_all();
|
||||
$message = trim((string) ($settings['page_404_message'] ?? ''));
|
||||
$search_per_page = max(4, min(48, (int) ($settings['page_search_per_page'] ?? 12)));
|
||||
$author_per_page = max(4, min(48, (int) ($settings['page_author_posts_per_page'] ?? 12)));
|
||||
|
||||
$header_style = sanitize_key((string) ($settings['page_header_style'] ?? '1'));
|
||||
if (!in_array($header_style, ['', '1', '2', '3'], true)) {
|
||||
$header_style = '1';
|
||||
}
|
||||
|
||||
return [
|
||||
'header_style' => $header_style,
|
||||
'header_cover_img' => esc_url_raw((string) ($settings['page_header_cover_img'] ?? '')),
|
||||
'page_404_message' => $message !== '' ? $message : __('页面未找到', 'aksrt'),
|
||||
'page_404_search' => !isset($settings['page_404_search']) || !empty($settings['page_404_search']),
|
||||
'page_404_popular' => !isset($settings['page_404_popular']) || !empty($settings['page_404_popular']),
|
||||
'page_404_back' => !isset($settings['page_404_back']) || !empty($settings['page_404_back']),
|
||||
'page_search_sidebar' => !isset($settings['page_search_sidebar']) || !empty($settings['page_search_sidebar']),
|
||||
'page_search_per_page' => $search_per_page,
|
||||
'page_author_cover' => !isset($settings['page_author_cover']) || !empty($settings['page_author_cover']),
|
||||
'page_author_sidebar' => !isset($settings['page_author_sidebar']) || !empty($settings['page_author_sidebar']),
|
||||
'page_author_posts_per_page' => $author_per_page,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Special/topic page display settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_special_page_settings(): array {
|
||||
$s = self::get_all();
|
||||
$layout = sanitize_key((string) ($s['special_layout'] ?? 'grid'));
|
||||
$source_type = sanitize_key((string) ($s['special_source_type'] ?? 'category'));
|
||||
$subpage_display = sanitize_key((string) ($s['special_subpage_display'] ?? 'cards'));
|
||||
$pagination = sanitize_key((string) ($s['special_pagination'] ?? 'numeric'));
|
||||
$orderby = sanitize_key((string) ($s['special_orderby'] ?? 'date'));
|
||||
|
||||
if (!in_array($layout, ['grid', 'list', 'masonry'], true)) {
|
||||
$layout = 'grid';
|
||||
}
|
||||
if (!in_array($source_type, ['category', 'tag', 'custom'], true)) {
|
||||
$source_type = 'category';
|
||||
}
|
||||
if (!in_array($subpage_display, ['cards', 'list', 'grid'], true)) {
|
||||
$subpage_display = 'cards';
|
||||
}
|
||||
if (!in_array($pagination, ['numeric', 'load_more', 'infinite'], true)) {
|
||||
$pagination = 'numeric';
|
||||
}
|
||||
if (!in_array($orderby, ['date', 'modified', 'views', 'comments'], true)) {
|
||||
$orderby = 'date';
|
||||
}
|
||||
|
||||
return [
|
||||
'cover_enabled' => !empty($s['special_cover_enabled']),
|
||||
'summary_enabled' => !empty($s['special_summary_enabled']),
|
||||
'summary_length' => max(50, min(500, (int) ($s['special_summary_length'] ?? 200))),
|
||||
'default_cover' => esc_url_raw((string) ($s['special_default_cover'] ?? '')),
|
||||
'layout' => $layout,
|
||||
'columns' => max(1, min(4, (int) ($s['special_columns'] ?? 2))),
|
||||
'source_type' => $source_type,
|
||||
'source_ids' => trim((string) ($s['special_source_ids'] ?? '')),
|
||||
'subpage_display' => $subpage_display,
|
||||
'subpage_count' => max(1, min(20, (int) ($s['special_subpage_count'] ?? 6))),
|
||||
'sidebar' => !empty($s['special_sidebar']),
|
||||
'pagination' => $pagination,
|
||||
'per_page' => max(4, min(48, (int) ($s['special_per_page'] ?? 12))),
|
||||
'post_count' => !empty($s['special_post_count']),
|
||||
'orderby' => $orderby,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Share and poster settings.
|
||||
*
|
||||
* @return array{wechat_enabled:bool,wechat_appid:string,wechat_app_secret:string,only_logo:bool,compatible_s:bool,poster_img:string,poster_logo:string,share_img:string,share_desc:string}
|
||||
*/
|
||||
public static function get_share_settings(): array {
|
||||
$settings = self::get_all();
|
||||
|
||||
return [
|
||||
'wechat_enabled' => !empty($settings['share_wechat_s']),
|
||||
'wechat_appid' => sanitize_text_field((string) ($settings['share_wechat_appid'] ?? '')),
|
||||
'wechat_app_secret' => sanitize_text_field((string) ($settings['share_wechat_app_secret'] ?? '')),
|
||||
'only_logo' => !empty($settings['share_only_logo']),
|
||||
'compatible_s' => !empty($settings['share_img_compatible_s']),
|
||||
'poster_img' => esc_url_raw((string) ($settings['share_img_byimg'] ?? '')),
|
||||
'poster_logo' => esc_url_raw((string) ($settings['share_logo'] ?? '')),
|
||||
'share_img' => esc_url_raw((string) ($settings['share_img'] ?? '')),
|
||||
'share_desc' => sanitize_textarea_field((string) ($settings['share_desc'] ?? '')) ?: __('扫一扫 立即查看', 'aksrt'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Single post/page display settings.
|
||||
*
|
||||
* @return array{toc_enabled:bool,toc_depth:int,reading_progress:bool,lightbox:bool,related_enabled:bool,related_count:int,like_enabled:bool,favorite_enabled:bool,share_enabled:bool,copyright_enabled:bool,print_enabled:bool,pdf_export_enabled:bool,word_count_enabled:bool,reading_time_enabled:bool}
|
||||
*/
|
||||
public static function get_post_page_settings(): array {
|
||||
// Canonical assembly lives in the post-display helper (related style/source split, aliases).
|
||||
if (class_exists('AKSRT\\Settings\\PostDisplay')) {
|
||||
return PostDisplay::get_post_page_settings();
|
||||
}
|
||||
|
||||
$settings = self::get_all();
|
||||
return [
|
||||
'toc_enabled' => !isset($settings['post_toc_enabled']) || !empty($settings['post_toc_enabled']),
|
||||
'toc_depth' => max(1, min(6, (int) ($settings['post_toc_depth'] ?? 3))),
|
||||
'reading_progress' => !isset($settings['post_reading_progress']) || !empty($settings['post_reading_progress']),
|
||||
'breadcrumbs' => !isset($settings['breadcrumbs_single_s']) || !empty($settings['breadcrumbs_single_s']),
|
||||
'breadcrumbs_home' => trim((string) ($settings['breadcrumbs_home_text'] ?? '')) ?: __('首页', 'aksrt'),
|
||||
'related_enabled' => !isset($settings['post_related_enabled']) || !empty($settings['post_related_enabled']),
|
||||
'related_count' => max(1, min(20, (int) ($settings['post_related_count'] ?? 6))),
|
||||
'related_style' => 'img',
|
||||
'related_source' => 'category',
|
||||
'related_type' => 'category',
|
||||
'related_orderby' => 'views',
|
||||
'related_title' => sanitize_text_field((string) ($settings['post_related_title'] ?? '相关推荐')),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取懒加载配置
|
||||
*
|
||||
* 返回 schema 定义的全部字段:全局开关、动画、占位图、模糊预览、
|
||||
* 以及 8 项粒度范围开关。
|
||||
*
|
||||
* @return array {enabled, animation, placeholder_url, blur, avatar, content, comment, private, slider, cover, other, widget}
|
||||
*/
|
||||
public static function get_lazyload_config(): array {
|
||||
$s = self::get_all();
|
||||
|
||||
// placeholder 兼容:schema 存 lazyload_placeholder,REST/Vue 存 lazyload_placeholder_url
|
||||
$placeholder = '';
|
||||
if (!empty($s['lazyload_placeholder'])) {
|
||||
$placeholder = $s['lazyload_placeholder'];
|
||||
} elseif (!empty($s['lazyload_placeholder_url'])) {
|
||||
$placeholder = $s['lazyload_placeholder_url'];
|
||||
}
|
||||
|
||||
return [
|
||||
'enabled' => !isset($s['lazyload_enabled']) || !empty($s['lazyload_enabled']),
|
||||
'animation' => $s['lazyload_animation'] ?? 'blur',
|
||||
'placeholder_url' => (string) $placeholder,
|
||||
'blur' => !isset($s['lazyload_blur']) || !empty($s['lazyload_blur']),
|
||||
'avatar' => !isset($s['lazyload_avatar']) || !empty($s['lazyload_avatar']),
|
||||
'content' => !empty($s['lazyload_content']),
|
||||
'comment' => !isset($s['lazyload_comment']) || !empty($s['lazyload_comment']),
|
||||
'private' => !isset($s['lazyload_private']) || !empty($s['lazyload_private']),
|
||||
'slider' => !isset($s['lazyload_slider']) || !empty($s['lazyload_slider']),
|
||||
'cover' => !isset($s['lazyload_cover']) || !empty($s['lazyload_cover']),
|
||||
'other' => !isset($s['lazyload_other']) || !empty($s['lazyload_other']),
|
||||
'widget' => !isset($s['lazyload_widget']) || !empty($s['lazyload_widget']),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取备案配置(统一 page-display footer schema 和全局设置)
|
||||
* @return array {icp_enabled, icp_number, police_enabled, police_number}
|
||||
*/
|
||||
public static function get_filing_settings(): array {
|
||||
$s = self::get_all();
|
||||
$icp_enabled = !isset($s['footer_icp']) || !empty($s['footer_icp']);
|
||||
$police_enabled = !isset($s['footer_police']) || !empty($s['footer_police']);
|
||||
// 优先读 footer schema 的 icp_number,回退到全局 icp_filing
|
||||
$icp_number = trim((string) ($s['icp_number'] ?? $s['icp_filing'] ?? ''));
|
||||
$police_number = trim((string) ($s['police_number'] ?? ''));
|
||||
return [
|
||||
'icp_enabled' => $icp_enabled,
|
||||
'icp_number' => $icp_number,
|
||||
'police_enabled' => $police_enabled,
|
||||
'police_number' => $police_number,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取页脚附加文字 */
|
||||
public static function footer_text(): string {
|
||||
return trim((string) self::get_value('footer_text', ''));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取 ICP 备案号 */
|
||||
public static function icp_filing(): string {
|
||||
return trim((string) self::get_value('icp_filing', ''));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取公安备案号 */
|
||||
public static function police_filing(): string {
|
||||
return trim((string) self::get_value('police_number', ''));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取导航 Logo 宽度 */
|
||||
public static function logo_width(): int {
|
||||
$width = (int) self::get_value('logo_width', 150);
|
||||
return max(50, min(400, $width));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取Favicon URL */
|
||||
public static function custom_favicon_url(): string {
|
||||
$favicon = (string) self::get_value('site_favicon', '');
|
||||
return $favicon !== '' ? $favicon : '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static function favicon_url(): string {
|
||||
$custom = self::custom_favicon_url();
|
||||
if ($custom !== '') {
|
||||
return $custom;
|
||||
}
|
||||
|
||||
$site_icon = get_site_icon_url(512);
|
||||
return $site_icon ? (string) $site_icon : self::default_asset_url('default-favicon.svg');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取About显示名 */
|
||||
/**
|
||||
* 让 SEO 设置中的 Favicon 覆盖 WordPress 原生 site_icon 输出链路。
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $size
|
||||
* @param int $blog_id
|
||||
* @return string
|
||||
*/
|
||||
public static function filter_site_icon_url($url, $size, $blog_id): string {
|
||||
$custom = self::custom_favicon_url();
|
||||
return $custom !== '' ? $custom : (string) $url;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 尝试把自定义 favicon 同步到 WordPress 原生 site_icon 选项。
|
||||
*
|
||||
* 仅当 URL 能映射到媒体库附件时才同步;外链仍通过 get_site_icon_url 过滤覆盖。
|
||||
*/
|
||||
public static function sync_native_site_icon(string $favicon_url): void {
|
||||
$favicon_url = trim(esc_url_raw($favicon_url));
|
||||
|
||||
if ($favicon_url === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$attachment_id = attachment_url_to_postid($favicon_url);
|
||||
if ($attachment_id > 0 && (int) get_option('site_icon', 0) !== $attachment_id) {
|
||||
update_option('site_icon', $attachment_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 启动时对齐原生 site_icon,同步自定义 site_favicon 到原生 site_icon。 */
|
||||
public static function maybe_sync_native_site_icon(): void {
|
||||
$custom = self::custom_favicon_url();
|
||||
if ($custom === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
self::sync_native_site_icon($custom);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static function about_display_name(): string {
|
||||
$s = self::get_all();
|
||||
return !empty($s['about_display_name']) ? $s['about_display_name'] : get_bloginfo('name');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取About简介 */
|
||||
public static function about_bio(): string {
|
||||
$s = self::get_all();
|
||||
return !empty($s['about_bio']) ? $s['about_bio'] : get_bloginfo('description');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取About头像URL */
|
||||
public static function about_avatar(): string {
|
||||
$s = self::get_all();
|
||||
return $s['about_avatar'] ?? ($s['admin_avatar_url'] ?? '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取SEO关键词 */
|
||||
public static function seo_keywords(): string {
|
||||
$s = self::get_all();
|
||||
return $s['seo_keywords'] ?? '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取自定义头部代码 */
|
||||
public static function custom_head_code(): string {
|
||||
$code = (string) self::get_value('head_code', '');
|
||||
if ($code === '') {
|
||||
$code = (string) self::get_value('custom_js_header', '');
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取自定义 CSS */
|
||||
public static function custom_css(): string {
|
||||
return (string) self::get_value('custom_css', '');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取自定义底部代码 */
|
||||
public static function custom_footer_code(): string {
|
||||
$code = (string) self::get_value('foot_code', '');
|
||||
if ($code === '') {
|
||||
$code = (string) self::get_value('custom_js_footer', '');
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取统计代码 */
|
||||
public static function trackcode(): string {
|
||||
return trim((string) self::get_value('trackcode', ''));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取SMTP配置 */
|
||||
public static function get_smtp(): array {
|
||||
return get_option('aksrt_mail_smtp', [
|
||||
'enabled' => false,
|
||||
'host' => '',
|
||||
'port' => 465,
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'encryption' => 'ssl',
|
||||
'from_name' => '',
|
||||
'from_address' => '',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 获取邮件品牌设置(发件人昵称/标题前缀/底部内容) */
|
||||
public static function get_mail_branding(): array {
|
||||
$s = self::get_all();
|
||||
return [
|
||||
'showname' => trim((string) ($s['mail_showname'] ?? '')),
|
||||
'title_prefix' => trim((string) ($s['mail_title_prefix'] ?? '')),
|
||||
'description' => trim((string) ($s['mail_description'] ?? '')),
|
||||
'more_content' => trim((string) ($s['mail_more_content'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class HomeCms {
|
||||
|
||||
public static function get_footer_settings(): array {
|
||||
$defaults = [
|
||||
'contacts' => [],
|
||||
'quick_links' => [],
|
||||
'more_links' => [],
|
||||
'hot_categories' => 5,
|
||||
'copyright_text' => '',
|
||||
'layout_template' => 'template_1',
|
||||
];
|
||||
$footer = get_option('aksrt_footer_settings', []);
|
||||
$merged = array_merge($defaults, is_array($footer) ? $footer : []);
|
||||
|
||||
$s = Settings::get_all();
|
||||
$bridge_keys = [
|
||||
'footer_columns', 'footer_copyright', 'footer_icp', 'icp_number',
|
||||
'footer_police', 'police_number',
|
||||
'footer_theme_custom', 'footer_theme_bg_custom', 'footer_theme_bg', 'footer_theme_color_custom',
|
||||
'footer_contact_wechat_img', 'footer_contact_qq', 'footer_contact_weibo', 'footer_contact_email',
|
||||
];
|
||||
foreach ($bridge_keys as $key) {
|
||||
if (isset($s[$key])) {
|
||||
$merged[$key] = $s[$key];
|
||||
}
|
||||
}
|
||||
return $merged;
|
||||
}
|
||||
|
||||
public static function get_footer_contacts(): array {
|
||||
$footer = self::get_footer_settings();
|
||||
return array_filter($footer['contacts'], fn($c) => !empty($c['enabled']));
|
||||
}
|
||||
|
||||
public static function get_quick_links(): array {
|
||||
$footer = self::get_footer_settings();
|
||||
$links = array_filter($footer['quick_links'], fn($l) => !empty($l['enabled']));
|
||||
usort($links, fn($a, $b) => ($a['sort_order'] ?? 0) <=> ($b['sort_order'] ?? 0));
|
||||
return array_values($links);
|
||||
}
|
||||
|
||||
public static function get_more_links(): array {
|
||||
$footer = self::get_footer_settings();
|
||||
$links = array_filter($footer['more_links'], fn($l) => !empty($l['enabled']));
|
||||
usort($links, fn($a, $b) => ($a['sort_order'] ?? 0) <=> ($b['sort_order'] ?? 0));
|
||||
return array_values($links);
|
||||
}
|
||||
|
||||
public static function get_hot_categories_count(): int {
|
||||
$footer = self::get_footer_settings();
|
||||
return max(1, min(20, (int) ($footer['hot_categories'] ?? 5)));
|
||||
}
|
||||
|
||||
public static function get_copyright_text(): string {
|
||||
$footer = self::get_footer_settings();
|
||||
return $footer['copyright_text'] ?: '';
|
||||
}
|
||||
|
||||
public static function get_footer_brand_settings(): array {
|
||||
$f = self::get_footer_settings();
|
||||
return [
|
||||
'm_s' => is_array($f['footer_t1_m_s'] ?? null) ? $f['footer_t1_m_s'] : ['pc', 'mobile'],
|
||||
'img' => (string) ($f['footer_t1_img'] ?? ''),
|
||||
'img_dark' => (string) ($f['footer_t1_img_dark'] ?? ''),
|
||||
'title' => (string) ($f['footer_t1_t'] ?? ''),
|
||||
'custom_code' => (string) ($f['fcode_t1_code'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_footer_contact_extended_settings(): array {
|
||||
$f = self::get_footer_settings();
|
||||
return [
|
||||
'm_s' => is_array($f['footer_contact_m_s'] ?? null) ? $f['footer_contact_m_s'] : ['pc', 'mobile'],
|
||||
'wechat_img' => (string) ($f['footer_contact_wechat_img'] ?? ''),
|
||||
'qq' => (string) ($f['footer_contact_qq'] ?? ''),
|
||||
'weibo' => (string) ($f['footer_contact_weibo'] ?? ''),
|
||||
'email' => (string) ($f['footer_contact_email'] ?? ''),
|
||||
'more' => is_array($f['footer_contact_more'] ?? null) ? $f['footer_contact_more'] : [],
|
||||
'code_1' => (string) ($f['fcode_t2_code_1'] ?? ''),
|
||||
'code_2' => (string) ($f['fcode_t2_code_2'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_footer_mini_img_settings(): array {
|
||||
$f = self::get_footer_settings();
|
||||
$raw_items = is_array($f['footer_mini_img'] ?? null) ? $f['footer_mini_img'] : [];
|
||||
$items = [];
|
||||
foreach ($raw_items as $item) {
|
||||
if (!is_array($item)) {
|
||||
continue;
|
||||
}
|
||||
$img = (string) ($item['img'] ?? $item['image'] ?? '');
|
||||
if ($img === '') {
|
||||
continue;
|
||||
}
|
||||
$items[] = [
|
||||
'img' => $img,
|
||||
'image' => $img,
|
||||
'text' => (string) ($item['text'] ?? $item['label'] ?? ''),
|
||||
'label' => (string) ($item['label'] ?? $item['text'] ?? ''),
|
||||
];
|
||||
}
|
||||
return [
|
||||
'm_s' => is_array($f['footer_mini_img_m_s'] ?? null) ? $f['footer_mini_img_m_s'] : ['pc', 'mobile'],
|
||||
'items' => $items,
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_footer_customize_code(): string {
|
||||
$f = self::get_footer_settings();
|
||||
return (string) ($f['fcode_customize_code'] ?? '');
|
||||
}
|
||||
|
||||
public static function get_footer_theme_config(): array {
|
||||
$s = Settings::get_all();
|
||||
return [
|
||||
'custom' => !empty($s['footer_theme_custom']),
|
||||
'bg_custom' => sanitize_hex_color((string) ($s['footer_theme_bg_custom'] ?? '')) ?: '',
|
||||
'bg' => sanitize_hex_color((string) ($s['footer_theme_bg'] ?? '')) ?: '',
|
||||
'color_custom' => sanitize_hex_color((string) ($s['footer_theme_color_custom'] ?? '')) ?: '',
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_site_profile(): string {
|
||||
return 'cms';
|
||||
}
|
||||
|
||||
public static function get_cms_features(): array {
|
||||
$defaults = [
|
||||
'resource_cpt_enabled' => true,
|
||||
'download_login' => true,
|
||||
'download_credit' => true,
|
||||
'download_captcha' => false,
|
||||
'search_include_resource' => true,
|
||||
];
|
||||
$s = Settings::get_all();
|
||||
$saved = isset($s['cms_features']) && is_array($s['cms_features']) ? $s['cms_features'] : [];
|
||||
return array_merge($defaults, $saved);
|
||||
}
|
||||
|
||||
public static function cms_feature(string $key, $default = null) {
|
||||
$f = self::get_cms_features();
|
||||
return array_key_exists($key, $f) ? $f[$key] : $default;
|
||||
}
|
||||
|
||||
public static function homepage_allowed_sorts(): array {
|
||||
return ['modified', 'date', 'views', 'likes', 'comments', 'favorites', 'downloads', 'rand'];
|
||||
}
|
||||
|
||||
public static function homepage_sort_labels(): array {
|
||||
return [
|
||||
'modified' => __('更新', 'aksrt'),
|
||||
'date' => __('发布', 'aksrt'),
|
||||
'views' => __('浏览', 'aksrt'),
|
||||
'likes' => __('点赞', 'aksrt'),
|
||||
'comments' => __('评论', 'aksrt'),
|
||||
'favorites' => __('收藏', 'aksrt'),
|
||||
'downloads' => __('下载', 'aksrt'),
|
||||
'rand' => __('随机', 'aksrt'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_homepage_fixed_settings(): array {
|
||||
$s = Settings::get_all();
|
||||
$allowed_sorts = self::homepage_allowed_sorts();
|
||||
|
||||
// Canonical Zibll-aligned primary list contract.
|
||||
$main_list_enabled = !array_key_exists('home_posts_list_s', $s) || !empty($s['home_posts_list_s']);
|
||||
$sort_bar_enabled = !array_key_exists('home_list1_orderby_s', $s) || !empty($s['home_list1_orderby_s']);
|
||||
|
||||
$orderby_option = isset($s['home_list1_orderby_option']) && is_array($s['home_list1_orderby_option'])
|
||||
? $s['home_list1_orderby_option']
|
||||
: [];
|
||||
$default_sort = sanitize_key((string) ($orderby_option['orderby'] ?? 'date'));
|
||||
if (!in_array($default_sort, $allowed_sorts, true)) {
|
||||
$default_sort = 'date';
|
||||
}
|
||||
$sort_options_raw = $orderby_option['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 = sanitize_text_field((string) ($s['index_list_title'] ?? ''));
|
||||
if ($list_title === '') {
|
||||
$list_title = __('最新发布', 'aksrt');
|
||||
}
|
||||
|
||||
$exclude_posts = self::normalize_int_array($s['home_exclude_posts'] ?? []);
|
||||
$exclude_cats = self::normalize_int_array($s['home_exclude_cats'] ?? []);
|
||||
$tabs_raw = isset($s['home_lists']) && is_array($s['home_lists']) ? $s['home_lists'] : [];
|
||||
|
||||
$settings = [
|
||||
// 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),
|
||||
|
||||
// AKSRT presentation extras.
|
||||
'homepage_card_style' => isset($s['homepage_card_style']) ? sanitize_key((string) $s['homepage_card_style']) : 'default',
|
||||
'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']),
|
||||
'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)) {
|
||||
$settings['homepage_card_style'] = 'default';
|
||||
}
|
||||
|
||||
$settings['homepage_multi_thumb_min_images'] = max(2, min(4, $settings['homepage_multi_thumb_min_images']));
|
||||
|
||||
if (!in_array($settings['homepage_default_view'], ['list', 'card'], true)) {
|
||||
$settings['homepage_default_view'] = 'list';
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Homepage always uses ordinary posts. Kept for API stability.
|
||||
*
|
||||
* @return string Always 'post'.
|
||||
*/
|
||||
public static function homepage_content_model(): string {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
public static function homepage_tabs(): array {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['home_lists'];
|
||||
}
|
||||
|
||||
/** @return array<int, array{term_id:int,title:string,orderby:string,enabled:bool}> */
|
||||
public static function home_lists(): array {
|
||||
return self::homepage_tabs();
|
||||
}
|
||||
|
||||
public static function homepage_card_style(): string {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['homepage_card_style'];
|
||||
}
|
||||
|
||||
public static function homepage_multi_thumb_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['homepage_multi_thumb_enabled']);
|
||||
}
|
||||
|
||||
public static function homepage_multi_thumb_min_images(): int {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return (int) $settings['homepage_multi_thumb_min_images'];
|
||||
}
|
||||
|
||||
public static function homepage_sidebar_mini_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['homepage_sidebar_mini_enabled']);
|
||||
}
|
||||
|
||||
public static function homepage_default_sort(): string {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['home_list1_orderby_option']['orderby'] ?? 'date';
|
||||
}
|
||||
|
||||
public static function homepage_default_view(): string {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['homepage_default_view'];
|
||||
}
|
||||
|
||||
public static function homepage_sort_ajax_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['homepage_sort_ajax_enabled']);
|
||||
}
|
||||
|
||||
public static function homepage_sticky_tabs_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['homepage_sticky_tabs_enabled']);
|
||||
}
|
||||
|
||||
public static function home_posts_list_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['home_posts_list_s']);
|
||||
}
|
||||
|
||||
public static function home_list_title(): string {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return (string) $settings['index_list_title'];
|
||||
}
|
||||
|
||||
public static function home_list_sort_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['home_list1_orderby_s']);
|
||||
}
|
||||
|
||||
public static function home_list_sort_options(): array {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['home_list1_orderby_option']['options'] ?? ['modified', 'date', 'views', 'likes', 'comments'];
|
||||
}
|
||||
|
||||
public static function home_list_sort_dropdown(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['home_list_sort_dropdown']);
|
||||
}
|
||||
|
||||
public static function home_exclude_post_ids(): array {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['home_exclude_posts'];
|
||||
}
|
||||
|
||||
public static function home_exclude_category_ids(): array {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['home_exclude_cats'];
|
||||
}
|
||||
|
||||
public static function homepage_tab_posts_per_page(): int {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return (int) $settings['homepage_tab_posts_per_page'];
|
||||
}
|
||||
|
||||
public static function homepage_tab_limit(): int {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return (int) $settings['homepage_tab_limit'];
|
||||
}
|
||||
|
||||
public static function get_paid_content_settings(): array {
|
||||
return PaymentRuntime::get_paid_content_settings();
|
||||
}
|
||||
|
||||
public static function get_content_coupon_settings(): array {
|
||||
return PaymentRuntime::get_content_coupon_settings();
|
||||
}
|
||||
|
||||
public static function get_payment_recharge_settings(): array {
|
||||
return PaymentRuntime::get_payment_recharge_settings();
|
||||
}
|
||||
|
||||
public static function get_payment_vip_settings(): array {
|
||||
return PaymentRuntime::get_payment_vip_settings();
|
||||
}
|
||||
|
||||
public static function get_payment_revenue_settings(): array {
|
||||
return PaymentRuntime::get_payment_revenue_settings();
|
||||
}
|
||||
|
||||
public static function get_payment_affiliate_settings(): array {
|
||||
return PaymentRuntime::get_payment_affiliate_settings();
|
||||
}
|
||||
|
||||
public static function get_payment_gateway_settings(): array {
|
||||
return PaymentRuntime::get_payment_gateway_settings();
|
||||
}
|
||||
|
||||
public static function get_order_settings(): array {
|
||||
return PaymentRuntime::get_order_settings();
|
||||
}
|
||||
|
||||
public static function get_card_pass_settings(): array {
|
||||
return PaymentRuntime::get_card_pass_settings();
|
||||
}
|
||||
|
||||
public static function get_withdrawal_settings(): array {
|
||||
return PaymentRuntime::get_withdrawal_settings();
|
||||
}
|
||||
|
||||
private static function normalize_sort_options(array $raw): array {
|
||||
$allowed = self::homepage_allowed_sorts();
|
||||
$result = [];
|
||||
$seen = [];
|
||||
|
||||
foreach ($raw as $key) {
|
||||
$key = sanitize_key((string) $key);
|
||||
if (in_array($key, $allowed, true) && !isset($seen[$key])) {
|
||||
$result[] = $key;
|
||||
$seen[$key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($result)) {
|
||||
$result = ['modified', 'date', 'views', 'likes', 'comments'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function normalize_int_array($raw): array {
|
||||
if (!is_array($raw)) {
|
||||
return [];
|
||||
}
|
||||
return array_values(array_filter(array_map('absint', $raw), static fn($v) => $v > 0));
|
||||
}
|
||||
|
||||
private static function normalize_homepage_tabs(array $raw_tabs): array {
|
||||
$allowed_orderby = self::homepage_allowed_sorts();
|
||||
$tabs = [];
|
||||
|
||||
foreach ($raw_tabs as $tab) {
|
||||
if (!is_array($tab)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$term_id = absint($tab['term_id'] ?? 0);
|
||||
if ($term_id <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$orderby = sanitize_key($tab['orderby'] ?? 'date');
|
||||
if (!in_array($orderby, $allowed_orderby, true)) {
|
||||
$orderby = 'date';
|
||||
}
|
||||
|
||||
$tabs[] = [
|
||||
'term_id' => $term_id,
|
||||
'title' => sanitize_text_field($tab['title'] ?? ''),
|
||||
'orderby' => $orderby,
|
||||
'enabled' => !empty($tab['enabled']),
|
||||
];
|
||||
}
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
private static function parse_slug_list(string $raw, array $fallback = []): array {
|
||||
$items = preg_split('/[\s,]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$normalized = [];
|
||||
|
||||
foreach ((array) $items as $item) {
|
||||
$slug = sanitize_key((string) $item);
|
||||
if ($slug !== '' && !in_array($slug, $normalized, true)) {
|
||||
$normalized[] = $slug;
|
||||
}
|
||||
}
|
||||
|
||||
return !empty($normalized) ? $normalized : $fallback;
|
||||
}
|
||||
|
||||
private static function count_structured_lines(string $raw): int {
|
||||
$lines = preg_split('/[\r\n]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$count = 0;
|
||||
|
||||
foreach ((array) $lines as $line) {
|
||||
if (trim((string) $line) !== '') {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait HomepageReader {
|
||||
|
||||
/**
|
||||
* Allowed sort/orderby values for the homepage.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function homepage_allowed_sorts(): array {
|
||||
return HomeCms::homepage_allowed_sorts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Full sort label map for admin UI and front-end rendering.
|
||||
*
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public static function homepage_sort_labels(): array {
|
||||
return HomeCms::homepage_sort_labels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed homepage visual settings.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_homepage_fixed_settings(): array {
|
||||
return HomeCms::get_homepage_fixed_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Homepage always uses ordinary posts.
|
||||
*
|
||||
* @return string Always 'post'.
|
||||
*/
|
||||
public static function homepage_content_model(): string {
|
||||
return HomeCms::homepage_content_model();
|
||||
}
|
||||
|
||||
/**
|
||||
* Structured homepage tabs.
|
||||
*
|
||||
* @return array<int, array{term_id:int, title:string, orderby:string, enabled:bool}>
|
||||
*/
|
||||
public static function homepage_tabs(): array {
|
||||
return HomeCms::homepage_tabs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Homepage card view variant.
|
||||
*
|
||||
* @return string default|style2|style3
|
||||
*/
|
||||
public static function homepage_card_style(): string {
|
||||
return HomeCms::homepage_card_style();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether homepage list cards should switch to the multi-thumb layout.
|
||||
*/
|
||||
public static function homepage_multi_thumb_enabled(): bool {
|
||||
return HomeCms::homepage_multi_thumb_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum image count required to trigger the multi-thumb layout.
|
||||
*/
|
||||
public static function homepage_multi_thumb_min_images(): int {
|
||||
return HomeCms::homepage_multi_thumb_min_images();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether homepage sidebar widgets should use the compact mini list style.
|
||||
*/
|
||||
public static function homepage_sidebar_mini_enabled(): bool {
|
||||
return HomeCms::homepage_sidebar_mini_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default homepage sort mode when no query override is present.
|
||||
*/
|
||||
public static function homepage_default_sort(): string {
|
||||
return HomeCms::homepage_default_sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default homepage view mode.
|
||||
*/
|
||||
public static function homepage_default_view(): string {
|
||||
return HomeCms::homepage_default_view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the homepage sortbar should refresh through AJAX.
|
||||
*/
|
||||
public static function homepage_sort_ajax_enabled(): bool {
|
||||
return HomeCms::homepage_sort_ajax_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the homepage tabs should use sticky/affix behaviour.
|
||||
*/
|
||||
public static function homepage_sticky_tabs_enabled(): bool {
|
||||
return HomeCms::homepage_sticky_tabs_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the main "latest posts" list is enabled on the homepage.
|
||||
*/
|
||||
public static function home_posts_list_enabled(): bool {
|
||||
return HomeCms::home_posts_list_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom title for the main homepage list section.
|
||||
*/
|
||||
public static function home_list_title(): string {
|
||||
return HomeCms::home_list_title();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the sort bar is enabled for the main stream.
|
||||
*/
|
||||
public static function home_list_sort_enabled(): bool {
|
||||
return HomeCms::home_list_sort_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configured sort option keys for the main stream sort bar.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function home_list_sort_options(): array {
|
||||
return HomeCms::home_list_sort_options();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the sort bar uses a dropdown instead of inline links.
|
||||
*/
|
||||
public static function home_list_sort_dropdown(): bool {
|
||||
return HomeCms::home_list_sort_dropdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Post IDs excluded from both main stream and tab queries.
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public static function home_exclude_post_ids(): array {
|
||||
return HomeCms::home_exclude_post_ids();
|
||||
}
|
||||
|
||||
/**
|
||||
* Category IDs excluded from the main stream.
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public static function home_exclude_category_ids(): array {
|
||||
return HomeCms::home_exclude_category_ids();
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts per page for each category tab.
|
||||
*/
|
||||
public static function homepage_tab_posts_per_page(): int {
|
||||
return HomeCms::homepage_tab_posts_per_page();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum number of category tabs to display.
|
||||
*/
|
||||
public static function homepage_tab_limit(): int {
|
||||
return HomeCms::homepage_tab_limit();
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 顶部多功能组件设置(图标卡片 + 搜索覆盖)
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 是否显示顶部组件搜索覆盖框
|
||||
*/
|
||||
public static function header_components_search_enabled(): bool {
|
||||
return DisplayRuntime::header_components_search_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 顶部组件搜索详细配置(PC/移动分别 + 子选项)
|
||||
*
|
||||
* @return array{pc:bool,mobile:bool,show_keywords:bool,popular_limit:int,show_input_cat:bool,show_type:bool,keywords:string[],categories:array,type_options:array}
|
||||
*/
|
||||
public static function get_header_components_search_config(): array {
|
||||
return DisplayRuntime::get_header_components_search_config();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否显示顶部组件图标卡片覆盖
|
||||
*/
|
||||
public static function header_components_cards_enabled(): bool {
|
||||
return DisplayRuntime::header_components_cards_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶部组件图标卡片配置
|
||||
* @return array
|
||||
*/
|
||||
public static function homepage_module_hero_enabled(): bool {
|
||||
return DisplayRuntime::homepage_module_hero_enabled();
|
||||
}
|
||||
|
||||
public static function homepage_module_banner_enabled(): bool {
|
||||
return DisplayRuntime::homepage_module_banner_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Global slider configuration shared by Hero and Banner.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_slider_config(): array {
|
||||
return DisplayRuntime::get_slider_config();
|
||||
}
|
||||
|
||||
public static function get_header_components_icon_cards(): array {
|
||||
return DisplayRuntime::get_header_components_icon_cards();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶部组件卡片列数
|
||||
*/
|
||||
public static function get_header_components_card_columns(): int {
|
||||
return DisplayRuntime::get_header_components_card_columns();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否显示顶部组件卡片背景色
|
||||
*/
|
||||
public static function header_components_card_bg_enabled(): bool {
|
||||
return DisplayRuntime::header_components_card_bg_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页脚配色配置
|
||||
*/
|
||||
public static function get_footer_theme_config(): array {
|
||||
return HomeCms::get_footer_theme_config();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* Identity provider configuration for the admin REST surface.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
use AKSRT\Identity\Provider\ProviderFactory;
|
||||
use AKSRT\Identity\SecretStore;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
final class IdentityAdmin {
|
||||
|
||||
private const PROVIDER_FIELDS = [
|
||||
'aliyun' => ['access_key_id', 'access_key_secret'],
|
||||
'tencent' => ['secret_id', 'secret_key'],
|
||||
];
|
||||
|
||||
/** @return array<string,mixed> */
|
||||
public static function read(): array {
|
||||
$stored = Settings::get_all();
|
||||
$provider = sanitize_key((string) ($stored['user_verify_provider'] ?? 'aliyun'));
|
||||
if (!isset(self::PROVIDER_FIELDS[$provider])) {
|
||||
$provider = 'aliyun';
|
||||
}
|
||||
return [
|
||||
'provider' => $provider,
|
||||
'providers' => [
|
||||
'aliyun' => self::provider_state('aliyun'),
|
||||
'tencent' => self::provider_state('tencent'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** @param array<string,mixed> $input @return array<string,mixed> */
|
||||
public static function update(array $input): array {
|
||||
if (array_key_exists('provider', $input)) {
|
||||
$provider = sanitize_key((string) $input['provider']);
|
||||
if (isset(self::PROVIDER_FIELDS[$provider])) {
|
||||
Settings::write_domain('users', 'verify', ['user_verify_provider' => $provider]);
|
||||
}
|
||||
}
|
||||
|
||||
$providers = isset($input['providers']) && is_array($input['providers']) ? $input['providers'] : [];
|
||||
foreach (self::PROVIDER_FIELDS as $provider => $fields) {
|
||||
$changes = isset($providers[$provider]) && is_array($providers[$provider]) ? $providers[$provider] : [];
|
||||
$updates = [];
|
||||
if (!empty($changes['clear_credentials'])) {
|
||||
foreach ($fields as $field) {
|
||||
$updates[$field] = null;
|
||||
}
|
||||
} else {
|
||||
$credentials = isset($changes['credentials']) && is_array($changes['credentials']) ? $changes['credentials'] : [];
|
||||
foreach ($fields as $field) {
|
||||
$value = trim((string) ($credentials[$field] ?? ''));
|
||||
if ($value !== '') {
|
||||
$updates[$field] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($updates !== []) {
|
||||
SecretStore::update($provider, $updates);
|
||||
}
|
||||
}
|
||||
return self::read();
|
||||
}
|
||||
|
||||
/** @return array{success:bool,message:string} */
|
||||
public static function test(string $provider): array {
|
||||
if (!isset(self::PROVIDER_FIELDS[$provider])) {
|
||||
return ['success' => false, 'message' => __('不支持的身份认证服务商', 'aksrt')];
|
||||
}
|
||||
$valid = ProviderFactory::make($provider)->validate_config();
|
||||
if (is_wp_error($valid)) {
|
||||
return ['success' => false, 'message' => $valid->get_error_message()];
|
||||
}
|
||||
return ['success' => true, 'message' => sprintf(__('%s配置检查通过', 'aksrt'), self::label($provider))];
|
||||
}
|
||||
|
||||
/** @return array<string,mixed> */
|
||||
private static function provider_state(string $provider): array {
|
||||
$secrets = SecretStore::get($provider);
|
||||
$configured_fields = [];
|
||||
$missing = [];
|
||||
foreach (self::PROVIDER_FIELDS[$provider] as $field) {
|
||||
$configured = !empty($secrets[$field]);
|
||||
$configured_fields[$field] = $configured;
|
||||
if (!$configured) {
|
||||
$missing[] = $field;
|
||||
}
|
||||
}
|
||||
return [
|
||||
'label' => self::label($provider),
|
||||
'configured' => $missing === [],
|
||||
'configured_fields' => $configured_fields,
|
||||
'missing_fields' => $missing,
|
||||
];
|
||||
}
|
||||
|
||||
private static function label(string $provider): string {
|
||||
return $provider === 'aliyun' ? __('阿里云', 'aksrt') : __('腾讯云', 'aksrt');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,621 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class Integration {
|
||||
|
||||
/** 私信邮件接收组限制 (all/vip/vip2/admin) */
|
||||
public static function get_email_private_receive_limit(): string {
|
||||
$limit = (string) Settings::get_value('email_private_receive_limit', 'all');
|
||||
$valid = ['all', 'vip', 'vip2', 'admin'];
|
||||
return in_array($limit, $valid, true) ? $limit : 'all';
|
||||
}
|
||||
|
||||
/** 获取OAuth配置 */
|
||||
public static function get_oauth(): array {
|
||||
return get_option('aksrt_oauth', []);
|
||||
}
|
||||
|
||||
/** 检查OAuth平台是否已配置 */
|
||||
public static function oauth_configured(string $provider): bool {
|
||||
$oauth = self::get_oauth();
|
||||
return !empty($oauth[$provider]['client_id']) && !empty($oauth[$provider]['client_secret']);
|
||||
}
|
||||
|
||||
/** OAuth 代理登录模式: 'off' | 'server' | 'client' (schema 存 'close'→映射为 'off') */
|
||||
public static function oauth_proxy_mode(): string {
|
||||
$settings = Settings::get_all();
|
||||
$mode = sanitize_key((string) ($settings['oauth_proxy_mode'] ?? ''));
|
||||
if ($mode === '') {
|
||||
$oauth = self::get_oauth();
|
||||
$mode = $oauth['proxy']['mode'] ?? (!empty($settings['oauth_agent']) ? 'client' : 'off');
|
||||
}
|
||||
if ($mode === 'close') {
|
||||
$mode = 'off';
|
||||
}
|
||||
return in_array($mode, ['off', 'server', 'client'], true) ? $mode : 'off';
|
||||
}
|
||||
|
||||
/** OAuth 代理登录 HMAC 密钥 */
|
||||
public static function oauth_proxy_secret(): string {
|
||||
$settings = Settings::get_all();
|
||||
if (!empty($settings['oauth_proxy_secret'])) {
|
||||
return (string) $settings['oauth_proxy_secret'];
|
||||
}
|
||||
$oauth = self::get_oauth();
|
||||
return (string) ($oauth['proxy']['secret'] ?? '');
|
||||
}
|
||||
|
||||
/** OAuth 代理登录服务端地址(客户端模式使用) */
|
||||
public static function oauth_proxy_server_url(): string {
|
||||
$settings = Settings::get_all();
|
||||
if (!empty($settings['oauth_proxy_server_url'])) {
|
||||
return esc_url_raw((string) $settings['oauth_proxy_server_url']);
|
||||
}
|
||||
$oauth = self::get_oauth();
|
||||
return esc_url_raw((string) ($oauth['proxy']['server_url'] ?? ''));
|
||||
}
|
||||
|
||||
/** OAuth 代理登录允许的平台列表(服务端模式使用) */
|
||||
public static function oauth_proxy_allowed_providers(): array {
|
||||
$settings = Settings::get_all();
|
||||
$valid = ['github', 'gitee', 'qq', 'google', 'weibo', 'weixin', 'baidu', 'alipay'];
|
||||
if (isset($settings['oauth_proxy_server_providers']) && is_array($settings['oauth_proxy_server_providers'])) {
|
||||
return array_values(array_intersect($settings['oauth_proxy_server_providers'], $valid));
|
||||
}
|
||||
$oauth = self::get_oauth();
|
||||
$allowed = $oauth['proxy']['allowed_providers'] ?? ['github', 'gitee', 'qq', 'google'];
|
||||
return array_values(array_intersect($allowed, $valid));
|
||||
}
|
||||
|
||||
/** OAuth 代理登录启用的平台列表(客户端模式使用) */
|
||||
public static function oauth_proxy_client_providers(): array {
|
||||
$settings = Settings::get_all();
|
||||
$valid = ['github', 'gitee', 'qq', 'google', 'weibo', 'weixin', 'baidu', 'alipay'];
|
||||
if (isset($settings['oauth_proxy_client_providers']) && is_array($settings['oauth_proxy_client_providers'])) {
|
||||
return array_values(array_intersect($settings['oauth_proxy_client_providers'], $valid));
|
||||
}
|
||||
$oauth = self::get_oauth();
|
||||
$enabled = $oauth['proxy']['client_providers'] ?? ['github', 'gitee', 'qq', 'google'];
|
||||
return array_values(array_intersect($enabled, $valid));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信公众号登录完整配置
|
||||
*
|
||||
* @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 {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$gzh_type = sanitize_key((string) ($settings['weixingzh_gzh_type'] ?? 'service'));
|
||||
if (!in_array($gzh_type, ['service', 'subscribe'], true)) {
|
||||
$gzh_type = 'service';
|
||||
}
|
||||
|
||||
$auto_expires = max(0, min(86400, (int) ($settings['weixingzh_auto_expires'] ?? 3600)));
|
||||
|
||||
return [
|
||||
'gzh_type' => $gzh_type,
|
||||
'token' => (string) ($settings['weixingzh_token'] ?? ''),
|
||||
'token_nocheck' => !empty($settings['weixingzh_token_nocheck']),
|
||||
'encoding_aes_key' => (string) ($settings['weixingzh_encoding_aes_key'] ?? ''),
|
||||
'appid' => (string) ($settings['weixingzh_appid'] ?? ''),
|
||||
'appsecret' => (string) ($settings['weixingzh_appsecret'] ?? ''),
|
||||
'code_qrcode' => (string) ($settings['weixingzh_code_qrcode'] ?? ''),
|
||||
'code_keyword' => (string) ($settings['weixingzh_code_keyword'] ?? '登录'),
|
||||
'code_reply' => (string) ($settings['weixingzh_code_reply'] ?? ''),
|
||||
'code_subscribe_reply' => (string) ($settings['weixingzh_code_subscribe_reply'] ?? ''),
|
||||
'subscribe_msg' => (string) ($settings['weixingzh_subscribe_msg'] ?? ''),
|
||||
'new_subscribe_msg' => (string) ($settings['weixingzh_new_subscribe_msg'] ?? ''),
|
||||
'scan_msg' => (string) ($settings['weixingzh_scan_msg'] ?? ''),
|
||||
'auto_reply_text' => (string) ($settings['weixingzh_auto_reply_text'] ?? ''),
|
||||
'auto_reply_search' => (string) ($settings['weixingzh_auto_reply_search'] ?? ''),
|
||||
'auto_reply_image' => (string) ($settings['weixingzh_auto_reply_image'] ?? ''),
|
||||
'auto_reply_voice' => (string) ($settings['weixingzh_auto_reply_voice'] ?? ''),
|
||||
'auto_reply_default' => (string) ($settings['weixingzh_auto_reply_default'] ?? ''),
|
||||
'gzh_menu' => (string) ($settings['weixingzh_gzh_menu'] ?? ''),
|
||||
'priority' => !empty($settings['weixingzh_priority']),
|
||||
'auto' => !empty($settings['weixingzh_auto']),
|
||||
'auto_expires' => $auto_expires,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 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 {
|
||||
$settings = Settings::get_all();
|
||||
$oauth = self::get_oauth();
|
||||
|
||||
$mode = sanitize_key((string) ($settings['oauth_proxy_mode'] ?? ''));
|
||||
if ($mode === '') {
|
||||
$mode = $oauth['proxy']['mode'] ?? (!empty($settings['oauth_agent']) ? 'client' : 'close');
|
||||
}
|
||||
if (!in_array($mode, ['close', 'server', 'client'], true)) {
|
||||
$mode = 'close';
|
||||
}
|
||||
|
||||
$secret = (string) ($settings['oauth_proxy_secret'] ?? ($oauth['proxy']['secret'] ?? ''));
|
||||
$server_url = esc_url_raw((string) ($settings['oauth_proxy_server_url'] ?? ($oauth['proxy']['server_url'] ?? '')));
|
||||
|
||||
$valid_providers = ['github', 'gitee', 'qq', 'google', 'weibo', 'weixin', 'baidu', 'alipay'];
|
||||
$server_providers = array_values(array_intersect(
|
||||
(array) ($settings['oauth_proxy_server_providers'] ?? ($oauth['proxy']['allowed_providers'] ?? ['github', 'gitee', 'qq', 'google'])),
|
||||
$valid_providers
|
||||
));
|
||||
$client_providers = array_values(array_intersect(
|
||||
(array) ($settings['oauth_proxy_client_providers'] ?? ($oauth['proxy']['client_providers'] ?? ['github', 'gitee', 'qq', 'google'])),
|
||||
$valid_providers
|
||||
));
|
||||
|
||||
$gzh_type = sanitize_key((string) ($settings['oauth_proxy_gzh_type'] ?? 'service'));
|
||||
if (!in_array($gzh_type, ['service', 'subscribe'], true)) {
|
||||
$gzh_type = 'service';
|
||||
}
|
||||
|
||||
return [
|
||||
'mode' => $mode,
|
||||
'secret' => $secret,
|
||||
'server_url' => $server_url,
|
||||
'server_providers' => $server_providers,
|
||||
'client_providers' => $client_providers,
|
||||
'gzh_type' => $gzh_type,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取底部Tab完整配置
|
||||
* @return array {enabled, scroll_hide, scroll_down_hide, items}
|
||||
*/
|
||||
public static function get_footer_tabbar_settings(): array {
|
||||
$defaults = [
|
||||
'enabled' => true,
|
||||
'scroll_hide' => false,
|
||||
'scroll_down_hide' => true,
|
||||
'max_items' => 5,
|
||||
'icon_size' => 22,
|
||||
'text_size' => 10,
|
||||
'show_text' => true,
|
||||
'active_color' => '#f04494',
|
||||
'bg_color' => '',
|
||||
'border' => true,
|
||||
'shadow' => true,
|
||||
'animation' => true,
|
||||
'double_click_home' => true,
|
||||
'badge_dot' => false,
|
||||
'footer_tabbar_single' => 'default',
|
||||
'items' => [
|
||||
[
|
||||
'id' => 'tab_home',
|
||||
'type' => 'home',
|
||||
'icon' => 'fas fa-home',
|
||||
'text' => __('首页', 'aksrt'),
|
||||
'link' => '',
|
||||
'badge' => '',
|
||||
'badge_mode' => 'static',
|
||||
'category_id' => 0,
|
||||
'new_window' => false,
|
||||
'enabled' => true,
|
||||
'sort_order' => 0,
|
||||
'ontop' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'tab_category',
|
||||
'type' => 'category',
|
||||
'icon' => 'fas fa-th-large',
|
||||
'text' => __('分类', 'aksrt'),
|
||||
'link' => '',
|
||||
'badge' => '',
|
||||
'badge_mode' => 'static',
|
||||
'category_id' => 0,
|
||||
'new_window' => false,
|
||||
'enabled' => true,
|
||||
'sort_order' => 1,
|
||||
],
|
||||
[
|
||||
'id' => 'tab_search',
|
||||
'type' => 'search',
|
||||
'icon' => 'fas fa-search',
|
||||
'text' => __('搜索', 'aksrt'),
|
||||
'link' => '',
|
||||
'badge' => '',
|
||||
'badge_mode' => 'dynamic',
|
||||
'category_id' => 0,
|
||||
'search_default_type' => 'post',
|
||||
'new_window' => false,
|
||||
'enabled' => true,
|
||||
'sort_order' => 2,
|
||||
],
|
||||
[
|
||||
'id' => 'tab_auth',
|
||||
'type' => 'auth',
|
||||
'icon' => 'fas fa-user',
|
||||
'text' => __('我的', 'aksrt'),
|
||||
'link' => '',
|
||||
'badge' => '',
|
||||
'badge_mode' => 'dynamic',
|
||||
'category_id' => 0,
|
||||
'search_default_type' => 'post',
|
||||
'new_window' => false,
|
||||
'enabled' => true,
|
||||
'sort_order' => 3,
|
||||
],
|
||||
],
|
||||
];
|
||||
$saved = get_option('aksrt_footer_tabbar', []);
|
||||
if (!is_array($saved)) {
|
||||
$saved = [];
|
||||
}
|
||||
return array_merge($defaults, $saved);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取底部Tab项(仅返回启用的,按排序)
|
||||
* @return array
|
||||
*/
|
||||
public static function get_footer_tabbar_items(): array {
|
||||
$settings = self::get_footer_tabbar_settings();
|
||||
if (empty($settings['enabled'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$items = array_filter($settings['items'], fn($item) => !empty($item['enabled']));
|
||||
usort($items, fn($a, $b) => ($a['sort_order'] ?? 0) <=> ($b['sort_order'] ?? 0));
|
||||
return array_values($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章页专属Tab模式
|
||||
* @return string 'default' | 'extend'
|
||||
*/
|
||||
public static function get_footer_tabbar_single(): string {
|
||||
$settings = self::get_footer_tabbar_settings();
|
||||
$mode = (string) ($settings['footer_tabbar_single'] ?? 'default');
|
||||
$valid = ['default', 'extend'];
|
||||
return in_array($mode, $valid, true) ? $mode : 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通知系统设置
|
||||
* @return array {read_retention_days, unread_retention_days, max_per_user}
|
||||
*/
|
||||
public static function get_notification_settings(): array {
|
||||
$defaults = [
|
||||
'enabled_types' => [
|
||||
'comment_reply' => true,
|
||||
'comment_approved' => true,
|
||||
'download_ready' => true,
|
||||
'credits_added' => true,
|
||||
'credits_deducted' => true,
|
||||
'verify_email' => true,
|
||||
'pending_comments' => true,
|
||||
'upload_moderation' => true,
|
||||
],
|
||||
'user_badge_enabled' => true,
|
||||
'badge_include_stateful' => true,
|
||||
'read_retention_days' => 30,
|
||||
'unread_retention_days' => 180,
|
||||
'max_per_user' => 200,
|
||||
];
|
||||
$saved = get_option('aksrt_notification_settings', []);
|
||||
if (!is_array($saved)) {
|
||||
$saved = [];
|
||||
}
|
||||
$merged = array_merge($defaults, $saved);
|
||||
$merged['read_retention_days'] = max(1, min(365, (int) $merged['read_retention_days']));
|
||||
$merged['unread_retention_days'] = max(7, min(3650, (int) $merged['unread_retention_days']));
|
||||
$merged['max_per_user'] = max(20, min(5000, (int) $merged['max_per_user']));
|
||||
return $merged;
|
||||
}
|
||||
|
||||
/** 单项通知是否启用 */
|
||||
public static function notification_enabled(string $type): bool {
|
||||
$settings = self::get_notification_settings();
|
||||
$enabled = is_array($settings['enabled_types'] ?? null) ? $settings['enabled_types'] : [];
|
||||
return !isset($enabled[$type]) || !empty($enabled[$type]);
|
||||
}
|
||||
|
||||
/** user 徽标是否启用 */
|
||||
public static function notification_user_badge_enabled(): bool {
|
||||
$settings = self::get_notification_settings();
|
||||
return !isset($settings['user_badge_enabled']) || !empty($settings['user_badge_enabled']);
|
||||
}
|
||||
|
||||
/** user 徽标是否包含即时提醒 */
|
||||
public static function notification_badge_include_stateful(): bool {
|
||||
$settings = self::get_notification_settings();
|
||||
return !empty($settings['badge_include_stateful']);
|
||||
}
|
||||
|
||||
/** 站内通知总开关 */
|
||||
public static function message_enabled(): bool {
|
||||
return !empty(Settings::get_value('message_s', true));
|
||||
}
|
||||
|
||||
/** 通知基础设置(basic group) */
|
||||
public static function notification_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$slug = sanitize_key((string) ($settings['msg_center_rewrite_slug'] ?? 'message'));
|
||||
if ($slug === '') {
|
||||
$slug = 'message';
|
||||
}
|
||||
|
||||
$paginate = sanitize_key((string) ($settings['message_paginate_type'] ?? 'ajax_lists'));
|
||||
if (!in_array($paginate, ['ajax_lists', 'default'], true)) {
|
||||
$paginate = 'ajax_lists';
|
||||
}
|
||||
|
||||
$icon_show = $settings['message_icon_show'] ?? ['nav_menu'];
|
||||
if (!is_array($icon_show)) {
|
||||
$icon_show = ['nav_menu'];
|
||||
}
|
||||
$allowed_positions = ['nav_menu', 'avatar', 'mobile_bar'];
|
||||
$icon_show = array_values(array_intersect($icon_show, $allowed_positions));
|
||||
|
||||
return [
|
||||
'enabled' => !empty($settings['message_s']),
|
||||
'slug' => $slug,
|
||||
'icon_show' => $icon_show,
|
||||
'paginate_type' => $paginate,
|
||||
'user_set' => !empty($settings['message_user_set']),
|
||||
];
|
||||
}
|
||||
|
||||
/** 已关闭的通知推送类型列表 */
|
||||
public static function notification_closed_types(): array {
|
||||
$types = Settings::get_value('message_close_msg_type', []);
|
||||
if (!is_array($types)) {
|
||||
return [];
|
||||
}
|
||||
$allowed = ['posts', 'comment', 'favorite', 'like', 'hot', 'followed', 'system', 'pay', 'withdraw_reply', 'medal', 'auth_apply_reply'];
|
||||
return array_values(array_intersect($types, $allowed));
|
||||
}
|
||||
|
||||
/** 自动清理已读消息配置 */
|
||||
public static function auto_clear_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$types = $settings['message_auto_clear_types'] ?? ['posts', 'comment', 'favorite', 'like', 'hot', 'followed', 'system'];
|
||||
if (!is_array($types)) {
|
||||
$types = [];
|
||||
}
|
||||
$allowed = ['posts', 'comment', 'favorite', 'like', 'hot', 'followed', 'system', 'pay', 'withdraw_reply', 'medal', 'auth_apply_reply', 'download', 'credits', 'private', 'report'];
|
||||
return [
|
||||
'enabled' => !empty($settings['message_auto_clear_s']),
|
||||
'days' => max(1, min(3650, (int) ($settings['message_auto_clear_time'] ?? 365))),
|
||||
'types' => array_values(array_intersect($types, $allowed)),
|
||||
];
|
||||
}
|
||||
|
||||
/** 私信功能配置 */
|
||||
public static function private_message_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$quick_often = (string) ($settings['private_quick_often'] ?? "你好,请问有什么可以帮你的?\n感谢你的反馈\n已处理,请查收");
|
||||
$quick_lines = array_filter(array_map('trim', preg_split('/\r\n|\r|\n/', $quick_often)));
|
||||
|
||||
return [
|
||||
'enabled' => !array_key_exists('private_s', $settings) || !empty($settings['private_s']),
|
||||
'smilie' => !empty($settings['private_smilie_s']),
|
||||
'code' => !empty($settings['private_code_s']),
|
||||
'image' => !empty($settings['private_image_s']),
|
||||
'upload_img' => !empty($settings['private_upload_img']),
|
||||
'quick_reply' => !empty($settings['private_quick_s']),
|
||||
'quick_often' => array_values($quick_lines),
|
||||
'submit_text' => sanitize_text_field((string) ($settings['private_submit_text'] ?? '发送')),
|
||||
'placeholder' => sanitize_text_field((string) ($settings['private_placeholder'] ?? '请输入消息...')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取右侧浮动按钮完整配置
|
||||
* @return array {enabled, style, position, scroll_hide, scroll_down_hide, filter_blur, items}
|
||||
*/
|
||||
public static function get_floating_buttons_settings(): array {
|
||||
$defaults = [
|
||||
'enabled' => true,
|
||||
'style' => 'round',
|
||||
'position' => 'bottom',
|
||||
'scroll_hide' => false,
|
||||
'scroll_down_hide' => true,
|
||||
'max' => 5,
|
||||
'size' => 44,
|
||||
'spacing' => 10,
|
||||
'shadow' => true,
|
||||
'animation' => true,
|
||||
'opacity' => 100,
|
||||
'active_color' => '',
|
||||
'bg_color' => '',
|
||||
'pc_show' => true,
|
||||
'm_show' => true,
|
||||
'filter_blur' => ['mobile'],
|
||||
'items' => [
|
||||
[
|
||||
'id' => 'btn_wechat',
|
||||
'type' => 'service_wechat',
|
||||
'icon' => 'fab fa-weixin',
|
||||
'icon_dark' => '',
|
||||
'icon_light' => '',
|
||||
'text' => __('微信', 'aksrt'),
|
||||
'desc' => '',
|
||||
'action_mode'=> 'qrcode',
|
||||
'qq' => '',
|
||||
'qrcode_img' => '',
|
||||
'wechat_img' => '',
|
||||
'link' => '',
|
||||
'add_items' => [],
|
||||
'hover' => '',
|
||||
'qr_size' => 120,
|
||||
'hover_width' => 200,
|
||||
'pc_s' => true,
|
||||
'm_s' => true,
|
||||
'color' => '',
|
||||
'bg' => '',
|
||||
'enabled' => true,
|
||||
'sort_order' => 0,
|
||||
],
|
||||
[
|
||||
'id' => 'btn_theme',
|
||||
'type' => 'theme_mode',
|
||||
'icon' => 'fas fa-sun',
|
||||
'icon_dark' => '',
|
||||
'icon_light' => '',
|
||||
'text' => __('主题', 'aksrt'),
|
||||
'desc' => __('切换主题', 'aksrt'),
|
||||
'action_mode'=> 'link',
|
||||
'qq' => '',
|
||||
'qrcode_img' => '',
|
||||
'wechat_img' => '',
|
||||
'link' => '',
|
||||
'add_items' => [],
|
||||
'hover' => '',
|
||||
'qr_size' => 120,
|
||||
'hover_width' => 200,
|
||||
'pc_s' => true,
|
||||
'm_s' => false,
|
||||
'color' => '',
|
||||
'bg' => '',
|
||||
'enabled' => true,
|
||||
'sort_order' => 1,
|
||||
],
|
||||
[
|
||||
'id' => 'btn_top',
|
||||
'type' => 'back_top',
|
||||
'icon' => 'fas fa-chevron-up',
|
||||
'icon_dark' => '',
|
||||
'icon_light' => '',
|
||||
'text' => __('顶部', 'aksrt'),
|
||||
'desc' => __('返回顶部', 'aksrt'),
|
||||
'action_mode'=> 'link',
|
||||
'qq' => '',
|
||||
'qrcode_img' => '',
|
||||
'wechat_img' => '',
|
||||
'link' => '',
|
||||
'add_items' => [],
|
||||
'hover' => '',
|
||||
'qr_size' => 120,
|
||||
'hover_width' => 200,
|
||||
'pc_s' => true,
|
||||
'm_s' => true,
|
||||
'color' => '',
|
||||
'bg' => '',
|
||||
'enabled' => true,
|
||||
'sort_order' => 2,
|
||||
],
|
||||
],
|
||||
];
|
||||
$saved = get_option('aksrt_floating_buttons', []);
|
||||
if (!is_array($saved)) {
|
||||
$saved = [];
|
||||
}
|
||||
return array_merge($defaults, $saved);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取右侧浮动按钮项(仅返回启用的,按排序)
|
||||
* @return array
|
||||
*/
|
||||
public static function get_floating_buttons_items(): array {
|
||||
$settings = self::get_floating_buttons_settings();
|
||||
if (empty($settings['enabled'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$items = array_filter($settings['items'], fn($item) => !empty($item['enabled']));
|
||||
usort($items, fn($a, $b) => ($a['sort_order'] ?? 0) <=> ($b['sort_order'] ?? 0));
|
||||
return array_values($items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信通知设置
|
||||
*
|
||||
* @return array{enabled:bool,app_id:string,app_secret:string,template_id:string}
|
||||
*/
|
||||
public static function get_wechat_settings(): array {
|
||||
$stored = get_option('aksrt_wechat_settings', []);
|
||||
if (!is_array($stored)) {
|
||||
$stored = [];
|
||||
}
|
||||
|
||||
return [
|
||||
'enabled' => !empty($stored['enabled']),
|
||||
'app_id' => sanitize_text_field((string) ($stored['app_id'] ?? '')),
|
||||
'app_secret' => (string) ($stored['app_secret'] ?? ''),
|
||||
'template_id' => sanitize_text_field((string) ($stored['template_id'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新微信通知设置
|
||||
*
|
||||
* @param array $settings 合并后的完整微信配置
|
||||
*/
|
||||
public static function update_wechat_settings(array $settings): void {
|
||||
$allowed = ['enabled', 'app_id', 'app_secret', 'template_id'];
|
||||
$clean = [];
|
||||
foreach ($allowed as $key) {
|
||||
if (array_key_exists($key, $settings)) {
|
||||
$clean[$key] = $settings[$key];
|
||||
}
|
||||
}
|
||||
update_option('aksrt_wechat_settings', $clean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档模式设置
|
||||
*/
|
||||
public static function get_docs_mode_settings(): array {
|
||||
$all = Settings::get_all();
|
||||
|
||||
$template = in_array($all['docs_mode_default_template'] ?? '', ['documentnav', 'special'], true)
|
||||
? $all['docs_mode_default_template']
|
||||
: 'documentnav';
|
||||
|
||||
$order = in_array($all['docs_mode_default_order'] ?? '', ['menu_order', 'date', 'title'], true)
|
||||
? $all['docs_mode_default_order']
|
||||
: 'menu_order';
|
||||
|
||||
$style = in_array($all['docs_mode_style'] ?? '', ['default', 'simple', 'card'], true)
|
||||
? $all['docs_mode_style']
|
||||
: 'default';
|
||||
|
||||
$raw_cats = $all['docs_mode_cats'] ?? [];
|
||||
if (!is_array($raw_cats)) {
|
||||
$raw_cats = array_filter(array_map('trim', explode(',', (string) $raw_cats)));
|
||||
}
|
||||
$cats = array_values(array_filter(array_map('absint', $raw_cats)));
|
||||
|
||||
return [
|
||||
'enabled' => !empty($all['docs_mode_enabled']),
|
||||
'default_template' => $template,
|
||||
'toc_enabled' => !isset($all['docs_mode_toc_enabled']) || !empty($all['docs_mode_toc_enabled']),
|
||||
'chapter_nav_enabled' => !isset($all['docs_mode_chapter_nav_enabled']) || !empty($all['docs_mode_chapter_nav_enabled']),
|
||||
'default_order' => $order,
|
||||
'cats' => $cats,
|
||||
'exclude' => !isset($all['docs_mode_exclude']) || !empty($all['docs_mode_exclude']),
|
||||
'toc_depth' => max(1, min(6, (int) ($all['docs_mode_toc_depth'] ?? 3))),
|
||||
'chapter_title' => sanitize_text_field((string) ($all['docs_mode_chapter_title'] ?? '')),
|
||||
'style' => $style,
|
||||
'icon' => !isset($all['docs_mode_icon']) || !empty($all['docs_mode_icon']),
|
||||
'count' => !isset($all['docs_mode_count']) || !empty($all['docs_mode_count']),
|
||||
'docs_mode_enabled' => !empty($all['docs_mode_enabled']),
|
||||
'docs_mode_default_template' => $template,
|
||||
'docs_mode_toc_enabled' => !isset($all['docs_mode_toc_enabled']) || !empty($all['docs_mode_toc_enabled']),
|
||||
'docs_mode_chapter_nav_enabled' => !isset($all['docs_mode_chapter_nav_enabled']) || !empty($all['docs_mode_chapter_nav_enabled']),
|
||||
'docs_mode_default_order' => $order,
|
||||
'docs_mode_cats' => $cats,
|
||||
'docs_mode_exclude' => !isset($all['docs_mode_exclude']) || !empty($all['docs_mode_exclude']),
|
||||
'docs_mode_toc_depth' => max(1, min(6, (int) ($all['docs_mode_toc_depth'] ?? 3))),
|
||||
'docs_mode_chapter_title' => sanitize_text_field((string) ($all['docs_mode_chapter_title'] ?? '')),
|
||||
'docs_mode_style' => $style,
|
||||
'docs_mode_icon' => !isset($all['docs_mode_icon']) || !empty($all['docs_mode_icon']),
|
||||
'docs_mode_count' => !isset($all['docs_mode_count']) || !empty($all['docs_mode_count']),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class Mail {
|
||||
|
||||
/** 所有邮件事件类型常量 */
|
||||
public const EMAIL_EVENTS = [
|
||||
'reg_verify_link',
|
||||
'reg_verify_code',
|
||||
'reg_success',
|
||||
'password_reset',
|
||||
'change_code',
|
||||
'change_notice',
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取邮件事件配置
|
||||
*
|
||||
* @param string $event 事件类型,留空返回全部
|
||||
* @return array
|
||||
*/
|
||||
public static function get_email_event_config(string $event = ''): array {
|
||||
$s = Settings::get_all();
|
||||
|
||||
$global = [
|
||||
'footer_text' => sanitize_text_field((string) ($s['email_footer_text'] ?? '')),
|
||||
'site_branding' => !isset($s['email_site_branding']) || !empty($s['email_site_branding']),
|
||||
'template_mode' => in_array($s['email_template_mode'] ?? 'plain', ['plain', 'html'], true)
|
||||
? ($s['email_template_mode'] ?? 'plain') : 'plain',
|
||||
];
|
||||
|
||||
if ($event === '') {
|
||||
$events = [];
|
||||
foreach (self::EMAIL_EVENTS as $ev) {
|
||||
$events[$ev] = self::build_email_event_entry($s, $ev);
|
||||
}
|
||||
return ['global' => $global, 'events' => $events];
|
||||
}
|
||||
|
||||
if (!in_array($event, self::EMAIL_EVENTS, true)) {
|
||||
return ['enabled' => true, 'subject' => '', 'content' => '', 'html' => false, 'global' => $global];
|
||||
}
|
||||
|
||||
return array_merge(self::build_email_event_entry($s, $event), ['global' => $global]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮件事件是否启用
|
||||
*/
|
||||
public static function is_email_event_enabled(string $event): bool {
|
||||
if (!in_array($event, self::EMAIL_EVENTS, true)) {
|
||||
return true;
|
||||
}
|
||||
$s = Settings::get_all();
|
||||
return !isset($s["email_{$event}_enabled"]) || !empty($s["email_{$event}_enabled"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过邮件事件体系发送邮件
|
||||
*/
|
||||
public static function send_event_email(
|
||||
string $event,
|
||||
string $to,
|
||||
string $default_subject,
|
||||
string $default_content,
|
||||
array $placeholders = []
|
||||
): bool {
|
||||
if (!self::is_email_event_enabled($event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cfg = self::get_email_event_config($event);
|
||||
|
||||
$subject = ($cfg['subject'] !== '') ? $cfg['subject'] : $default_subject;
|
||||
$subject = strtr($subject, $placeholders);
|
||||
|
||||
$content = ($cfg['content'] !== '') ? $cfg['content'] : $default_content;
|
||||
$content = strtr($content, $placeholders);
|
||||
|
||||
$branding = Settings::get_mail_branding();
|
||||
$footer = $cfg['global']['footer_text'];
|
||||
if ($footer === '' && $branding['description'] !== '') {
|
||||
$footer = $branding['description'];
|
||||
}
|
||||
if ($footer === '') {
|
||||
$footer = get_bloginfo('name');
|
||||
}
|
||||
if ($footer !== '') {
|
||||
$content .= "\n\n— " . $footer;
|
||||
if ($branding['description'] !== '' && $footer !== $branding['description']) {
|
||||
$content .= "\n" . $branding['description'];
|
||||
}
|
||||
}
|
||||
|
||||
$is_html = $cfg['html'] || ($cfg['global']['template_mode'] === 'html');
|
||||
$headers = [$is_html ? 'Content-Type: text/html; charset=UTF-8' : 'Content-Type: text/plain; charset=UTF-8'];
|
||||
|
||||
return wp_mail($to, $subject, $content, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建单个邮件事件条目
|
||||
*/
|
||||
private static function build_email_event_entry(array $s, string $event): array {
|
||||
return [
|
||||
'enabled' => !isset($s["email_{$event}_enabled"]) || !empty($s["email_{$event}_enabled"]),
|
||||
'subject' => sanitize_text_field((string) ($s["email_{$event}_subject"] ?? '')),
|
||||
'content' => sanitize_textarea_field((string) ($s["email_{$event}_content"] ?? '')),
|
||||
'html' => !empty($s["email_{$event}_html"]),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,510 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class PaymentRuntime {
|
||||
|
||||
/**
|
||||
* Paid content / download policy.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_paid_content_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$features = HomeCms::get_cms_features();
|
||||
$catalog_note = trim((string) ($settings['payment_paid_catalog_note'] ?? ''));
|
||||
$manual_note = trim((string) ($settings['payment_manual_delivery_note'] ?? ''));
|
||||
|
||||
$box_position = sanitize_key((string) ($settings['pay_box_position'] ?? 'top'));
|
||||
// Zibll: box_top | top | bottom | box_bottom
|
||||
if (!in_array($box_position, ['box_top', 'top', 'bottom', 'box_bottom'], true)) {
|
||||
$box_position = 'top';
|
||||
}
|
||||
|
||||
return [
|
||||
'download_login' => !empty($features['download_login']),
|
||||
'download_credit' => !empty($features['download_credit']) && Settings::credits_enabled(),
|
||||
'download_captcha' => !empty($features['download_captcha']),
|
||||
'default_cost' => Settings::download_default_cost(),
|
||||
'paid_post_types' => self::parse_slug_list((string) ($settings['payment_paid_post_types'] ?? 'post'), ['post']),
|
||||
'vip_free_download' => !empty($settings['payment_vip_free_download']),
|
||||
'vip_exempt_roles' => self::parse_slug_list((string) ($settings['payment_vip_exempt_roles'] ?? '')),
|
||||
'catalog_note' => $catalog_note,
|
||||
'manual_delivery_note' => $manual_note !== '' ? $manual_note : __('付费或人工确认内容请在订单备注中记录交付方式。', 'aksrt'),
|
||||
'no_logged_in' => !isset($settings['pay_no_logged_in']) || !empty($settings['pay_no_logged_in']),
|
||||
'free_logged_show' => !empty($settings['pay_free_logged_show']),
|
||||
'down_alone_page' => !empty($settings['payment_down_alone_page']),
|
||||
'display' => [
|
||||
'mark' => sanitize_text_field((string) ($settings['pay_mark'] ?? '付费')),
|
||||
'currency_symbol' => sanitize_text_field((string) ($settings['payment_currency_symbol'] ?? '¥')),
|
||||
'show_user' => !isset($settings['pay_show_user']) || !empty($settings['pay_show_user']),
|
||||
'show_paycount' => !isset($settings['pay_show_paycount']) || !empty($settings['pay_show_paycount']),
|
||||
'box_position' => $box_position,
|
||||
],
|
||||
'download' => [
|
||||
'enabled' => !empty($settings['payment_download_enable']),
|
||||
'remote' => !isset($settings['payment_download_remote_s']) || !empty($settings['payment_download_remote_s']),
|
||||
'verify_nonce' => !isset($settings['payment_download_verify_nonce']) || !empty($settings['payment_download_verify_nonce']),
|
||||
'user_log' => max(0, min(9999, (int) ($settings['payment_download_user_log'] ?? 50))),
|
||||
'post_log' => max(0, min(9999, (int) ($settings['payment_download_post_log'] ?? 50))),
|
||||
'remote_size' => max(1, (int) ($settings['payment_download_remote_size'] ?? 2048)),
|
||||
'remote_ext' => sanitize_text_field((string) ($settings['payment_download_remote_ext'] ?? 'zip,rar,7z')),
|
||||
'alone_page' => !empty($settings['payment_down_alone_page']),
|
||||
],
|
||||
// Content cashier coupon (zibll coupon_post_s / coupon_desc).
|
||||
'coupon_post_s' => !empty($settings['coupon_post_s']),
|
||||
'coupon_desc' => sanitize_textarea_field((string) ($settings['coupon_desc'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Content coupon global switches (zibll coupon_post_s).
|
||||
*
|
||||
* @return array{enabled:bool,desc:string}
|
||||
*/
|
||||
public static function get_content_coupon_settings(): array {
|
||||
$settings = self::get_paid_content_settings();
|
||||
return [
|
||||
'enabled' => !empty($settings['coupon_post_s']),
|
||||
'desc' => (string) ($settings['coupon_desc'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Balance recharge settings (Zibll pay_balance_* contract).
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_payment_recharge_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$packages = (string) ($settings['pay_balance_product'] ?? "30|30|入门包\n98|108|推荐包");
|
||||
if (is_array($settings['pay_balance_product'] ?? null)) {
|
||||
$packages = self::format_product_lines((array) $settings['pay_balance_product']);
|
||||
}
|
||||
$desc = sanitize_textarea_field((string) ($settings['pay_balance_desc'] ?? ''));
|
||||
|
||||
return [
|
||||
'enabled' => !empty($settings['pay_balance_s']),
|
||||
'desc' => $desc,
|
||||
'auto_to_balance' => !isset($settings['pay_auto_to_balance']) || !empty($settings['pay_auto_to_balance']),
|
||||
'packages_raw' => $packages,
|
||||
'package_count' => self::count_structured_lines($packages),
|
||||
'help_text' => $desc !== '' ? $desc : __('当前支持人工确认与测试联调;接入真实网关时复用同一组字段。', 'aksrt'),
|
||||
'product' => [
|
||||
'name' => sanitize_text_field((string) ($settings['pay_balance_product_name'] ?? '')),
|
||||
'price' => max(0, (float) ($settings['pay_balance_price'] ?? 0)),
|
||||
'tag' => sanitize_text_field((string) ($settings['pay_balance_tag'] ?? '元')),
|
||||
'tag_class' => sanitize_text_field((string) ($settings['pay_balance_tag_class'] ?? '')),
|
||||
'custom_s' => !isset($settings['pay_balance_product_custom_s']) || !empty($settings['pay_balance_product_custom_s']),
|
||||
'custom_limit' => max(1, min(99999, (int) ($settings['pay_balance_product_custom_limit'] ?? 9999))),
|
||||
],
|
||||
'transfer' => [
|
||||
'enabled' => !empty($settings['pay_balance_transfer_s']),
|
||||
'service_charge' => max(0, min(50, (int) ($settings['pay_balance_transfer_service_charge'] ?? 0))),
|
||||
'desc' => sanitize_textarea_field((string) ($settings['pay_balance_transfer_desc'] ?? '')),
|
||||
],
|
||||
'pass_charge' => [
|
||||
'enabled' => !empty($settings['pay_balance_pass_charge_s']),
|
||||
'desc' => sanitize_textarea_field((string) ($settings['pay_balance_pass_charge_desc'] ?? '')),
|
||||
'only_password' => !empty($settings['pay_balance_pass_charge_only_password']),
|
||||
],
|
||||
'exchange' => [
|
||||
'enabled' => !empty($settings['pay_balance_exchange_s']),
|
||||
'rate' => max(1, min(10000, (int) ($settings['pay_balance_exchange_rate'] ?? 100))),
|
||||
'desc' => sanitize_textarea_field((string) ($settings['pay_balance_exchange_desc'] ?? '')),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Dual-level VIP settings (Zibll pay_user_vip_1 / pay_user_vip_2).
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_payment_vip_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$vip1_enabled = !empty($settings['pay_user_vip_1_s']);
|
||||
$vip2_enabled = !empty($settings['pay_user_vip_2_s']);
|
||||
$enabled = $vip1_enabled || $vip2_enabled;
|
||||
|
||||
$name1 = trim((string) ($settings['pay_user_vip_1_name'] ?? ''));
|
||||
$name2 = trim((string) ($settings['pay_user_vip_2_name'] ?? ''));
|
||||
if ($name1 === '') {
|
||||
$name1 = __('一级会员', 'aksrt');
|
||||
}
|
||||
if ($name2 === '') {
|
||||
$name2 = __('二级会员', 'aksrt');
|
||||
}
|
||||
|
||||
$badge = $vip2_enabled ? $name2 : ($vip1_enabled ? $name1 : __('VIP', 'aksrt'));
|
||||
|
||||
$renew_price_type = sanitize_key((string) ($settings['vip_renew_price_type'] ?? 'discount'));
|
||||
if (!in_array($renew_price_type, ['same', 'discount', 'reduce'], true)) {
|
||||
$renew_price_type = 'discount';
|
||||
}
|
||||
|
||||
$default_l1 = "30|59|1|month|限时|月卡\n98|199|3|month|特惠|季卡\n365|599|12|month|超值|年卡\n999|1299|0|day|永久|永久卡";
|
||||
$default_l2 = "58|99|1|month|限时|月卡\n168|299|3|month|特惠|季卡\n598|999|12|month|超值|年卡\n1299|1999|0|day|永久|永久卡";
|
||||
$products_1 = sanitize_textarea_field((string) ($settings['payment_vip_1_products'] ?? $default_l1));
|
||||
$products_2 = sanitize_textarea_field((string) ($settings['payment_vip_2_products'] ?? $default_l2));
|
||||
// Restore newlines lost only if empty after sanitize — sanitize_textarea_field keeps \n.
|
||||
if (trim($products_1) === '') {
|
||||
$products_1 = $default_l1;
|
||||
}
|
||||
if (trim($products_2) === '') {
|
||||
$products_2 = $default_l2;
|
||||
}
|
||||
|
||||
$desc = sanitize_textarea_field((string) ($settings['pay_user_vip_desc'] ?? ''));
|
||||
$more = (string) ($settings['pay_user_vip_more'] ?? '');
|
||||
$allowed_equity = [
|
||||
'li' => [],
|
||||
'ul' => [],
|
||||
'ol' => [],
|
||||
'strong' => [],
|
||||
'b' => [],
|
||||
'em' => [],
|
||||
'i' => ['class' => true],
|
||||
'span' => ['class' => true],
|
||||
'br' => [],
|
||||
'a' => ['href' => true, 'target' => true, 'rel' => true, 'class' => true],
|
||||
];
|
||||
|
||||
return [
|
||||
'enabled' => $enabled,
|
||||
'name' => $vip1_enabled ? $name1 : $badge,
|
||||
'badge_text' => $badge,
|
||||
'desc' => $desc,
|
||||
'more' => wp_kses($more, $allowed_equity + ['div' => ['class' => true], 'p' => ['class' => true]]),
|
||||
'help_text' => $desc !== '' ? $desc : __('会员权益以免扣下载和身份展示为主,开通后立即生效。', 'aksrt'),
|
||||
'levels' => [
|
||||
1 => [
|
||||
'enabled' => $vip1_enabled,
|
||||
'name' => $name1,
|
||||
'desc' => sanitize_text_field((string) ($settings['pay_user_vip_1_desc'] ?? __('尊享一级会员特权', 'aksrt'))),
|
||||
'equity' => wp_kses((string) (($settings['pay_user_vip_1_equity'] ?? '') !== '' ? $settings['pay_user_vip_1_equity'] : '<li>免费下载部分资源</li><li>会员专属身份标识</li><li>付费内容会员价</li>'), $allowed_equity),
|
||||
'img_icon' => esc_url_raw((string) ($settings['vip_1_img_icon'] ?? '')),
|
||||
'product_s' => !isset($settings['vip_1_product_s']) || !empty($settings['vip_1_product_s']),
|
||||
'products_raw' => $products_1,
|
||||
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_1'] ?? 0))),
|
||||
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_1'] ?? 0))),
|
||||
],
|
||||
2 => [
|
||||
'enabled' => $vip2_enabled,
|
||||
'name' => $name2,
|
||||
'desc' => sanitize_text_field((string) ($settings['pay_user_vip_2_desc'] ?? __('尊享二级会员特权', 'aksrt'))),
|
||||
'equity' => wp_kses((string) (($settings['pay_user_vip_2_equity'] ?? '') !== '' ? $settings['pay_user_vip_2_equity'] : '<li>更高免费下载额度</li><li>更高等级身份标识</li><li>更多付费内容会员价</li>'), $allowed_equity),
|
||||
'img_icon' => esc_url_raw((string) ($settings['vip_2_img_icon'] ?? '')),
|
||||
'product_s' => !isset($settings['vip_2_product_s']) || !empty($settings['vip_2_product_s']),
|
||||
'products_raw' => $products_2,
|
||||
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_2'] ?? 0))),
|
||||
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_2'] ?? 0))),
|
||||
],
|
||||
],
|
||||
'benefit' => [
|
||||
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit'] ?? 0))),
|
||||
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed'] ?? 0))),
|
||||
'pass_charge' => !empty($settings['pay_vip_pass_charge_s']),
|
||||
'pass_charge_desc' => sanitize_textarea_field((string) ($settings['pay_vip_pass_charge_desc'] ?? '')),
|
||||
'pass_charge_only_password' => !isset($settings['pay_vip_pass_charge_only_password']) || !empty($settings['pay_vip_pass_charge_only_password']),
|
||||
],
|
||||
'renew' => [
|
||||
'enabled' => !isset($settings['vip_renew']) || !empty($settings['vip_renew']),
|
||||
'desc' => sanitize_textarea_field((string) ($settings['vip_renew_desc'] ?? '')),
|
||||
'price_type' => $renew_price_type,
|
||||
'discount' => max(1, min(100, (int) ($settings['vip_renew_discount'] ?? 8))),
|
||||
'reduce' => max(0, min(9999, (int) ($settings['vip_renew_reduce'] ?? 20))),
|
||||
],
|
||||
'upgrade' => [
|
||||
'enabled' => !isset($settings['vip_upgrade']) || !empty($settings['vip_upgrade']),
|
||||
'desc' => sanitize_textarea_field((string) ($settings['vip_upgrade_desc'] ?? '')),
|
||||
// Multi-line upgrade product rules — must not collapse newlines.
|
||||
'product' => sanitize_textarea_field((string) ($settings['vip_upgrade_product'] ?? '')),
|
||||
],
|
||||
'points_exchange' => [
|
||||
'enabled' => !empty($settings['pay_vip_points_exchange_s']),
|
||||
'desc' => sanitize_textarea_field((string) ($settings['pay_vip_points_exchange_desc'] ?? '')),
|
||||
'packages_raw' => sanitize_textarea_field((string) ($settings['payment_vip_points_packages'] ?? "1|500|30|积分月卡\n1|5000|0|积分永久")),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_payment_revenue_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$note = trim((string) ($settings['payment_revenue_note'] ?? ''));
|
||||
|
||||
return [
|
||||
'enabled' => !empty($settings['pay_income_s']),
|
||||
'share_ratio' => max(0, min(100, (int) ($settings['payment_revenue_share_ratio'] ?? 70))),
|
||||
'ratio_vip1' => max(0, min(100, (int) ($settings['ratio_vip_1'] ?? 0))),
|
||||
'ratio_vip2' => max(0, min(100, (int) ($settings['ratio_vip_2'] ?? 0))),
|
||||
'settlement_threshold' => max(0, (int) ($settings['payment_revenue_settlement_threshold'] ?? 100)),
|
||||
'cycle_days' => max(1, min(365, (int) ($settings['payment_revenue_cycle_days'] ?? 30))),
|
||||
'points_rule' => sanitize_textarea_field((string) ($settings['payment_revenue_points_rule'] ?? '')),
|
||||
'note' => $note !== '' ? $note : __('分成策略和台账结构已就绪,订单入账后自动按比例结算。', 'aksrt'),
|
||||
'display' => [
|
||||
'desc_details' => sanitize_textarea_field((string) ($settings['pay_income_desc_details'] ?? '')),
|
||||
'desc_page' => esc_url_raw((string) ($settings['pay_income_desc_page'] ?? '')),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_payment_affiliate_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$note = trim((string) ($settings['pay_rebate_text_desc'] ?? ''));
|
||||
|
||||
return [
|
||||
'enabled' => !empty($settings['pay_rebate_s']),
|
||||
'ratio' => max(0, min(100, (int) ($settings['pay_rebate_ratio'] ?? 10))),
|
||||
'window_days' => max(1, min(365, (int) ($settings['payment_affiliate_window_days'] ?? 30))),
|
||||
'require_paid_order' => !isset($settings['payment_affiliate_require_paid_order']) || !empty($settings['payment_affiliate_require_paid_order']),
|
||||
'self_s' => !isset($settings['pay_rebate_self_s']) || !empty($settings['pay_rebate_self_s']),
|
||||
'show_users' => !isset($settings['pay_rebate_show_users']) || !empty($settings['pay_rebate_show_users']),
|
||||
'note' => $note !== '' ? $note : __('返佣链路复用邀请体系,订单归因和结算自动衔接当前策略字段。', 'aksrt'),
|
||||
'user_ratio' => [
|
||||
'user' => max(0, min(100, (int) ($settings['payment_affiliate_user_ratio'] ?? $settings['pay_rebate_ratio'] ?? 10))),
|
||||
'vip1' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_1'] ?? 0))),
|
||||
'vip2' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_2'] ?? 0))),
|
||||
],
|
||||
'poster' => [
|
||||
'enabled' => !isset($settings['pay_rebate_poster_s']) || !empty($settings['pay_rebate_poster_s']),
|
||||
'img' => esc_url_raw((string) ($settings['pay_rebate_poster_img'] ?? '')),
|
||||
'title' => sanitize_text_field((string) ($settings['pay_rebate_poster_title'] ?? '')),
|
||||
'desc' => sanitize_text_field((string) ($settings['pay_rebate_poster_desc'] ?? '')),
|
||||
],
|
||||
'text' => [
|
||||
'desc' => sanitize_textarea_field((string) ($settings['pay_rebate_text_desc'] ?? '')),
|
||||
'details_title' => sanitize_text_field((string) ($settings['pay_rebate_text_details_title'] ?? '')),
|
||||
'details' => sanitize_textarea_field((string) ($settings['pay_rebate_text_details'] ?? '')),
|
||||
'discount' => sanitize_text_field((string) ($settings['pay_rebate_text_discount'] ?? '')),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_payment_gateway_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$gateway_keys = ['wechat', 'alipay', 'paypal', 'stripe', 'balance', 'card_pass', 'epay'];
|
||||
$gateways = [];
|
||||
foreach ($gateway_keys as $gw) {
|
||||
$gateways[$gw] = !empty($settings["payment_{$gw}_enabled"]);
|
||||
}
|
||||
|
||||
return [
|
||||
'help_text' => __('以渠道开关与凭据是否齐全为准;异步回调由各网关验签。卡密为兑换入口,不进入收银台。', 'aksrt'),
|
||||
'gateways' => $gateways,
|
||||
'epay' => [
|
||||
'apiurl' => esc_url_raw((string) ($settings['epay_apiurl'] ?? '')),
|
||||
'pid' => sanitize_text_field((string) ($settings['epay_pid'] ?? '')),
|
||||
'key' => sanitize_text_field((string) ($settings['epay_key'] ?? '')),
|
||||
'channel_alipay' => !array_key_exists('epay_channel_alipay', $settings) || !empty($settings['epay_channel_alipay']),
|
||||
'channel_wxpay' => !array_key_exists('epay_channel_wxpay', $settings) || !empty($settings['epay_channel_wxpay']),
|
||||
'device' => sanitize_key((string) ($settings['epay_device'] ?? 'auto')),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Order display / checkout policy (Zibll pay_* + AKSRT order ops).
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_order_settings(): array {
|
||||
$s = Settings::get_all();
|
||||
|
||||
$expiry = max(5, min(1440, (int) ($s['payment_order_expiry'] ?? 30)));
|
||||
$cookie_day = max(1, min(31, (int) ($s['pay_cookie_day'] ?? 15)));
|
||||
$max_minutes = max(5, min(1440, (int) ($s['payment_order_max_minutes'] ?? 30)));
|
||||
|
||||
$box_position = sanitize_key((string) ($s['pay_box_position'] ?? 'top'));
|
||||
if (!in_array($box_position, ['box_top', 'top', 'bottom', 'box_bottom'], true)) {
|
||||
$box_position = 'top';
|
||||
}
|
||||
|
||||
$status_keys = ['pending', 'paid', 'completed', 'cancelled', 'refunded', 'refunding', 'processing'];
|
||||
$status_defaults = ['待支付', '已支付', '已完成', '已取消', '已退款', '退款中', '处理中'];
|
||||
$status_texts = [];
|
||||
foreach ($status_keys as $i => $key) {
|
||||
$val = trim((string) ($s["payment_order_status_{$key}"] ?? ''));
|
||||
$status_texts[$key] = $val !== '' ? $val : $status_defaults[$i];
|
||||
}
|
||||
|
||||
return [
|
||||
'prefix' => sanitize_text_field((string) ($s['payment_order_prefix'] ?? 'AKSRT')),
|
||||
'expiry' => $expiry,
|
||||
'show_user' => !isset($s['pay_show_user']) || !empty($s['pay_show_user']),
|
||||
'show_paycount' => !isset($s['pay_show_paycount']) || !empty($s['pay_show_paycount']),
|
||||
'no_logged_in' => !isset($s['pay_no_logged_in']) || !empty($s['pay_no_logged_in']),
|
||||
'cookie_day' => $cookie_day,
|
||||
'no_logged_remind' => sanitize_textarea_field((string) ($s['pay_no_logged_remind'] ?? '')),
|
||||
'wait_float' => !isset($s['pay_wait_float_s']) || !empty($s['pay_wait_float_s']),
|
||||
'order_max_minutes' => $max_minutes,
|
||||
'mark' => sanitize_text_field((string) ($s['pay_mark'] ?? '付费')),
|
||||
'box_position' => $box_position,
|
||||
'free_logged_show' => !empty($s['pay_free_logged_show']),
|
||||
'show_ip' => !empty($s['payment_show_ip']),
|
||||
'show_device' => !empty($s['payment_show_device']),
|
||||
'show_order_no' => !isset($s['payment_show_order_no']) || !empty($s['payment_show_order_no']),
|
||||
'show_create_time' => !isset($s['payment_show_create_time']) || !empty($s['payment_show_create_time']),
|
||||
'show_pay_time' => !isset($s['payment_show_pay_time']) || !empty($s['payment_show_pay_time']),
|
||||
'status_texts' => $status_texts,
|
||||
'service' => [
|
||||
'text' => sanitize_textarea_field((string) ($s['pay_service'] ?? '')),
|
||||
'icon' => sanitize_text_field((string) ($s['pay_service_icon'] ?? '')),
|
||||
'value' => sanitize_text_field((string) ($s['pay_service_value'] ?? '')),
|
||||
'qq' => sanitize_text_field((string) ($s['pay_service_qq'] ?? '')),
|
||||
'wechat' => esc_url_raw((string) ($s['pay_service_wechat'] ?? '')),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_card_pass_settings(): array {
|
||||
$s = Settings::get_all();
|
||||
|
||||
$type = sanitize_key((string) ($s['card_pass_type'] ?? 'balance'));
|
||||
if (!in_array($type, ['balance', 'vip', 'credits'], true)) {
|
||||
$type = 'balance';
|
||||
}
|
||||
|
||||
$success_msg = trim((string) ($s['card_pass_success_msg'] ?? ''));
|
||||
$fail_msg = trim((string) ($s['card_pass_fail_msg'] ?? ''));
|
||||
|
||||
return [
|
||||
'enabled' => !empty($s['card_pass_enabled']),
|
||||
'desc' => sanitize_textarea_field((string) ($s['card_pass_desc'] ?? '')),
|
||||
'type' => $type,
|
||||
'prefix' => sanitize_text_field((string) ($s['card_pass_prefix'] ?? 'AK')),
|
||||
'length' => max(8, min(32, (int) ($s['card_pass_length'] ?? 16))),
|
||||
'batch_size' => max(1, min(500, (int) ($s['card_pass_batch_size'] ?? 50))),
|
||||
'max_redeem' => max(1, min(100, (int) ($s['card_pass_max_redeem'] ?? 1))),
|
||||
'expiry_days' => max(0, (int) ($s['card_pass_expiry'] ?? 0)),
|
||||
'amount' => max(1, min(9999, (int) ($s['card_pass_amount'] ?? 10))),
|
||||
'vip_days' => max(1, min(3650, (int) ($s['card_pass_vip_days'] ?? 30))),
|
||||
'credits' => max(0, min(99999, (int) ($s['card_pass_credits'] ?? 0))),
|
||||
'redeem_page' => esc_url_raw((string) ($s['card_pass_redeem_page'] ?? '')),
|
||||
'success_msg' => $success_msg !== '' ? $success_msg : __('兑换成功!', 'aksrt'),
|
||||
'fail_msg' => $fail_msg !== '' ? $fail_msg : __('卡号无效或已过期', 'aksrt'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{min_amount:int,service_charge_rate:int,text:string}
|
||||
*/
|
||||
public static function get_withdrawal_settings(): array {
|
||||
$s = Settings::get_all();
|
||||
|
||||
return [
|
||||
'min_amount' => max(1, min(99999, (int) ($s['pay_rebate_withdraw_lowest_money'] ?? 50))),
|
||||
'service_charge_rate' => max(0, min(50, (int) ($s['withdraw_service_charge'] ?? 0))),
|
||||
'text' => sanitize_textarea_field((string) ($s['pay_rebate_withdraw_text_details'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a registered adapter is admin-enabled.
|
||||
* Maps gateway ids (wechatpay) to schema toggles (payment_wechat_enabled).
|
||||
*/
|
||||
public static function is_gateway_enabled(string $gateway_id): bool {
|
||||
$settings = Settings::get_all();
|
||||
$gateway_id = sanitize_key($gateway_id);
|
||||
$map = [
|
||||
'alipay' => 'payment_alipay_enabled',
|
||||
'wechatpay' => 'payment_wechat_enabled',
|
||||
'paypal' => 'payment_paypal_enabled',
|
||||
'stripe' => 'payment_stripe_enabled',
|
||||
'balance' => 'payment_balance_enabled',
|
||||
'card_pass' => 'payment_card_pass_enabled',
|
||||
'epay' => 'payment_epay_enabled',
|
||||
'epay_alipay' => 'payment_epay_enabled',
|
||||
'epay_wxpay' => 'payment_epay_enabled',
|
||||
];
|
||||
$key = $map[$gateway_id] ?? '';
|
||||
if ($key === '') {
|
||||
return false;
|
||||
}
|
||||
if ($gateway_id === 'balance') {
|
||||
// Master: 余额充值 → 启用余额功能. Optional kill-switch: payment_balance_enabled=false.
|
||||
// Missing key (legacy sites) follows pay_balance_s so "open wallet" alone enables pay.
|
||||
if (empty($settings['pay_balance_s'])) {
|
||||
return false;
|
||||
}
|
||||
if (array_key_exists('payment_balance_enabled', $settings) && empty($settings['payment_balance_enabled'])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (empty($settings[$key])) {
|
||||
return false;
|
||||
}
|
||||
// Epay sub-channels require the matching channel switch (default on when key missing).
|
||||
if ($gateway_id === 'epay_alipay') {
|
||||
return !array_key_exists('epay_channel_alipay', $settings) || !empty($settings['epay_channel_alipay']);
|
||||
}
|
||||
if ($gateway_id === 'epay_wxpay') {
|
||||
return !array_key_exists('epay_channel_wxpay', $settings) || !empty($settings['epay_channel_wxpay']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $fallback
|
||||
* @return string[]
|
||||
*/
|
||||
private static function parse_slug_list(string $raw, array $fallback = []): array {
|
||||
$items = preg_split('/[\s,]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$normalized = [];
|
||||
foreach ((array) $items as $item) {
|
||||
$slug = sanitize_key((string) $item);
|
||||
if ($slug !== '' && !in_array($slug, $normalized, true)) {
|
||||
$normalized[] = $slug;
|
||||
}
|
||||
}
|
||||
return !empty($normalized) ? $normalized : $fallback;
|
||||
}
|
||||
|
||||
private static function count_structured_lines(string $raw): int {
|
||||
$lines = preg_split('/[\r\n]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$count = 0;
|
||||
foreach ((array) $lines as $line) {
|
||||
if (trim((string) $line) !== '') {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int,mixed> $products
|
||||
*/
|
||||
private static function format_product_lines(array $products): string {
|
||||
$lines = [];
|
||||
foreach ($products as $row) {
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
$price = $row['pay_price'] ?? $row['price'] ?? '';
|
||||
$value = $row['value'] ?? $row['balance'] ?? $price;
|
||||
$title = $row['title'] ?? $row['name'] ?? '';
|
||||
$lines[] = $price . '|' . $value . '|' . $title;
|
||||
}
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,672 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class PostDisplay {
|
||||
|
||||
public static function get_post_list_style_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
// post_card_style storage key mirrors Zibll list_type.
|
||||
$list_type = sanitize_key((string) ($settings['post_card_style'] ?? 'thumb'));
|
||||
$allowed_list_types = ['thumb', 'compact', 'large_thumb', 'multi_thumb', 'text', 'thumb_if_has', 'card', 'standard'];
|
||||
|
||||
if (!in_array($list_type, $allowed_list_types, true)) {
|
||||
$list_type = 'thumb';
|
||||
}
|
||||
// Historical aliases → Zibll list_type tokens.
|
||||
if ($list_type === 'standard') {
|
||||
$list_type = 'thumb';
|
||||
}
|
||||
// Non-Zibll extras stay list-mode variants (never force card grid).
|
||||
if (in_array($list_type, ['compact', 'large_thumb', 'multi_thumb'], true)) {
|
||||
// Keep token for CSS hooks; render as list.
|
||||
}
|
||||
|
||||
// Zibll: only list_type=card is card mode; thumb/text/thumb_if_has are list.
|
||||
$render_mode_map = [
|
||||
'thumb' => 'list',
|
||||
'compact' => 'list',
|
||||
'large_thumb' => 'list',
|
||||
'multi_thumb' => 'list',
|
||||
'text' => 'list',
|
||||
'thumb_if_has' => 'list',
|
||||
'card' => 'card',
|
||||
];
|
||||
|
||||
$sticky_pages_raw = $settings['sticky_s'] ?? null;
|
||||
if (is_array($sticky_pages_raw)) {
|
||||
$allowed_pages = ['home', 'cat', 'tag', 'topics'];
|
||||
$sticky_pages = array_values(array_intersect(array_map('sanitize_key', $sticky_pages_raw), $allowed_pages));
|
||||
} else {
|
||||
$sticky_pages = ['home', 'cat'];
|
||||
}
|
||||
|
||||
$badge_types_raw = $settings['list_badge_show'] ?? null;
|
||||
if (is_array($badge_types_raw)) {
|
||||
$allowed_types = ['pay', 'cat', 'topics', 'tag'];
|
||||
$badge_types = array_values(array_intersect(array_map('sanitize_key', $badge_types_raw), $allowed_types));
|
||||
} else {
|
||||
$badge_types = ['pay', 'cat', 'topics', 'tag'];
|
||||
}
|
||||
|
||||
$show_author = array_key_exists('post_list_author', $settings)
|
||||
? !empty($settings['post_list_author'])
|
||||
: (!isset($settings['post_show_author']) || !empty($settings['post_show_author']));
|
||||
|
||||
$show_date = array_key_exists('post_list_time', $settings)
|
||||
? !empty($settings['post_list_time'])
|
||||
: (!isset($settings['post_show_date']) || !empty($settings['post_show_date']));
|
||||
|
||||
$target_blank = array_key_exists('target_blank', $settings)
|
||||
? !empty($settings['target_blank'])
|
||||
: !empty($settings['post_target_blank']);
|
||||
|
||||
$ajax_trigger = '';
|
||||
if (array_key_exists('ajax_trigger', $settings)) {
|
||||
$ajax_trigger = sanitize_text_field((string) $settings['ajax_trigger']);
|
||||
} elseif (array_key_exists('ajax_trigger_text', $settings)) {
|
||||
$ajax_trigger = sanitize_text_field((string) $settings['ajax_trigger_text']);
|
||||
}
|
||||
|
||||
$ajax_nomore = '';
|
||||
if (array_key_exists('ajax_nomore', $settings)) {
|
||||
$ajax_nomore = sanitize_text_field((string) $settings['ajax_nomore']);
|
||||
} elseif (array_key_exists('ajax_nomore_text', $settings)) {
|
||||
$ajax_nomore = sanitize_text_field((string) $settings['ajax_nomore_text']);
|
||||
}
|
||||
|
||||
$list_style = sanitize_key((string) ($settings['list_list_style'] ?? ''));
|
||||
if (!in_array($list_style, ['', 'style2'], true)) {
|
||||
$list_style = '';
|
||||
}
|
||||
|
||||
$card_variant = sanitize_key((string) ($settings['list_card_style'] ?? ''));
|
||||
if (!in_array($card_variant, ['', 'style3'], true)) {
|
||||
$card_variant = '';
|
||||
}
|
||||
|
||||
$card_cat_ids = [];
|
||||
if (is_array($settings['list_card_cat'] ?? null)) {
|
||||
$card_cat_ids = array_values(array_filter(array_map('intval', $settings['list_card_cat'])));
|
||||
}
|
||||
|
||||
return [
|
||||
// Zibll list_type (storage: post_card_style).
|
||||
'list_type' => $list_type,
|
||||
// Base mode from list_type only (surface card overrides applied by resolver).
|
||||
'render_mode' => $render_mode_map[$list_type] ?? 'list',
|
||||
// List item subtype token for text/thumb_if_has class hooks (not card variant).
|
||||
'list_type_token' => $list_type,
|
||||
// List mode visual variant (Zibll list_list_option.style).
|
||||
'list_style' => $list_style,
|
||||
// Card mode visual variant (Zibll list_card_option.style).
|
||||
'card_variant' => $card_variant,
|
||||
// Back-compat aliases used by older callers (prefer list_type / card_variant).
|
||||
'card_style' => $list_type,
|
||||
'show_author' => $show_author,
|
||||
'show_date' => $show_date,
|
||||
'show_views' => !isset($settings['post_show_views']) || !empty($settings['post_show_views']),
|
||||
'show_category' => !isset($settings['post_show_category']) || !empty($settings['post_show_category']),
|
||||
'show_comments' => !isset($settings['post_meta_comments']) || !empty($settings['post_meta_comments']),
|
||||
'show_likes' => !isset($settings['post_meta_likes']) || !empty($settings['post_meta_likes']),
|
||||
'badge_types' => $badge_types,
|
||||
'badge_show' => !empty($badge_types),
|
||||
'sticky_pages' => $sticky_pages,
|
||||
'sticky_enabled' => !empty($sticky_pages),
|
||||
'target_blank' => $target_blank,
|
||||
'heading_bold' => !empty($settings['item_heading_bold']),
|
||||
'mobile_meta' => in_array(sanitize_key((string) ($settings['list_meta_show'] ?? 'like')), ['view', 'like', 'comm'], true) ? sanitize_key((string) ($settings['list_meta_show'] ?? 'like')) : 'like',
|
||||
'list_show_type' => in_array(sanitize_key((string) ($settings['list_show_type'] ?? 'separate')), ['separate', 'no_margin'], true) ? sanitize_key((string) ($settings['list_show_type'] ?? 'separate')) : 'separate',
|
||||
'excerpt_length' => max(20, min(500, (int) ($settings['post_excerpt_length'] ?? 120))),
|
||||
'ias_max' => max(0, min(10, (int) ($settings['ias_max'] ?? 3))),
|
||||
'paging_ajax' => self::is_list_paging_ajax($settings),
|
||||
'paging_ajax_ias' => self::is_list_paging_ajax_ias($settings),
|
||||
'ajax_trigger_text' => $ajax_trigger,
|
||||
'ajax_nomore_text' => $ajax_nomore,
|
||||
'list_orderby' => in_array(sanitize_key((string) ($settings['list_orderby'] ?? 'modified')), ['modified', 'date', 'default'], true) ? sanitize_key((string) ($settings['list_orderby'] ?? 'modified')) : 'modified',
|
||||
'columns' => max(1, min(3, (int) ($settings['post_list_columns'] ?? 1))),
|
||||
'per_page' => max(4, min(48, (int) ($settings['post_list_per_page'] ?? 12))),
|
||||
'list_img_position' => in_array(sanitize_key((string) ($settings['list_list_img_position'] ?? 'left')), ['left', 'right'], true) ? sanitize_key((string) ($settings['list_list_img_position'] ?? 'left')) : 'left',
|
||||
'list_scale' => max(50, min(200, (int) ($settings['list_list_scale'] ?? 70))),
|
||||
'card_scale' => max(20, min(200, (int) ($settings['list_card_scale'] ?? 70))),
|
||||
'card_home' => !empty($settings['list_card_home']),
|
||||
'card_cat' => !empty($card_cat_ids),
|
||||
'card_cat_ids' => $card_cat_ids,
|
||||
'card_tag' => !empty($settings['list_card_tag']),
|
||||
'card_topics' => !empty($settings['list_card_topics']),
|
||||
'card_author' => !empty($settings['list_card_author']),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_post_thumb_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$priority_raw = (string) ($settings['thumb_priority'] ?? 'featured,attachment,resource,custom');
|
||||
$priority = preg_split('/[\s,]+/', strtolower($priority_raw)) ?: [];
|
||||
$priority = array_values(array_unique(array_filter(array_map('sanitize_key', $priority))));
|
||||
$allowed_sources = ['featured', 'attachment', 'resource', 'custom', 'category_cover', 'post_first_img'];
|
||||
$priority = array_values(array_filter($priority, static function (string $source) use ($allowed_sources): bool {
|
||||
return in_array($source, $allowed_sources, true);
|
||||
}));
|
||||
|
||||
if (empty($priority)) {
|
||||
$priority = ['featured', 'attachment', 'resource', 'custom'];
|
||||
}
|
||||
|
||||
$fallback = sanitize_key((string) ($settings['thumb_fallback'] ?? 'placeholder'));
|
||||
if (!in_array($fallback, ['placeholder', 'hide', 'random'], true)) {
|
||||
$fallback = 'placeholder';
|
||||
}
|
||||
|
||||
$aspect_ratio = (string) ($settings['thumb_aspect_ratio'] ?? '16:9');
|
||||
if (!in_array($aspect_ratio, ['16:9', '4:3', '1:1', 'auto'], true)) {
|
||||
$aspect_ratio = '16:9';
|
||||
}
|
||||
|
||||
return [
|
||||
'priority' => $priority,
|
||||
'fallback' => $fallback,
|
||||
'spare_images' => is_array($settings['thumb_spare_images'] ?? null) ? $settings['thumb_spare_images'] : [],
|
||||
'aspect_ratio' => $aspect_ratio,
|
||||
'multi_enabled' => !empty($settings['thumb_multi_enabled']),
|
||||
'multi_count' => max(2, min(6, (int) ($settings['thumb_multi_count'] ?? 3))),
|
||||
'lazy' => !isset($settings['thumb_lazy']) || !empty($settings['thumb_lazy']),
|
||||
'fit' => in_array(sanitize_key((string) ($settings['list_thumb_fit'] ?? 'cover')), ['cover', 'contain'], true) ? sanitize_key((string) ($settings['list_thumb_fit'] ?? 'cover')) : 'cover',
|
||||
'slides_s' => !isset($settings['list_thumb_slides_s']) || !empty($settings['list_thumb_slides_s']),
|
||||
'video_s' => !isset($settings['list_thumb_video_s']) || !empty($settings['list_thumb_video_s']),
|
||||
'video_mute_s' => !isset($settings['list_thumb_video_mute_s']) || !empty($settings['list_thumb_video_mute_s']),
|
||||
'postfirstimg_s' => !isset($settings['thumb_postfirstimg_s']) || !empty($settings['thumb_postfirstimg_s']),
|
||||
'catimg_s' => !isset($settings['thumb_catimg_s']) || !empty($settings['thumb_catimg_s']),
|
||||
'postfirstimg_size'=> in_array(sanitize_key((string) ($settings['thumb_postfirstimg_size'] ?? 'medium')), ['thumbnail', 'medium', 'large', 'full'], true) ? sanitize_key((string) ($settings['thumb_postfirstimg_size'] ?? 'medium')) : 'medium',
|
||||
'mult_thumb_cat_ids' => is_array($settings['mult_thumb_cat'] ?? null) ? array_map('intval', $settings['mult_thumb_cat']) : [],
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_post_filter_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
return [
|
||||
'enabled' => !empty($settings['filter_enabled']),
|
||||
'categories' => !isset($settings['filter_categories']) || !empty($settings['filter_categories']),
|
||||
'tags' => !empty($settings['filter_tags']),
|
||||
'sort' => !isset($settings['filter_sort']) || !empty($settings['filter_sort']),
|
||||
'ajax_enabled' => !empty($settings['filter_ajax_enabled']),
|
||||
'cat_show_cat' => !isset($settings['filter_cat_show_cat']) || !empty($settings['filter_cat_show_cat']),
|
||||
'cat_show_tag' => !empty($settings['filter_cat_show_tag']),
|
||||
'tag_show_cat' => !isset($settings['filter_tag_show_cat']) || !empty($settings['filter_tag_show_cat']),
|
||||
'tag_show_tag' => !empty($settings['filter_tag_show_tag']),
|
||||
'topics_show_cat' => !isset($settings['filter_topics_show_cat']) || !empty($settings['filter_topics_show_cat']),
|
||||
'topics_show_tag' => !empty($settings['filter_topics_show_tag']),
|
||||
'custom_filter_show' => is_array($settings['custom_filter_show'] ?? null) ? array_map('sanitize_key', $settings['custom_filter_show']) : ['cat', 'tag'],
|
||||
'custom_filter' => self::sanitize_custom_filter_defs($settings['custom_filter'] ?? []),
|
||||
'cat_custom_filter' => self::sanitize_cat_custom_filter($settings['cat_custom_filter'] ?? []),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_filter_config_for_category(int $term_id): array {
|
||||
$cfg = self::get_post_filter_settings();
|
||||
foreach ($cfg['cat_custom_filter'] as $rule) {
|
||||
if (in_array($term_id, $rule['cats'], true)) {
|
||||
return $rule;
|
||||
}
|
||||
}
|
||||
return [
|
||||
'cats' => [],
|
||||
'cat_s' => $cfg['cat_show_cat'],
|
||||
'tag_s' => $cfg['cat_show_tag'],
|
||||
'topics_s' => false,
|
||||
'orderby_s' => $cfg['sort'],
|
||||
'custom_filters' => [],
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_post_page_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
// Canonical render keys (used by aksrt_single_*). Legacy *_s aliases kept for older callers.
|
||||
$breadcrumbs = !isset($settings['breadcrumbs_single_s']) || !empty($settings['breadcrumbs_single_s']);
|
||||
$breadcrumbs_home = sanitize_text_field((string) ($settings['breadcrumbs_home_text'] ?? '首页'));
|
||||
// Zibll breadcrumbs_single_text: true → last crumb is "正文"; false → full title.
|
||||
$breadcrumbs_single_text = !isset($settings['breadcrumbs_single_text']) || !empty($settings['breadcrumbs_single_text']);
|
||||
$prevnext = !isset($settings['post_prevnext_s']) || !empty($settings['post_prevnext_s']);
|
||||
$authordesc = !isset($settings['post_authordesc_s']) || !empty($settings['post_authordesc_s']);
|
||||
$hide_time = !empty($settings['post_single_hide_time_s']);
|
||||
$share_enabled = !isset($settings['share_s']) || !empty($settings['share_s']);
|
||||
$rewards_enabled = !empty($settings['post_rewards_s']);
|
||||
$rewards_text = sanitize_text_field((string) ($settings['post_rewards_text'] ?? ''));
|
||||
if ($rewards_text === '') {
|
||||
$rewards_text = '赞赏';
|
||||
}
|
||||
$rewards_amounts = array_values(array_filter(array_map(static function ($value): float {
|
||||
return round((float) $value, 2);
|
||||
}, explode(',', (string) ($settings['post_rewards_amounts'] ?? '5,10,20,50,100'))), static fn(float $value): bool => $value > 0));
|
||||
if ($rewards_amounts === []) {
|
||||
$rewards_amounts = [5, 10, 20, 50, 100];
|
||||
}
|
||||
$rewards_min = max(0.01, round((float) ($settings['post_rewards_min'] ?? 1), 2));
|
||||
$rewards_max = max($rewards_min, round((float) ($settings['post_rewards_max'] ?? 1000), 2));
|
||||
$author_card_limit = max(0, min(12, (int) ($settings['post_author_card_limit'] ?? 6)));
|
||||
$author_card_orderby = sanitize_key((string) ($settings['post_author_card_orderby'] ?? 'views'));
|
||||
if (!in_array($author_card_orderby, ['views', 'date', 'modified', 'comment_count'], true)) {
|
||||
$author_card_orderby = 'views';
|
||||
}
|
||||
$author_card_style = sanitize_key((string) ($settings['post_author_card_style'] ?? 'card'));
|
||||
if (!in_array($author_card_style, ['card', 'list'], true)) {
|
||||
$author_card_style = 'card';
|
||||
}
|
||||
$maxheight_enabled = !empty($settings['article_maxheight_kg'])
|
||||
|| !empty($settings['post_article_maxheight_kg'])
|
||||
|| !empty($settings['post_maxheight_kg']);
|
||||
$maxheight = max(0, (int) ($settings['article_maxheight'] ?? $settings['post_article_maxheight'] ?? $settings['post_maxheight'] ?? 1000));
|
||||
if ($maxheight <= 0) {
|
||||
$maxheight = 1000;
|
||||
}
|
||||
|
||||
// Related: split Zibll display style (img/list/text) from query source (category/tag/random).
|
||||
// Legacy post_related_type held either style (img|list|text) or source (category|tag|random).
|
||||
$raw_related_type = sanitize_key((string) ($settings['post_related_type'] ?? ''));
|
||||
$raw_related_style = sanitize_key((string) ($settings['post_related_style'] ?? ''));
|
||||
$raw_related_source = sanitize_key((string) ($settings['post_related_source'] ?? ''));
|
||||
|
||||
$related_style = 'img';
|
||||
if (in_array($raw_related_style, ['img', 'list', 'text'], true)) {
|
||||
$related_style = $raw_related_style;
|
||||
} elseif (in_array($raw_related_type, ['img', 'list', 'text'], true)) {
|
||||
$related_style = $raw_related_type;
|
||||
}
|
||||
|
||||
$related_source = 'category';
|
||||
if (in_array($raw_related_source, ['category', 'tag', 'random'], true)) {
|
||||
$related_source = $raw_related_source;
|
||||
} elseif (in_array($raw_related_type, ['category', 'tag', 'random'], true)) {
|
||||
$related_source = $raw_related_type;
|
||||
}
|
||||
|
||||
$related_orderby = sanitize_key((string) ($settings['post_related_orderby'] ?? 'views'));
|
||||
if (!in_array($related_orderby, ['rand', 'relevance', 'date', 'views', 'modified'], true)) {
|
||||
$related_orderby = 'views';
|
||||
}
|
||||
|
||||
return [
|
||||
'toc_enabled' => !isset($settings['post_toc_enabled']) || !empty($settings['post_toc_enabled']),
|
||||
'toc_depth' => max(1, min(6, (int) ($settings['post_toc_depth'] ?? 3))),
|
||||
'article_nav_mobile_nav_s' => !isset($settings['article_nav_mobile_nav_s']) || !empty($settings['article_nav_mobile_nav_s']),
|
||||
'mobile_nav_s' => !isset($settings['article_nav_mobile_nav_s']) || !empty($settings['article_nav_mobile_nav_s']),
|
||||
'reading_progress' => !isset($settings['post_reading_progress']) || !empty($settings['post_reading_progress']),
|
||||
// Canonical + legacy breadcrumbs.
|
||||
'breadcrumbs' => $breadcrumbs,
|
||||
'breadcrumbs_home' => $breadcrumbs_home,
|
||||
'breadcrumbs_single_s' => $breadcrumbs,
|
||||
'breadcrumbs_home_text' => $breadcrumbs_home,
|
||||
'breadcrumbs_single_text' => $breadcrumbs_single_text,
|
||||
// Canonical + legacy prev/next / author / time.
|
||||
'prevnext' => $prevnext,
|
||||
'prevnext_s' => $prevnext,
|
||||
'authordesc' => $authordesc,
|
||||
'authordesc_s' => $authordesc,
|
||||
'hide_time' => $hide_time,
|
||||
'single_hide_time_s' => $hide_time,
|
||||
'article_image_cover' => !isset($settings['post_article_image_cover']) || !empty($settings['post_article_image_cover']),
|
||||
'article_image_cover_scale'=> max(10, min(100, (int) ($settings['post_article_image_cover_scale'] ?? 35))),
|
||||
'article_slide_cover' => !isset($settings['post_article_slide_cover']) || !empty($settings['post_article_slide_cover']),
|
||||
'article_video_cover' => !isset($settings['post_article_video_cover']) || !empty($settings['post_article_video_cover']),
|
||||
'article_video_cover_scale'=> max(20, min(100, (int) ($settings['post_article_video_cover_scale'] ?? 56))),
|
||||
'lightbox' => !isset($settings['post_lightbox']) || !empty($settings['post_lightbox']),
|
||||
'lightbox_thumbs' => !isset($settings['post_lightbox_thumbs']) || !empty($settings['post_lightbox_thumbs']),
|
||||
'lightbox_zoom' => !isset($settings['post_lightbox_zoom']) || !empty($settings['post_lightbox_zoom']),
|
||||
'lightbox_full' => !isset($settings['post_lightbox_full']) || !empty($settings['post_lightbox_full']),
|
||||
'lightbox_down' => !empty($settings['post_lightbox_down']),
|
||||
'lightbox_play' => !empty($settings['post_lightbox_play']),
|
||||
'related_enabled' => !isset($settings['post_related_enabled']) || !empty($settings['post_related_enabled']),
|
||||
'related_count' => max(1, min(20, (int) ($settings['post_related_count'] ?? 6))),
|
||||
// Display style (Zibll img/list/text) + query source (category/tag/random).
|
||||
'related_style' => $related_style,
|
||||
'related_source' => $related_source,
|
||||
// Legacy alias: older code treated related_type as source.
|
||||
'related_type' => $related_source,
|
||||
'related_orderby' => $related_orderby,
|
||||
'related_title' => sanitize_text_field((string) ($settings['post_related_title'] ?? '相关推荐')),
|
||||
'like_enabled' => !isset($settings['post_like_enabled']) || !empty($settings['post_like_enabled']),
|
||||
'favorite_enabled' => !isset($settings['post_favorite_enabled']) || !empty($settings['post_favorite_enabled']),
|
||||
// Canonical + legacy share.
|
||||
'share_enabled' => $share_enabled,
|
||||
'share_s' => $share_enabled,
|
||||
// Author card posts (Zibll user_card_box defaults).
|
||||
'author_card_limit' => $author_card_limit,
|
||||
'author_card_orderby' => $author_card_orderby,
|
||||
'author_card_style' => $author_card_style,
|
||||
// On-site wallet tipping.
|
||||
'rewards_enabled' => $rewards_enabled,
|
||||
'post_rewards_s' => $rewards_enabled,
|
||||
'rewards_text' => $rewards_text,
|
||||
'rewards_btn_text' => $rewards_text,
|
||||
'rewards_amounts' => $rewards_amounts,
|
||||
'rewards_custom' => !isset($settings['post_rewards_custom']) || !empty($settings['post_rewards_custom']),
|
||||
'rewards_min' => $rewards_min,
|
||||
'rewards_max' => $rewards_max,
|
||||
// Content max height (Zibll article_maxheight_kg / article_maxheight).
|
||||
'maxheight_enabled' => $maxheight_enabled,
|
||||
'maxheight' => $maxheight,
|
||||
'copyright_enabled' => !isset($settings['post_copyright_enabled']) || !empty($settings['post_copyright_enabled']),
|
||||
'copyright_text' => (string) ($settings['post_copyright_text'] ?? ''),
|
||||
'button_toptext' => sanitize_text_field((string) ($settings['post_button_toptext'] ?? '喜欢就支持一下吧')),
|
||||
'front_content' => (string) ($settings['post_front_content'] ?? ''),
|
||||
'after_content' => (string) ($settings['post_after_content'] ?? ''),
|
||||
'yiyan_header' => !empty($settings['post_yiyan_header']),
|
||||
'yiyan_footer' => !empty($settings['post_yiyan_footer']),
|
||||
'yiyan_box' => !empty($settings['post_yiyan_box']),
|
||||
'default_views_min' => max(0, min(9999, (int) ($settings['post_default_views_min'] ?? 20))),
|
||||
'default_views_max' => max(1, min(9999, (int) ($settings['post_default_views_max'] ?? 50))),
|
||||
'default_likes_min' => max(0, min(9999, (int) ($settings['post_default_likes_min'] ?? 5))),
|
||||
'default_likes_max' => max(1, min(9999, (int) ($settings['post_default_likes_max'] ?? 15))),
|
||||
'word_count_enabled' => !isset($settings['post_word_count_enabled']) || !empty($settings['post_word_count_enabled']),
|
||||
'reading_time_enabled' => !isset($settings['post_reading_time_enabled']) || !empty($settings['post_reading_time_enabled']),
|
||||
'print_enabled' => !isset($settings['feature_print']) || !empty($settings['feature_print']),
|
||||
'pdf_export_enabled' => !empty($settings['feature_pdf_export']),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_share_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
return [
|
||||
'enabled' => !isset($settings['share_s']) || !empty($settings['share_s']),
|
||||
'wechat_appid' => sanitize_text_field((string) ($settings['wechat_share_appid'] ?? '')),
|
||||
'wechat_timestamp' => sanitize_text_field((string) ($settings['wechat_share_timestamp'] ?? '')),
|
||||
'wechat_nonce' => sanitize_text_field((string) ($settings['wechat_share_nonce'] ?? '')),
|
||||
'wechat_signature' => sanitize_text_field((string) ($settings['wechat_share_signature'] ?? '')),
|
||||
'poster_enabled' => !empty($settings['post_share_poster_s']),
|
||||
'poster_qr_enabled' => !empty($settings['post_share_poster_qr_s']),
|
||||
'poster_bg' => (string) ($settings['post_share_poster_bg'] ?? ''),
|
||||
'social_items' => is_array($settings['social_share_items'] ?? null) ? $settings['social_share_items'] : [],
|
||||
'copy_link_enabled' => !isset($settings['post_share_copylink_s']) || !empty($settings['post_share_copylink_s']),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_submit_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
$title_min = max(1, min(100, (int) ($settings['post_article_title_strlen_limit_min'] ?? 5)));
|
||||
$title_max = max(5, min(200, (int) ($settings['post_article_title_strlen_limit_max'] ?? 30)));
|
||||
if ($title_max < $title_min) {
|
||||
$title_max = $title_min;
|
||||
}
|
||||
|
||||
$review_mode = sanitize_key((string) ($settings['front_submit_review_mode'] ?? 'pending'));
|
||||
if (!in_array($review_mode, ['pending', 'publish', 'draft'], true)) {
|
||||
$review_mode = 'pending';
|
||||
}
|
||||
|
||||
$editor_mode = sanitize_key((string) ($settings['front_submit_editor_mode'] ?? 'rich'));
|
||||
if (!in_array($editor_mode, ['rich', 'markdown', 'plain'], true)) {
|
||||
$editor_mode = 'rich';
|
||||
}
|
||||
|
||||
return [
|
||||
'enabled' => !isset($settings['front_submit_enabled']) || !empty($settings['front_submit_enabled']),
|
||||
'btn_text' => sanitize_text_field((string) ($settings['post_article_btn_txte'] ?? '')) ?: __('发布文章', 'aksrt'),
|
||||
'title_min' => $title_min,
|
||||
'title_max' => $title_max,
|
||||
'title_placeholder' => sanitize_text_field((string) ($settings['post_t_placeholder'] ?? '')) ?: __('请输入标题', 'aksrt'),
|
||||
'content_placeholder' => sanitize_textarea_field((string) ($settings['post_c_placeholder'] ?? '')) ?: __('请输入内容', 'aksrt'),
|
||||
'allowed_cat_ids' => is_array($settings['post_article_cat'] ?? null) ? array_values(array_filter(array_map('intval', $settings['post_article_cat']))) : [],
|
||||
'default_user_id' => max(0, (int) ($settings['post_article_user'] ?? 0)),
|
||||
'guest_enabled' => !empty($settings['front_submit_guest_enabled']),
|
||||
'allow_title' => !isset($settings['front_submit_title']) || !empty($settings['front_submit_title']),
|
||||
'allow_content' => !isset($settings['front_submit_content']) || !empty($settings['front_submit_content']),
|
||||
'allow_excerpt' => !isset($settings['front_submit_excerpt']) || !empty($settings['front_submit_excerpt']),
|
||||
'allow_cover' => !isset($settings['front_submit_cover']) || !empty($settings['front_submit_cover']),
|
||||
'allow_category' => !isset($settings['front_submit_category']) || !empty($settings['front_submit_category']),
|
||||
'allow_tags' => !isset($settings['front_submit_tags']) || !empty($settings['front_submit_tags']),
|
||||
'tags_s' => !isset($settings['front_submit_tags']) || !empty($settings['front_submit_tags']),
|
||||
'cover_required' => !empty($settings['front_submit_cover_required']),
|
||||
'max_images' => max(0, min(50, (int) ($settings['front_submit_max_images'] ?? 5))),
|
||||
'review_mode' => $review_mode,
|
||||
'editor_mode' => $editor_mode,
|
||||
'draft_save' => !isset($settings['front_submit_draft_save']) || !empty($settings['front_submit_draft_save']),
|
||||
'leave_warning' => !isset($settings['front_submit_leave_warning']) || !empty($settings['front_submit_leave_warning']),
|
||||
'captcha' => !empty($settings['front_submit_captcha']) || !empty($settings['verification_newposts_s']),
|
||||
'pay_free_s' => !isset($settings['post_article_pay_free_s']) || !empty($settings['post_article_pay_free_s']),
|
||||
'pay_price_min' => max(0, (float) ($settings['post_article_pay_price_min'] ?? 0)),
|
||||
'pay_price_max' => max(0, (float) ($settings['post_article_pay_price_max'] ?? 100)),
|
||||
'pay_vip_price_s' => !isset($settings['post_article_pay_vip_price_s']) || !empty($settings['post_article_pay_vip_price_s']),
|
||||
'pay_vip_1_discount' => max(0, min(100, (int) ($settings['post_article_pay_vip_1_discount'] ?? 80))),
|
||||
'pay_vip_2_discount' => max(0, min(100, (int) ($settings['post_article_pay_vip_2_discount'] ?? 50))),
|
||||
'topics_s' => !empty($settings['post_article_topics_s']),
|
||||
'custom_filter_s' => !isset($settings['post_article_custom_filter_s']) || !empty($settings['post_article_custom_filter_s']),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_comment_display_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$order = sanitize_key((string) ($settings['comment_order'] ?? 'desc'));
|
||||
if (!in_array($order, ['asc', 'desc'], true)) {
|
||||
$order = 'desc';
|
||||
}
|
||||
|
||||
$empty_text = trim((string) ($settings['comment_empty_text'] ?? ''));
|
||||
$submit_text = trim((string) ($settings['comment_submit_text'] ?? ''));
|
||||
$box_placeholder = trim((string) ($settings['comment_text'] ?? ''));
|
||||
$title = trim((string) ($settings['comment_title'] ?? ''));
|
||||
|
||||
return [
|
||||
'order' => $order,
|
||||
'pagination_mode' => self::get_comment_pagination_mode(),
|
||||
'paging_ajax_ias' => !isset($settings['comment_paging_ajax_ias_s']) || !empty($settings['comment_paging_ajax_ias_s']),
|
||||
'paging_ajax_ias_max'=> max(0, min(10, (int) ($settings['comment_paging_ajax_ias_max'] ?? 3))),
|
||||
'per_page' => max(5, min(100, (int) ($settings['comment_per_page'] ?? 20))),
|
||||
'nested_depth' => max(1, min(10, (int) ($settings['comment_nested_depth'] ?? 3))),
|
||||
'require_login' => Settings::comment_requires_registration(),
|
||||
'allow_reply' => !isset($settings['comment_allow_reply']) || !empty($settings['comment_allow_reply']),
|
||||
'avatar_size' => max(24, min(96, (int) ($settings['comment_avatar_size'] ?? 48))),
|
||||
'empty_text' => $empty_text !== '' ? $empty_text : __('暂无评论,来做第一个评论的人吧~', 'aksrt'),
|
||||
'toolbar' => [
|
||||
'smilie' => !isset($settings['comment_smilie']) || !empty($settings['comment_smilie']),
|
||||
'code' => !isset($settings['comment_code']) || !empty($settings['comment_code']),
|
||||
'image' => !isset($settings['comment_img']) || !empty($settings['comment_img']),
|
||||
'upload_img' => !empty($settings['comment_upload_img']),
|
||||
],
|
||||
'like_enabled' => !isset($settings['comment_like_s']) || !empty($settings['comment_like_s']),
|
||||
'author_tag' => !isset($settings['comment_author_tag']) || !empty($settings['comment_author_tag']),
|
||||
'corderby' => !isset($settings['comment_corderby']) || !empty($settings['comment_corderby']),
|
||||
'edit_window' => max(0, min(1440, (int) ($settings['comment_edit_window'] ?? 10))),
|
||||
'submit_text' => $submit_text !== '' ? $submit_text : __('提交评论', 'aksrt'),
|
||||
'box_placeholder' => $box_placeholder !== '' ? $box_placeholder : __('说点什么吧...', 'aksrt'),
|
||||
'title' => $title !== '' ? $title : __('评论', 'aksrt'),
|
||||
// Extended zibll-parity settings.
|
||||
'close_comments' => !empty($settings['comment_close_comments']),
|
||||
'hot_threshold' => max(1, min(999, (int) ($settings['comment_hot_threshold'] ?? 10))),
|
||||
'quick_s' => !isset($settings['comment_quick_s']) || !empty($settings['comment_quick_s']),
|
||||
'quick_phrases' => self::parse_comment_quick_phrases((string) ($settings['comment_quick_often'] ?? '')),
|
||||
'city_s' => !isset($settings['comment_city_s']) || !empty($settings['comment_city_s']),
|
||||
'city_type' => self::normalize_comment_city_type((string) ($settings['comment_city_type'] ?? 'province_city')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,string>
|
||||
*/
|
||||
private static function parse_comment_quick_phrases(string $raw): array {
|
||||
if (trim($raw) === '') {
|
||||
$raw = "不错,学习了\n感谢分享\n期待更新";
|
||||
}
|
||||
$lines = preg_split('/\r\n|\r|\n/', $raw) ?: [];
|
||||
$out = [];
|
||||
foreach ($lines as $line) {
|
||||
$line = trim((string) $line);
|
||||
if ($line !== '') {
|
||||
$out[] = $line;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($out));
|
||||
}
|
||||
|
||||
private static function normalize_comment_city_type(string $type): string {
|
||||
$type = sanitize_key($type);
|
||||
// Map legacy zibll pro/city labels.
|
||||
if ($type === 'pro') {
|
||||
return 'province';
|
||||
}
|
||||
if ($type === 'city') {
|
||||
return 'province_city';
|
||||
}
|
||||
return in_array($type, ['province_city', 'province', 'country_province'], true)
|
||||
? $type
|
||||
: 'province_city';
|
||||
}
|
||||
|
||||
|
||||
public static function apply_list_orderby($query): void {
|
||||
if (is_admin() || !($query instanceof \WP_Query) || !$query->is_main_query()) {
|
||||
return;
|
||||
}
|
||||
if (!$query->is_home() && !$query->is_archive() && !$query->is_search()) {
|
||||
return;
|
||||
}
|
||||
if ($query->get('orderby')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$orderby = sanitize_key((string) (self::get_post_list_style_settings()['list_orderby'] ?? 'modified'));
|
||||
if ($orderby === '' || $orderby === 'default') {
|
||||
return;
|
||||
}
|
||||
if (in_array($orderby, ['date', 'modified'], true)) {
|
||||
$query->set('orderby', $orderby);
|
||||
$query->set('order', 'DESC');
|
||||
}
|
||||
}
|
||||
|
||||
public static function apply_list_per_page($query): void {
|
||||
if (is_admin() || !$query->is_main_query()) {
|
||||
return;
|
||||
}
|
||||
if (!$query->is_archive() && !$query->is_search() && !$query->is_home()) {
|
||||
return;
|
||||
}
|
||||
$s = Settings::get_all();
|
||||
$per_page = max(4, min(48, (int) ($s['post_list_per_page'] ?? 12)));
|
||||
if ($per_page !== 12) {
|
||||
$query->set('posts_per_page', $per_page);
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_archive_layout(): string {
|
||||
$settings = self::get_post_list_style_settings();
|
||||
return $settings['render_mode'];
|
||||
}
|
||||
|
||||
public static function get_post_pagination_mode(): string {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
// Zibll: paging_ajax_s '1' = ajax append, '0' = numeric buttons.
|
||||
if (array_key_exists('paging_ajax_s', $settings)) {
|
||||
$ajax = self::is_list_paging_ajax($settings);
|
||||
if (!$ajax) {
|
||||
return 'numbered';
|
||||
}
|
||||
return self::is_list_paging_ajax_ias($settings) ? 'infinite' : 'load_more';
|
||||
}
|
||||
|
||||
// Temporary bridge for installs still holding the previous schema key only.
|
||||
$mode = (string) ($settings['post_pagination_mode'] ?? 'numbered');
|
||||
if ($mode === 'numeric') {
|
||||
$mode = 'numbered';
|
||||
}
|
||||
return in_array($mode, ['numbered', 'load_more', 'infinite'], true) ? $mode : 'numbered';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether list pagination uses AJAX append (Zibll paging_ajax_s).
|
||||
*
|
||||
* @param array<string,mixed>|null $settings
|
||||
*/
|
||||
public static function is_list_paging_ajax(?array $settings = null): bool {
|
||||
$settings = $settings ?? Settings::get_all();
|
||||
if (!array_key_exists('paging_ajax_s', $settings)) {
|
||||
// Fallback from previous 3-mode key.
|
||||
$mode = (string) ($settings['post_pagination_mode'] ?? 'numbered');
|
||||
return in_array($mode, ['load_more', 'infinite', 'ajax'], true);
|
||||
}
|
||||
$raw = $settings['paging_ajax_s'];
|
||||
if (is_bool($raw)) {
|
||||
return $raw;
|
||||
}
|
||||
return (string) $raw === '1' || (string) $raw === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether AJAX list paging auto-loads on scroll (Zibll paging_ajax_ias_s).
|
||||
*
|
||||
* @param array<string,mixed>|null $settings
|
||||
*/
|
||||
public static function is_list_paging_ajax_ias(?array $settings = null): bool {
|
||||
$settings = $settings ?? Settings::get_all();
|
||||
if (!self::is_list_paging_ajax($settings)) {
|
||||
return false;
|
||||
}
|
||||
if (!array_key_exists('paging_ajax_ias_s', $settings)) {
|
||||
$mode = (string) ($settings['post_pagination_mode'] ?? '');
|
||||
return $mode === 'infinite';
|
||||
}
|
||||
return !empty($settings['paging_ajax_ias_s']);
|
||||
}
|
||||
|
||||
public static function get_comment_pagination_mode(): string {
|
||||
$mode = (string) Settings::get_value('comment_pagination_type', 'numbered');
|
||||
if ($mode === 'page') {
|
||||
$mode = 'numbered';
|
||||
}
|
||||
return in_array($mode, ['numbered', 'load_more', 'infinite'], true) ? $mode : 'numbered';
|
||||
}
|
||||
|
||||
private static function sanitize_custom_filter_defs($raw): array {
|
||||
if (!is_array($raw)) {
|
||||
return [];
|
||||
}
|
||||
$result = [];
|
||||
foreach ($raw as $item) {
|
||||
if (!is_array($item)) continue;
|
||||
$name = sanitize_text_field((string) ($item['name'] ?? ''));
|
||||
$key = sanitize_key((string) ($item['key'] ?? ''));
|
||||
if ($name === '' || $key === '') continue;
|
||||
$vals = [];
|
||||
foreach ((array) ($item['vals'] ?? []) as $val) {
|
||||
if (!is_array($val)) continue;
|
||||
$vkey = sanitize_key((string) ($val['key'] ?? ''));
|
||||
$vname = sanitize_text_field((string) ($val['name'] ?? ''));
|
||||
if ($vkey === '' || $vname === '') continue;
|
||||
$vals[] = ['key' => $vkey, 'name' => $vname];
|
||||
}
|
||||
$result[] = ['name' => $name, 'key' => $key, 'vals' => $vals];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function sanitize_cat_custom_filter($raw): array {
|
||||
if (!is_array($raw)) {
|
||||
return [];
|
||||
}
|
||||
$result = [];
|
||||
foreach ($raw as $item) {
|
||||
if (!is_array($item)) continue;
|
||||
$cats = is_array($item['cats'] ?? null) ? array_values(array_filter(array_map('absint', $item['cats']), static fn($id) => $id > 0)) : [];
|
||||
if (empty($cats)) continue;
|
||||
$filters_raw = trim((string) ($item['custom_filters'] ?? ''));
|
||||
$filters = $filters_raw === '' ? [] : array_values(array_filter(array_map('sanitize_key', preg_split('/[,,\s]+/', $filters_raw) ?: [])));
|
||||
$result[] = [
|
||||
'cats' => $cats,
|
||||
'cat_s' => !isset($item['cat_s']) || !empty($item['cat_s']),
|
||||
'tag_s' => !empty($item['tag_s']),
|
||||
'topics_s' => !empty($item['topics_s']),
|
||||
'orderby_s' => !isset($item['orderby_s']) || !empty($item['orderby_s']),
|
||||
'custom_filters' => $filters,
|
||||
];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,515 @@
|
||||
<?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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Settings;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class UserRuntime {
|
||||
|
||||
/**
|
||||
* Public user-home display settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_user_home_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$allowed_tabs = ['posts', 'comments', 'favorites', 'credits', 'follow'];
|
||||
|
||||
$parse_csv = function (string $key, string $fallback) use ($settings, $allowed_tabs): array {
|
||||
$raw = $settings[$key] ?? $fallback;
|
||||
$items = is_array($raw) ? $raw : preg_split('/[\s,]+/', (string) $raw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$clean = [];
|
||||
foreach ((array) $items as $v) {
|
||||
$v = sanitize_key((string) $v);
|
||||
if (in_array($v, $allowed_tabs, true) && !in_array($v, $clean, true)) {
|
||||
$clean[] = $v;
|
||||
}
|
||||
}
|
||||
return $clean;
|
||||
};
|
||||
|
||||
// Zibll author_main_tab_opt defaults: post, favorite, comment, plate, forum, follow.
|
||||
$normalized_tabs = $parse_csv('user_home_tabs', 'posts,favorites,comments,follow');
|
||||
if (empty($normalized_tabs)) {
|
||||
$normalized_tabs = ['posts', 'favorites', 'comments', 'follow'];
|
||||
}
|
||||
|
||||
$raw_order = $parse_csv('user_home_tabs_order', '');
|
||||
$ordered = [];
|
||||
foreach ($raw_order as $tab) {
|
||||
if (in_array($tab, $normalized_tabs, true)) {
|
||||
$ordered[] = $tab;
|
||||
}
|
||||
}
|
||||
foreach ($normalized_tabs as $tab) {
|
||||
if (!in_array($tab, $ordered, true)) {
|
||||
$ordered[] = $tab;
|
||||
}
|
||||
}
|
||||
|
||||
$pc_hide = $parse_csv('user_home_tabs_pc_hide', '');
|
||||
$mobile_hide = $parse_csv('user_home_tabs_mobile_hide', '');
|
||||
|
||||
return [
|
||||
'tabs' => $normalized_tabs,
|
||||
'tabs_order' => $ordered,
|
||||
'tabs_pc_hide' => $pc_hide,
|
||||
'tabs_mobile_hide' => $mobile_hide,
|
||||
// Public author page is full-width (Zibll author.php). Sidebar option kept as no-op reserved key.
|
||||
'sidebar' => false,
|
||||
'cover' => !isset($settings['user_home_cover']) || !empty($settings['user_home_cover']),
|
||||
'follow' => !isset($settings['user_home_follow']) || !empty($settings['user_home_follow']),
|
||||
'posts_per_page' => max(5, min(50, (int) ($settings['user_home_posts_per_page'] ?? 10))),
|
||||
'avatar' => !isset($settings['user_home_avatar']) || !empty($settings['user_home_avatar']),
|
||||
'name' => !isset($settings['user_home_name']) || !empty($settings['user_home_name']),
|
||||
'desc' => !isset($settings['user_home_desc']) || !empty($settings['user_home_desc']),
|
||||
// Body stats row removed; counts live in tabs like Zibll.
|
||||
'stats' => false,
|
||||
'social' => !isset($settings['user_home_social']) || !empty($settings['user_home_social']),
|
||||
'tab_swiper' => !empty($settings['author_main_tab_swiper']),
|
||||
'message' => !isset($settings['user_home_message']) || !empty($settings['user_home_message']),
|
||||
'private' => !isset($settings['user_home_private']) || !empty($settings['user_home_private']),
|
||||
'paging_ajax' => !isset($settings['user_home_paging_ajax']) || !empty($settings['user_home_paging_ajax']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
$settings = Settings::get_all();
|
||||
$raw_tabs = $settings['user_center_tabs'] ?? 'profile,level,posts,comments,credits,favorites,auth';
|
||||
$tabs = is_array($raw_tabs)
|
||||
? $raw_tabs
|
||||
: preg_split('/[\s,]+/', (string) $raw_tabs, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
// Built-in switchable panels. VIP is always auto-injected when enabled
|
||||
// by AKSRT\User\Center — keep it allowed for explicit config too.
|
||||
$allowed_tabs = ['profile', 'level', 'posts', 'comments', 'favorites', 'credits', 'vip', 'orders', 'auth', 'settings'];
|
||||
$normalized_tabs = ['profile'];
|
||||
|
||||
foreach ((array) $tabs as $tab) {
|
||||
$tab = sanitize_key((string) $tab);
|
||||
if ($tab === 'profile') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($tab, $allowed_tabs, true) && !in_array($tab, $normalized_tabs, true)) {
|
||||
$normalized_tabs[] = $tab;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_array('posts', $normalized_tabs, true) && !in_array('comments', $normalized_tabs, true)) {
|
||||
$normalized_tabs[] = 'posts';
|
||||
}
|
||||
|
||||
// Ensure VIP appears in configured tabs when membership is on, even if
|
||||
// the stored option string is older and omits it.
|
||||
$vip_on = !empty(Settings::get_payment_vip_settings()['enabled']);
|
||||
if ($vip_on && !in_array('vip', $normalized_tabs, true)) {
|
||||
// Prefer after credits, else after favorites, else append before settings.
|
||||
$insert_at = count($normalized_tabs);
|
||||
foreach (['credits', 'favorites', 'posts'] as $anchor) {
|
||||
$idx = array_search($anchor, $normalized_tabs, true);
|
||||
if ($idx !== false) {
|
||||
$insert_at = (int) $idx + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
array_splice($normalized_tabs, $insert_at, 0, ['vip']);
|
||||
}
|
||||
if (!$vip_on) {
|
||||
$normalized_tabs = array_values(array_filter(
|
||||
$normalized_tabs,
|
||||
static fn(string $t): bool => $t !== 'vip'
|
||||
));
|
||||
}
|
||||
|
||||
return [
|
||||
'tabs' => $normalized_tabs,
|
||||
'avatar_upload' => !isset($settings['allow_avatar_upload']) || !empty($settings['allow_avatar_upload']),
|
||||
'cover_upload' => !isset($settings['user_cover_upload']) || !empty($settings['user_cover_upload']),
|
||||
'social_links' => !isset($settings['user_social_links']) || !empty($settings['user_social_links']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* User identity, level, medal, and report governance settings.
|
||||
*
|
||||
* @return array{
|
||||
* verify:array{enabled:bool,public_display:bool,allow_apply:bool,disable_desc:string,desc:string,types:array<string,array{slug:string,label:string,badge_text:string,fee:float,free_applications:int,require_real_name:bool}>},
|
||||
* level:array{enabled:bool,public_display:bool,source:string,label_prefix:string,thresholds:array<int,int>},
|
||||
* medal:array{enabled:bool,public_display:bool,limit:int,categories:array<int,array{cat_name:string,items:array<int,array{slug:string,name:string,desc:string,icon:string,get_type:string,get_val:int}>}>,items_by_slug:array<string,array{slug:string,name:string,desc:string,icon:string,get_type:string,get_val:int,cat_name:string}>},
|
||||
* badge:array{enabled:bool,public_display:bool,limit:int,dictionary:array<int,array{slug:string,label:string,tone:string,icon_url?: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 {
|
||||
$settings = Settings::get_all();
|
||||
$ban_notice_text = trim((string) ($settings['user_report_ban_notice_text'] ?? ''));
|
||||
$verify_types = [
|
||||
'personal' => [
|
||||
'slug' => 'personal',
|
||||
'label' => __('个人认证', 'aksrt'),
|
||||
'badge_text' => trim((string) ($settings['user_verify_personal_badge_text'] ?? '')) ?: __('个人认证', 'aksrt'),
|
||||
'fee' => max(0, round((float) ($settings['user_verify_personal_fee'] ?? 0), 2)),
|
||||
'free_applications' => max(0, (int) ($settings['user_verify_personal_free_applications'] ?? 0)),
|
||||
'require_real_name' => true,
|
||||
],
|
||||
'enterprise' => [
|
||||
'slug' => 'enterprise',
|
||||
'label' => __('企业认证', 'aksrt'),
|
||||
'badge_text' => trim((string) ($settings['user_verify_enterprise_badge_text'] ?? '')) ?: __('企业认证', 'aksrt'),
|
||||
'fee' => max(0, round((float) ($settings['user_verify_enterprise_fee'] ?? 0), 2)),
|
||||
'free_applications' => max(0, (int) ($settings['user_verify_enterprise_free_applications'] ?? 0)),
|
||||
'require_real_name' => true,
|
||||
],
|
||||
];
|
||||
$medal = self::parse_medal_catalog($settings);
|
||||
$provider = sanitize_key((string) ($settings['user_verify_provider'] ?? 'aliyun'));
|
||||
if (!in_array($provider, ['aliyun', 'tencent'], true)) {
|
||||
$provider = 'aliyun';
|
||||
}
|
||||
|
||||
return [
|
||||
'verify' => [
|
||||
'enabled' => !isset($settings['user_verify_enabled']) || !empty($settings['user_verify_enabled']),
|
||||
'public_display' => !isset($settings['user_verify_public_display']) || !empty($settings['user_verify_public_display']),
|
||||
'allow_apply' => !isset($settings['user_verify_allow_apply']) || !empty($settings['user_verify_allow_apply']),
|
||||
'disable_desc' => (string) ($settings['user_verify_disable_desc'] ?? ''),
|
||||
'desc' => (string) ($settings['user_verify_desc'] ?? ''),
|
||||
'provider' => $provider,
|
||||
'allow_manual_fallback' => !isset($settings['user_verify_allow_manual_fallback']) || !empty($settings['user_verify_allow_manual_fallback']),
|
||||
'poll_interval_seconds' => max(3, min(60, (int) ($settings['user_verify_poll_interval_seconds'] ?? 5))),
|
||||
'types' => $verify_types,
|
||||
],
|
||||
'level' => [
|
||||
'enabled' => !isset($settings['user_level_s']) || !empty($settings['user_level_s']),
|
||||
'public_display' => !isset($settings['user_level_public_display']) || !empty($settings['user_level_public_display']),
|
||||
'max' => max(3, min(30, (int) ($settings['user_level_max'] ?? 10))),
|
||||
],
|
||||
'medal' => $medal,
|
||||
// Alias for existing call sites that still read badge.*; dictionary is derived from medal catalog.
|
||||
'badge' => [
|
||||
'enabled' => $medal['enabled'],
|
||||
'public_display' => $medal['public_display'],
|
||||
'limit' => $medal['limit'],
|
||||
'dictionary' => array_values(array_map(static function (array $item): array {
|
||||
return [
|
||||
'slug' => $item['slug'],
|
||||
'label' => $item['name'],
|
||||
'tone' => 'info',
|
||||
'icon_url' => $item['icon'],
|
||||
];
|
||||
}, $medal['items_by_slug'])),
|
||||
],
|
||||
'report' => [
|
||||
'enabled' => !empty($settings['user_report_enabled']),
|
||||
'public_entry' => !isset($settings['user_report_public_entry']) || !empty($settings['user_report_public_entry']),
|
||||
'public_notice' => !isset($settings['user_report_public_notice']) || !empty($settings['user_report_public_notice']),
|
||||
'ban_notice_text' => $ban_notice_text !== '' ? $ban_notice_text : __('当前账号处于限制状态,部分互动能力已关闭。', 'aksrt'),
|
||||
'categories' => self::parse_report_categories((string) ($settings['user_report_categories'] ?? "spam|垃圾信息\nabuse|人身攻击\ncopyright|版权投诉")),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁封设置
|
||||
*/
|
||||
public static function ban_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$reasons_raw = (string) ($settings['ban_preset_reason'] ?? "spam|垃圾信息\nabuse|人身攻击\nviolation|违规操作");
|
||||
$reasons = [];
|
||||
foreach (preg_split('/\r\n|\r|\n/', $reasons_raw) as $line) {
|
||||
$line = trim($line);
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
$parts = explode('|', $line, 2);
|
||||
$reasons[] = [
|
||||
'slug' => sanitize_key($parts[0]),
|
||||
'name' => sanitize_text_field($parts[1] ?? $parts[0]),
|
||||
];
|
||||
}
|
||||
$appeal_keys_raw = (string) ($settings['ban_appeal_keys'] ?? '');
|
||||
$appeal_keys = array_filter(array_map('trim', explode(',', $appeal_keys_raw)));
|
||||
|
||||
return [
|
||||
'reasons' => $reasons,
|
||||
'appeal_desc' => wp_kses_post((string) ($settings['ban_appeal_desc'] ?? '')),
|
||||
'appeal_keys' => array_values($appeal_keys),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 举报设置
|
||||
*/
|
||||
public static function report_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
return [
|
||||
'enabled' => !empty($settings['user_report_enabled']),
|
||||
'public_entry' => !empty($settings['user_report_public_entry']),
|
||||
'public_notice' => !empty($settings['user_report_public_notice']),
|
||||
'ban_notice_text' => sanitize_text_field((string) ($settings['user_report_ban_notice_text'] ?? '')),
|
||||
'img_enabled' => !empty($settings['user_report_img_s']),
|
||||
'desc' => wp_kses_post((string) ($settings['user_report_desc'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse structured user_medal_args catalog (rewrite; no badge dictionary dual-read).
|
||||
*
|
||||
* @param array<string,mixed> $settings
|
||||
* @return array{enabled:bool,public_display:bool,limit:int,categories:array,items_by_slug:array}
|
||||
*/
|
||||
public static function parse_medal_catalog(array $settings): array {
|
||||
$enabled = !empty($settings['user_medal_s']);
|
||||
$public = !isset($settings['user_medal_public_display']) || !empty($settings['user_medal_public_display']);
|
||||
$limit = max(1, min(8, (int) ($settings['user_medal_limit'] ?? 3)));
|
||||
|
||||
$allowed_types = [
|
||||
'registration_time',
|
||||
'checkin_all_day',
|
||||
'new_post',
|
||||
'comment',
|
||||
'followed',
|
||||
'like',
|
||||
'comment_like',
|
||||
'views',
|
||||
'pay_income',
|
||||
'pay_rebate',
|
||||
'manually_add',
|
||||
];
|
||||
|
||||
$raw = $settings['user_medal_args'] ?? null;
|
||||
if (is_string($raw) && $raw !== '') {
|
||||
$decoded = json_decode($raw, true);
|
||||
$raw = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
if (!is_array($raw)) {
|
||||
$raw = [];
|
||||
}
|
||||
|
||||
$categories = [];
|
||||
$items_by_slug = [];
|
||||
|
||||
foreach ($raw as $cat) {
|
||||
if (!is_array($cat)) {
|
||||
continue;
|
||||
}
|
||||
$cat_name = sanitize_text_field((string) ($cat['cat_name'] ?? $cat['name'] ?? ''));
|
||||
if ($cat_name === '') {
|
||||
$cat_name = __('未命名', 'aksrt');
|
||||
}
|
||||
$items_out = [];
|
||||
$items = is_array($cat['items'] ?? null) ? $cat['items'] : [];
|
||||
foreach ($items as $item) {
|
||||
if (!is_array($item)) {
|
||||
continue;
|
||||
}
|
||||
$slug = sanitize_key((string) ($item['slug'] ?? ''));
|
||||
$name = sanitize_text_field((string) ($item['name'] ?? ''));
|
||||
if ($slug === '' || $name === '') {
|
||||
continue;
|
||||
}
|
||||
$get_type = sanitize_key((string) ($item['get_type'] ?? 'manually_add'));
|
||||
if (!in_array($get_type, $allowed_types, true)) {
|
||||
$get_type = 'manually_add';
|
||||
}
|
||||
$icon = esc_url_raw((string) ($item['icon'] ?? $item['icon_url'] ?? ''));
|
||||
$row = [
|
||||
'slug' => $slug,
|
||||
'name' => $name,
|
||||
'desc' => sanitize_text_field((string) ($item['desc'] ?? '')),
|
||||
'icon' => $icon,
|
||||
'get_type' => $get_type,
|
||||
'get_val' => max(0, (int) ($item['get_val'] ?? 0)),
|
||||
'cat_name' => $cat_name,
|
||||
];
|
||||
$items_out[] = $row;
|
||||
$items_by_slug[$slug] = $row;
|
||||
}
|
||||
$categories[] = [
|
||||
'cat_name' => $cat_name,
|
||||
'items' => $items_out,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'enabled' => $enabled,
|
||||
'public_display' => $public,
|
||||
'limit' => $limit,
|
||||
'categories' => $categories,
|
||||
'items_by_slug' => $items_by_slug,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,int>
|
||||
*/
|
||||
public static function parse_level_thresholds(string $raw): array {
|
||||
$lines = preg_split('/[\r\n]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$thresholds = [];
|
||||
|
||||
foreach ((array) $lines as $line) {
|
||||
$parts = preg_split('/[|:,]/', trim($line), 2);
|
||||
if (!is_array($parts) || count($parts) < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$level = (int) trim((string) $parts[0]);
|
||||
$value = (int) trim((string) $parts[1]);
|
||||
if ($level <= 0 || $value < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$thresholds[$level] = $value;
|
||||
}
|
||||
|
||||
if (empty($thresholds)) {
|
||||
$thresholds = [1 => 0, 2 => 30, 3 => 100, 4 => 300];
|
||||
}
|
||||
|
||||
ksort($thresholds, SORT_NUMERIC);
|
||||
return $thresholds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Removed — medal catalog is structured user_medal_args. Method kept empty stub intentionally deleted.
|
||||
* @return array<int,array{slug:string,label:string,tone:string,icon_url:string}>
|
||||
*/
|
||||
public static function parse_badge_dictionary(string $raw): array {
|
||||
// Rewrite policy: no dual-read of pipe dictionary. Callers must use parse_medal_catalog / get_user_identity_settings()['medal'].
|
||||
unset($raw);
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,array{slug:string,label:string}>
|
||||
*/
|
||||
public static function parse_report_categories(string $raw): array {
|
||||
$lines = preg_split('/[\r\n]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$items = [];
|
||||
|
||||
foreach ((array) $lines as $line) {
|
||||
$parts = array_map('trim', explode('|', (string) $line));
|
||||
if (count($parts) < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$slug = sanitize_key((string) $parts[0]);
|
||||
$label = sanitize_text_field((string) $parts[1]);
|
||||
if ($slug === '' || $label === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'slug' => $slug,
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user