fix(users): keep management inside center

This commit is contained in:
kate522 committed 2026-08-12 20:59:31 +08:00
1 parent c3bfd12c69
commit ce2b266890
44 files changed
+194 -2584

No files matched your search

-1
View File
@@ -18,7 +18,6 @@ class SchemaExtensions {
'audit' => SchemaExtensionsAudit::build(),
'push' => SchemaExtensionsPush::build(),
'security' => SchemaExtensionsSecurity::build(),
'docs-mode' => SchemaExtensionsDocsMode::build(),
],
];
}
@@ -1,53 +0,0 @@
<?php
/**
* @package AKSRT
*/
namespace AKSRT\Admin\Schema;
defined('ABSPATH') || exit;
class SchemaExtensionsDocsMode {
public static function build(): array {
return [
'key' => 'docs-mode',
'title' => '文档模式',
'version' => '1.0.0',
'option_key' => 'aksrt_settings',
'groups' => [
['key' => 'basic', 'title' => '基础配置', 'fields' => [
['key' => 'docs_mode_enabled', 'label' => '启用文档模式', 'type' => 'switch', 'default' => false],
['key' => 'docs_mode_default_template', 'label' => '文档首页模板', 'type' => 'select', 'default' => 'documentnav', 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true], 'options' => [
['label' => '文档导航页', 'value' => 'documentnav'],
['label' => '专题聚合页', 'value' => 'special'],
]],
]],
['key' => 'navigation', 'title' => '导航设置', 'fields' => [
['key' => 'docs_mode_toc_enabled', 'label' => '显示目录树', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true]],
['key' => 'docs_mode_chapter_nav_enabled', 'label' => '显示章节导航', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true]],
['key' => 'docs_mode_default_order', 'label' => '默认排序', 'type' => 'radio', 'default' => 'menu_order', 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true], 'options' => [
['label' => '按菜单顺序', 'value' => 'menu_order'],
['label' => '按发布时间', 'value' => 'date'],
['label' => '按标题排序', 'value' => 'title'],
]],
['key' => 'docs_mode_toc_depth', 'label' => '目录深度', 'type' => 'number', 'default' => 3, 'min' => 1, 'max' => 6, 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true]],
['key' => 'docs_mode_chapter_title', 'label' => '章节标题', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true]],
]],
['key' => 'filter', 'title' => '筛选设置', 'fields' => [
['key' => 'docs_mode_cats', 'label' => '文档分类', 'type' => 'taxonomy_select', 'taxonomy' => 'category', 'multiple' => true, 'default' => [], 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true]],
['key' => 'docs_mode_exclude', 'label' => '在首页排除此类内容', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true]],
]],
['key' => 'style', 'title' => '样式设置', 'fields' => [
['key' => 'docs_mode_style', 'label' => '文档样式', 'type' => 'select', 'default' => 'default', 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true], 'options' => [
['label' => '默认', 'value' => 'default'],
['label' => '简洁', 'value' => 'simple'],
['label' => '卡片', 'value' => 'card'],
]],
['key' => 'docs_mode_icon', 'label' => '显示图标', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true]],
['key' => 'docs_mode_count', 'label' => '显示文章数', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'docs_mode_enabled', 'value' => true]],
]],
],
];
}
}
-316
View File
@@ -1,316 +0,0 @@
<?php
/**
* Document navigation (zibll documentnav) — category tree + AJAX posts.
*
* @package AKSRT
*/
namespace AKSRT\Core;
defined('ABSPATH') || exit;
class DocumentNav {
private static $instance = null;
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function init(): void {
add_action('wp_ajax_aksrt_documentnav_posts', [$this, 'ajax_posts']);
add_action('wp_ajax_nopriv_aksrt_documentnav_posts', [$this, 'ajax_posts']);
add_action('add_meta_boxes', [$this, 'register_meta_box']);
add_action('save_post_page', [$this, 'save_meta_box']);
}
/**
* @return array{cat:int,initial_content:string}
*/
public static function get_options(int $post_id): array {
$raw = get_post_meta($post_id, 'documentnav_options', true);
if (!is_array($raw)) {
$raw = [];
}
$cat = isset($raw['cat']) ? absint($raw['cat']) : absint(get_post_meta($post_id, 'documentnav_cat', true));
$initial = isset($raw['initial_content']) ? sanitize_key((string) $raw['initial_content']) : sanitize_key((string) get_post_meta($post_id, 'documentnav_initial_content', true));
if (!in_array($initial, ['page_content', 'date_posts', 'updated_posts', 'views_posts'], true)) {
$initial = 'updated_posts';
}
return [
'cat' => $cat,
'initial_content' => $initial,
];
}
/**
* Render posts list HTML (zibll zib_get_documentnav_posts).
*/
public static function render_posts_html(\WP_Query $query): string {
if (!$query->have_posts()) {
$empty = function_exists('aksrt_get_null')
? aksrt_get_null(__('暂无相应内容', 'aksrt'), 40)
: '<p class="muted-2-color text-center">' . esc_html__('暂无相应内容', 'aksrt') . '</p>';
return '<div class="zib-widget">' . $empty . '</div>';
}
$html = '<div class="list-group main-shadow">';
while ($query->have_posts()) {
$query->the_post();
$time_ago = human_time_diff(get_the_time('U'), current_time('timestamp')) . __('前', 'aksrt');
$subtitle = (string) get_post_meta(get_the_ID(), 'subtitle', true);
if ($subtitle === '') {
$subtitle = (string) get_post_meta(get_the_ID(), 'aksrt_subtitle', true);
}
$html .= '<a class="list-group-item" href="' . esc_url(get_permalink()) . '">';
$html .= '<span class="badg badg-sm pull-right" title="' . esc_attr(get_the_time('Y-m-d H:i:s')) . '">' . esc_html($time_ago) . '</span>';
$html .= esc_html(get_the_title());
if ($subtitle !== '') {
$html .= '<span class="focus-color"> ' . esc_html($subtitle) . '</span>';
}
$html .= '</a>';
}
$html .= '</div>';
wp_reset_postdata();
return $html;
}
/**
* Simple paginate links for document nav container.
*/
public static function render_paginate(int $total, int $current, int $page_size, array $args = []): string {
$max = (int) ceil(max(0, $total) / max(1, $page_size));
if ($max <= 1) {
return '';
}
$current = max(1, min($current, $max));
$html = '<div class="pagenav notop text-center mt15">';
for ($i = 1; $i <= $max; $i++) {
$url = add_query_arg(array_merge($args, ['paged' => $i]));
$cls = $i === $current ? 'current' : '';
$html .= '<a class="' . esc_attr($cls) . '" href="' . esc_url($url) . '" data-paged="' . (int) $i . '">' . (int) $i . '</a> ';
}
$html .= '</div>';
return $html;
}
/**
* Recursive category accordion HTML.
*/
public static function render_panels(int $cat_id, string $data_parent = 'accordion', string $class = 'panel', bool &$is_on_open = true): string {
if ($cat_id <= 0) {
return '';
}
$terms = _get_term_hierarchy('category');
if (empty($terms[$cat_id]) || !is_array($terms[$cat_id])) {
return '';
}
$html = '<div class="panel-group posts-panel-group" id="' . esc_attr($data_parent) . '">';
foreach ($terms[$cat_id] as $child) {
$child = (int) $child;
if ($child === $cat_id) {
continue;
}
$cat_obj = get_category($child);
if (!$cat_obj || is_wp_error($cat_obj)) {
continue;
}
$has_kids = !empty($terms[$child]);
if ($has_kids) {
$open = $is_on_open;
$is_on_open = false;
$html .= '<div class="' . esc_attr($class) . '">';
$html .= '<h4 class="panel-title">';
$html .= '<a class="panel-toggle' . ($open ? '' : ' collapsed') . ' text-ellipsis" href="javascript:;" data-toggle="collapse" data-target="#dosc-nav-catid_' . $child . '" data-parent="#' . esc_attr($data_parent) . '">';
$html .= '<i class="fa fa-angle-right mr10" aria-hidden="true"></i>' . esc_html($cat_obj->name);
$html .= '</a></h4>';
$html .= '<div id="dosc-nav-catid_' . $child . '" class="panel-collapse' . ($open ? ' collapse in is-open' : ' collapse') . '">';
$html .= '<div class="category">';
$html .= self::render_panels($child, 'dosc-cat-nav-panel-' . $child, 'panel panel-child', $is_on_open);
$html .= '</div></div></div>';
} else {
$html .= '<a class="cat-load text-ellipsis" data-cat-id="' . $child . '" href="javascript:;" title="' . esc_attr($cat_obj->name) . '">';
$html .= '<i class="loading" aria-hidden="true"></i>' . esc_html($cat_obj->name);
$html .= '</a>';
}
}
$html .= '</div>';
return $html;
}
public function ajax_posts(): void {
$search = isset($_REQUEST['search']) ? sanitize_text_field(wp_unslash((string) $_REQUEST['search'])) : '';
$cat_id = isset($_REQUEST['cat_id']) ? absint($_REQUEST['cat_id']) : 0;
$one_cat = isset($_REQUEST['one_cat']) ? absint($_REQUEST['one_cat']) : 0;
$paged = isset($_REQUEST['paged']) ? max(1, absint($_REQUEST['paged'])) : 1;
$page_size = 12;
if ($search === '' && $cat_id <= 0) {
wp_send_json(['error' => 1, 'ys' => 'danger', 'msg' => __('参数传入错误!', 'aksrt')]);
}
$args = [
'ignore_sticky_posts' => true,
'paged' => $paged,
'posts_per_page' => $page_size,
'post_status' => 'publish',
'post_type' => 'post',
];
if ($search !== '') {
$args['s'] = $search;
$args['cat'] = $one_cat > 0 ? $one_cat : 0;
// Persist simple history (user meta or cookie-less option list is optional).
$this->remember_search($search);
} else {
$args['cat'] = $cat_id;
}
$query = new \WP_Query($args);
$html = self::render_posts_html($query);
$html .= self::render_paginate(
(int) $query->found_posts,
$paged,
$page_size,
[
'action' => 'aksrt_documentnav_posts',
'cat_id' => $cat_id,
'search' => $search,
'one_cat' => $one_cat,
]
);
wp_send_json([
'error' => 0,
'html' => $html,
'total' => (int) $query->found_posts,
'history_search' => $this->history_buttons_html(),
]);
}
private function remember_search(string $term): void {
$term = trim($term);
if ($term === '' || mb_strlen($term) < 2) {
return;
}
$key = is_user_logged_in() ? 'aksrt_doc_search_history_' . get_current_user_id() : '';
$list = [];
if ($key !== '') {
$saved = get_user_meta(get_current_user_id(), 'aksrt_doc_search_history', true);
$list = is_array($saved) ? $saved : [];
} else {
$cookie = isset($_COOKIE['aksrt_doc_search_history']) ? wp_unslash((string) $_COOKIE['aksrt_doc_search_history']) : '';
$decoded = json_decode($cookie, true);
$list = is_array($decoded) ? $decoded : [];
}
$list = array_values(array_unique(array_filter(array_map('strval', $list))));
array_unshift($list, $term);
$list = array_slice(array_values(array_unique($list)), 0, 8);
if ($key !== '') {
update_user_meta(get_current_user_id(), 'aksrt_doc_search_history', $list);
} elseif (!headers_sent()) {
setcookie('aksrt_doc_search_history', wp_json_encode($list), time() + WEEK_IN_SECONDS, COOKIEPATH ?: '/', COOKIE_DOMAIN, is_ssl(), true);
}
}
/**
* @return list<string>
*/
private function get_history(): array {
if (is_user_logged_in()) {
$saved = get_user_meta(get_current_user_id(), 'aksrt_doc_search_history', true);
return is_array($saved) ? array_values(array_filter(array_map('strval', $saved))) : [];
}
$cookie = isset($_COOKIE['aksrt_doc_search_history']) ? wp_unslash((string) $_COOKIE['aksrt_doc_search_history']) : '';
$decoded = json_decode($cookie, true);
return is_array($decoded) ? array_values(array_filter(array_map('strval', $decoded))) : [];
}
public function history_buttons_html(): string {
$items = $this->get_history();
if (!$items) {
return '';
}
$html = '';
foreach ($items as $term) {
$html .= '<a href="javascript:;" class="search_keywords but badg mr6 mb6">' . esc_html($term) . '</a>';
}
return $html;
}
public function register_meta_box(): void {
add_meta_box(
'aksrt_documentnav_meta',
__('文档导航设置', 'aksrt'),
[$this, 'render_meta_box'],
'page',
'side',
'default'
);
}
public function render_meta_box(\WP_Post $post): void {
$tpl = (string) get_post_meta($post->ID, '_wp_page_template', true);
if ($tpl !== 'templates/pages/page-documentnav.php') {
echo '<p class="description">' . esc_html__('将模板设为「AKSRT - 文档导航」后配置。', 'aksrt') . '</p>';
return;
}
$opt = self::get_options((int) $post->ID);
wp_nonce_field('aksrt_documentnav_meta', 'aksrt_documentnav_meta_nonce');
$cats = get_categories(['hide_empty' => false, 'parent' => 0]);
?>
<p>
<label for="documentnav_cat"><strong><?php esc_html_e('一级分类', 'aksrt'); ?></strong></label>
<select name="documentnav_cat" id="documentnav_cat" class="widefat">
<option value="0"><?php esc_html_e('请选择', 'aksrt'); ?></option>
<?php foreach ($cats as $c) : ?>
<option value="<?php echo (int) $c->term_id; ?>" <?php selected($opt['cat'], (int) $c->term_id); ?>>
<?php echo esc_html($c->name); ?>
</option>
<?php endforeach; ?>
</select>
</p>
<p>
<label for="documentnav_initial_content"><strong><?php esc_html_e('初始内容', 'aksrt'); ?></strong></label>
<select name="documentnav_initial_content" id="documentnav_initial_content" class="widefat">
<?php
$opts = [
'page_content' => __('显示页面内容', 'aksrt'),
'date_posts' => __('最近发布文章', 'aksrt'),
'updated_posts' => __('最近更新文章', 'aksrt'),
'views_posts' => __('查看最多文章', 'aksrt'),
];
foreach ($opts as $k => $label) :
?>
<option value="<?php echo esc_attr($k); ?>" <?php selected($opt['initial_content'], $k); ?>><?php echo esc_html($label); ?></option>
<?php endforeach; ?>
</select>
</p>
<?php
}
public function save_meta_box(int $post_id): void {
if (!isset($_POST['aksrt_documentnav_meta_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash((string) $_POST['aksrt_documentnav_meta_nonce'])), 'aksrt_documentnav_meta')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
$cat = isset($_POST['documentnav_cat']) ? absint($_POST['documentnav_cat']) : 0;
$initial = isset($_POST['documentnav_initial_content']) ? sanitize_key((string) wp_unslash($_POST['documentnav_initial_content'])) : 'updated_posts';
if (!in_array($initial, ['page_content', 'date_posts', 'updated_posts', 'views_posts'], true)) {
$initial = 'updated_posts';
}
update_post_meta($post_id, 'documentnav_options', [
'cat' => $cat,
'initial_content' => $initial,
]);
}
}
-302
View File
@@ -1,302 +0,0 @@
<?php
/**
* Page meta for 网址导航 template (page_links_* keys, zibll metabox parity).
*
* @package AKSRT
*/
namespace AKSRT\Core;
defined('ABSPATH') || exit;
class LinksPageMeta {
private static $instance = null;
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function init(): void {
add_action('add_meta_boxes', [$this, 'register_meta_box']);
add_action('save_post_page', [$this, 'save_meta_box']);
}
public function register_meta_box(): void {
add_meta_box(
'aksrt_page_links_meta',
__('网址导航设置', 'aksrt'),
[$this, 'render_meta_box'],
'page',
'normal',
'high'
);
}
/**
* Whether current page uses the links template.
*/
private function is_links_template(int $post_id): bool {
$tpl = (string) get_post_meta($post_id, '_wp_page_template', true);
return $tpl === 'templates/pages/page-links.php';
}
public function render_meta_box(\WP_Post $post): void {
$post_id = (int) $post->ID;
if (!$this->is_links_template($post_id)) {
echo '<p class="description">' . esc_html__('将页面模板设为「AKSRT - 网址导航」后在此配置分类、样式与提交模块。', 'aksrt') . '</p>';
return;
}
$s = function_exists('aksrt_get_page_links_settings')
? aksrt_get_page_links_settings($post_id)
: [];
wp_nonce_field('aksrt_page_links_meta', 'aksrt_page_links_meta_nonce');
$terms = get_terms([
'taxonomy' => 'link_category',
'hide_empty' => false,
]);
if (is_wp_error($terms)) {
$terms = [];
}
$selected_cats = array_map('intval', (array) ($s['category'] ?? []));
$submit_cats = array_map('intval', (array) ($s['submit_cats'] ?? []));
$search_types = (array) ($s['search_types'] ?? []);
$engine_options = [
'self' => __('站内', 'aksrt'),
'baidu' => __('百度', 'aksrt'),
'google' => __('谷歌', 'aksrt'),
'bing' => __('必应', 'aksrt'),
'sogou' => __('搜狗', 'aksrt'),
'360' => '360',
];
?>
<table class="form-table aksrt-page-links-meta" role="presentation">
<tr>
<th scope="row"><?php esc_html_e('显示页面内容', 'aksrt'); ?></th>
<td>
<label>
<input type="checkbox" name="page_links_content_s" value="1" <?php checked(!empty($s['content_s'])); ?>>
<?php esc_html_e('在链接列表上下方展示页面正文', 'aksrt'); ?>
</label>
<p>
<label>
<input type="radio" name="page_links_content_position" value="top" <?php checked(($s['content_position'] ?? 'top'), 'top'); ?>>
<?php esc_html_e('链接列表上面', 'aksrt'); ?>
</label>
&nbsp;
<label>
<input type="radio" name="page_links_content_position" value="bottom" <?php checked(($s['content_position'] ?? ''), 'bottom'); ?>>
<?php esc_html_e('链接列表下面', 'aksrt'); ?>
</label>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('搜索引擎模块', 'aksrt'); ?></th>
<td>
<label>
<input type="checkbox" name="page_links_search_s" value="1" <?php checked(!empty($s['search_s'])); ?>>
<?php esc_html_e('显示搜索封面(使用特色图作背景)', 'aksrt'); ?>
</label>
<p class="description"><?php esc_html_e('选择引擎(可多选,按住 Ctrl)', 'aksrt'); ?></p>
<select name="page_links_search_types[]" multiple class="widefat" size="6">
<?php foreach ($engine_options as $key => $label) : ?>
<option value="<?php echo esc_attr($key); ?>" <?php selected(in_array($key, $search_types, true)); ?>>
<?php echo esc_html($label); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('链接分类(必选)', 'aksrt'); ?></th>
<td>
<?php if (empty($terms)) : ?>
<p class="description">
<?php
printf(
/* translators: %s: link manager URL */
wp_kses_post(__('暂无链接分类。请先在 <a href="%s">链接管理</a> 中创建分类与链接。', 'aksrt')),
esc_url(admin_url('link-manager.php'))
);
?>
</p>
<?php else : ?>
<select name="page_links_category[]" multiple class="widefat" size="8">
<?php foreach ($terms as $term) : ?>
<option value="<?php echo (int) $term->term_id; ?>" <?php selected(in_array((int) $term->term_id, $selected_cats, true)); ?>>
<?php echo esc_html($term->name . ' (' . (int) $term->count . ')'); ?>
</option>
<?php endforeach; ?>
</select>
<p class="description"><?php esc_html_e('多选时按导航目录展示;一个都不选则不显示链接。', 'aksrt'); ?></p>
<?php endif; ?>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('显示样式', 'aksrt'); ?></th>
<td>
<?php
$style = (string) ($s['style'] ?? 'card');
$styles = [
'card' => __('图文列表', 'aksrt'),
'bigcard' => __('大卡片', 'aksrt'),
'image' => __('纯图片', 'aksrt'),
];
foreach ($styles as $key => $label) :
?>
<label style="margin-right:12px;">
<input type="radio" name="page_links_style" value="<?php echo esc_attr($key); ?>" <?php checked($style, $key); ?>>
<?php echo esc_html($label); ?>
</label>
<?php endforeach; ?>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('数量与排序', 'aksrt'); ?></th>
<td>
<label>
<?php esc_html_e('每类最多', 'aksrt'); ?>
<input type="number" name="page_links_limit" value="<?php echo esc_attr((string) (int) ($s['limit'] ?? 0)); ?>" min="0" step="1" class="small-text">
<?php esc_html_e('个(0=不限)', 'aksrt'); ?>
</label>
<p>
<select name="page_links_orderby">
<?php
$orderbys = [
'name' => __('名称', 'aksrt'),
'updated' => __('更新时间', 'aksrt'),
'rating' => __('评分', 'aksrt'),
'rand' => __('随机', 'aksrt'),
];
$orderby = (string) ($s['orderby'] ?? 'name');
foreach ($orderbys as $key => $label) :
?>
<option value="<?php echo esc_attr($key); ?>" <?php selected($orderby, $key); ?>><?php echo esc_html($label); ?></option>
<?php endforeach; ?>
</select>
<select name="page_links_order">
<option value="ASC" <?php selected(($s['order'] ?? 'ASC'), 'ASC'); ?>><?php esc_html_e('升序', 'aksrt'); ?></option>
<option value="DESC" <?php selected(($s['order'] ?? ''), 'DESC'); ?>><?php esc_html_e('降序', 'aksrt'); ?></option>
</select>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('链接行为', 'aksrt'); ?></th>
<td>
<label><input type="checkbox" name="page_links_go_s" value="1" <?php checked(!empty($s['go_s'])); ?>> <?php esc_html_e('外链重定向 /go/', 'aksrt'); ?></label><br>
<label><input type="checkbox" name="page_links_blank_s" value="1" <?php checked(!empty($s['blank_s'])); ?>> <?php esc_html_e('新标签打开', 'aksrt'); ?></label><br>
<label><input type="checkbox" name="page_links_nofollow_s" value="1" <?php checked(!empty($s['nofollow_s'])); ?>> <?php esc_html_e('添加 nofollow', 'aksrt'); ?></label>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('提交链接', 'aksrt'); ?></th>
<td>
<label><input type="checkbox" name="page_links_submit_s" value="1" <?php checked(!empty($s['submit_s'])); ?>> <?php esc_html_e('显示申请入驻', 'aksrt'); ?></label><br>
<label><input type="checkbox" name="page_links_submit_sign_s" value="1" <?php checked(!empty($s['submit_sign_s'])); ?>> <?php esc_html_e('登录后才能提交', 'aksrt'); ?></label>
<p>
<label><?php esc_html_e('按钮标题', 'aksrt'); ?>
<input type="text" class="regular-text" name="page_links_submit_title" value="<?php echo esc_attr((string) ($s['submit_title'] ?? '')); ?>">
</label>
</p>
<p>
<label for="page_links_submit_dec"><?php esc_html_e('提交说明(HTML)', 'aksrt'); ?></label><br>
<textarea class="large-text" rows="5" id="page_links_submit_dec" name="page_links_submit_dec"><?php echo esc_textarea((string) ($s['submit_dec'] ?? '')); ?></textarea>
</p>
<?php if (!empty($terms)) : ?>
<p class="description"><?php esc_html_e('提交时可选分类(空=全部分类)', 'aksrt'); ?></p>
<select name="page_links_submit_cats[]" multiple class="widefat" size="6">
<?php foreach ($terms as $term) : ?>
<option value="<?php echo (int) $term->term_id; ?>" <?php selected(in_array((int) $term->term_id, $submit_cats, true)); ?>>
<?php echo esc_html($term->name); ?>
</option>
<?php endforeach; ?>
</select>
<?php endif; ?>
</td>
</tr>
</table>
<?php
}
public function save_meta_box(int $post_id): void {
if (!isset($_POST['aksrt_page_links_meta_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash((string) $_POST['aksrt_page_links_meta_nonce'])), 'aksrt_page_links_meta')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if (!$this->is_links_template($post_id) && empty($_POST['page_links_category']) && empty($_POST['page_links_submit_s'])) {
// Still allow save if user just switched template in same request.
$tpl = isset($_POST['page_template']) ? (string) wp_unslash($_POST['page_template']) : '';
if ($tpl !== 'templates/pages/page-links.php') {
return;
}
}
$bool_keys = [
'page_links_content_s',
'page_links_search_s',
'page_links_go_s',
'page_links_blank_s',
'page_links_nofollow_s',
'page_links_submit_s',
'page_links_submit_sign_s',
];
foreach ($bool_keys as $key) {
update_post_meta($post_id, $key, isset($_POST[$key]) ? 1 : 0);
}
$position = isset($_POST['page_links_content_position']) ? sanitize_key((string) wp_unslash($_POST['page_links_content_position'])) : 'top';
if (!in_array($position, ['top', 'bottom'], true)) {
$position = 'top';
}
update_post_meta($post_id, 'page_links_content_position', $position);
$style = isset($_POST['page_links_style']) ? sanitize_key((string) wp_unslash($_POST['page_links_style'])) : 'card';
if (!in_array($style, ['card', 'bigcard', 'image', 'simple'], true)) {
$style = 'card';
}
update_post_meta($post_id, 'page_links_style', $style);
$orderby = isset($_POST['page_links_orderby']) ? sanitize_key((string) wp_unslash($_POST['page_links_orderby'])) : 'name';
if (!in_array($orderby, ['name', 'updated', 'rating', 'rand', 'id', 'length'], true)) {
$orderby = 'name';
}
update_post_meta($post_id, 'page_links_orderby', $orderby);
$order = isset($_POST['page_links_order']) ? strtoupper(sanitize_text_field(wp_unslash((string) $_POST['page_links_order']))) : 'ASC';
update_post_meta($post_id, 'page_links_order', $order === 'DESC' ? 'DESC' : 'ASC');
$limit = isset($_POST['page_links_limit']) ? max(0, (int) $_POST['page_links_limit']) : 0;
update_post_meta($post_id, 'page_links_limit', $limit);
$cats = isset($_POST['page_links_category']) ? array_values(array_filter(array_map('intval', (array) wp_unslash($_POST['page_links_category'])))) : [];
update_post_meta($post_id, 'page_links_category', $cats);
$submit_cats = isset($_POST['page_links_submit_cats']) ? array_values(array_filter(array_map('intval', (array) wp_unslash($_POST['page_links_submit_cats'])))) : [];
update_post_meta($post_id, 'page_links_submit_cats', $submit_cats);
$engines = isset($_POST['page_links_search_types']) ? array_values(array_filter(array_map('sanitize_key', (array) wp_unslash($_POST['page_links_search_types'])))) : [];
$allowed = ['self', 'baidu', 'google', 'bing', 'sogou', '360'];
$engines = array_values(array_intersect($engines, $allowed));
update_post_meta($post_id, 'page_links_search_types', $engines);
$title = isset($_POST['page_links_submit_title']) ? sanitize_text_field(wp_unslash((string) $_POST['page_links_submit_title'])) : '';
update_post_meta($post_id, 'page_links_submit_title', $title);
$dec = isset($_POST['page_links_submit_dec']) ? wp_kses_post(wp_unslash((string) $_POST['page_links_submit_dec'])) : '';
update_post_meta($post_id, 'page_links_submit_dec', $dec);
}
}
-123
View File
@@ -1,123 +0,0 @@
<?php
/**
* Frontend links (bookmarks) submit — zibll frontend_links_submit parity.
*
* @package AKSRT
*/
namespace AKSRT\Core;
defined('ABSPATH') || exit;
class LinksSubmit {
private static $instance = null;
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function init(): void {
add_action('wp_ajax_aksrt_frontend_links_submit', [$this, 'ajax_submit']);
add_action('wp_ajax_nopriv_aksrt_frontend_links_submit', [$this, 'ajax_submit']);
}
/**
* AJAX: create a pending WordPress bookmark (link).
*/
public function ajax_submit(): void {
if (!check_ajax_referer('aksrt_frontend_links_submit', '_wpnonce', false)) {
wp_send_json(['error' => 1, 'ys' => 'danger', 'msg' => __('安全校验失败,请刷新后重试', 'aksrt')]);
}
if (isset($_COOKIE['aksrt_links_submit_time'])) {
wp_send_json(['error' => 1, 'ys' => 'danger', 'msg' => __('操作过于频繁,请稍候再试', 'aksrt')]);
}
$link_name = isset($_POST['link_name']) ? sanitize_text_field(wp_unslash((string) $_POST['link_name'])) : '';
$link_url = isset($_POST['link_url']) ? esc_url_raw(wp_unslash((string) $_POST['link_url'])) : '';
$link_desc = isset($_POST['link_description']) ? sanitize_text_field(wp_unslash((string) $_POST['link_description'])) : '';
$cat_raw = isset($_POST['link_category']) ? wp_unslash($_POST['link_category']) : [];
if ($link_name === '') {
wp_send_json(['error' => 1, 'ys' => 'danger', 'msg' => __('请填写网站名称', 'aksrt')]);
}
if ($link_url === '' || !wp_http_validate_url($link_url)) {
wp_send_json(['error' => 1, 'ys' => 'danger', 'msg' => __('网站地址格式错误', 'aksrt')]);
}
// Optional logo upload.
$logo_url = '';
if (!empty($_FILES['image']['name'])) {
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
$attachment_id = media_handle_upload('image', 0);
if (is_wp_error($attachment_id)) {
wp_send_json(['error' => 1, 'ys' => 'danger', 'msg' => $attachment_id->get_error_message()]);
}
$src = wp_get_attachment_image_src((int) $attachment_id, 'medium');
$logo_url = !empty($src[0]) ? (string) $src[0] : (string) wp_get_attachment_url((int) $attachment_id);
}
$categories = [];
if (is_array($cat_raw)) {
$categories = array_values(array_filter(array_map('intval', $cat_raw)));
} elseif ($cat_raw !== '' && $cat_raw !== null) {
$categories = [absint($cat_raw)];
}
// Duplicate URL guard.
global $wpdb;
$exists = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(1) FROM {$wpdb->links} WHERE link_url = %s",
$link_url
)
);
if ($exists > 0) {
wp_send_json(['error' => 1, 'ys' => 'danger', 'msg' => __('您的链接已提交,请勿重复提交', 'aksrt')]);
}
if (!function_exists('wp_insert_link')) {
require_once ABSPATH . 'wp-admin/includes/bookmark.php';
}
$linkdata = [
'link_name' => $link_name,
'link_url' => $link_url,
'link_description' => $link_desc,
'link_image' => $logo_url,
// Non-admins create invisible links pending review (zibll parity).
'link_visible' => current_user_can('manage_links') ? 'Y' : 'N',
'link_category' => $categories,
];
$links_id = wp_insert_link($linkdata, true);
if (is_wp_error($links_id)) {
wp_send_json(['error' => 1, 'ys' => 'danger', 'msg' => $links_id->get_error_message()]);
}
// 30s client throttle cookie.
if (!headers_sent()) {
setcookie('aksrt_links_submit_time', (string) time(), time() + 30, COOKIEPATH ?: '/', COOKIE_DOMAIN, is_ssl(), true);
}
$msg = $linkdata['link_visible'] === 'Y'
? __('提交成功', 'aksrt')
: __('提交成功,等待管理员处理', 'aksrt');
/**
* Fires after a frontend link submission is stored.
*
* @param array $linkdata Sanitized bookmark data.
* @param int $links_id New link ID.
*/
do_action('aksrt_frontend_links_submit_success', $linkdata, (int) $links_id);
wp_send_json(['error' => 0, 'msg' => $msg, 'reload' => true]);
}
}
-108
View File
@@ -564,28 +564,6 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
}
// 网址导航页(zibll links.php)
if (is_page_template('templates/pages/page-links.php')) {
$links_css = get_template_directory() . '/assets/css/routes/links.css';
if (file_exists($links_css)) {
wp_enqueue_style(
'aksrt-route-links',
$base_uri . '/assets/css/routes/links.css',
['aksrt-tokens'],
(string) filemtime($links_css)
);
}
$links_js = get_template_directory() . '/assets/js/links-page.js';
if (file_exists($links_js)) {
wp_enqueue_script(
'aksrt-links-page',
$base_uri . '/assets/js/links-page.js',
['jquery'],
(string) filemtime($links_js),
true
);
}
}
// 文章导航页(zibll postsnavs.php)
if (is_page_template('templates/pages/page-posts-navs.php')) {
$page_navs_js = get_template_directory() . '/assets/js/page-navs.js';
@@ -643,29 +621,6 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
}
}
// 文档导航页(zibll documentnav.php)
if (is_page_template('templates/pages/page-documentnav.php')) {
$dn_css = get_template_directory() . '/assets/css/routes/documentnav.css';
if (file_exists($dn_css)) {
wp_enqueue_style(
'aksrt-route-documentnav',
$base_uri . '/assets/css/routes/documentnav.css',
['aksrt-tokens'],
(string) filemtime($dn_css)
);
}
$dn_js = get_template_directory() . '/assets/js/documentnav-page.js';
if (file_exists($dn_js)) {
wp_enqueue_script(
'aksrt-documentnav-page',
$base_uri . '/assets/js/documentnav-page.js',
[],
(string) filemtime($dn_js),
true
);
}
}
// 禁封申诉页
if (is_page_template('templates/pages/page-ban-appeal.php')) {
$ba_css = get_template_directory() . '/assets/css/routes/ban-appeal.css';
@@ -689,69 +644,6 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
}
}
// 交易中心共享壳层(订单 / 收益)
// Virtual rewrite routes (aksrt_orders / aksrt_revenue) also count.
$is_commerce_center = is_page_template('templates/pages/page-orders.php')
|| is_page_template('templates/pages/page-revenue.php')
|| (bool) get_query_var('aksrt_orders')
|| (bool) get_query_var('aksrt_revenue');
if ($is_commerce_center) {
$commerce_css = get_template_directory() . '/assets/css/routes/commerce.css';
if (file_exists($commerce_css)) {
wp_enqueue_style(
'aksrt-commerce-shell',
$base_uri . '/assets/css/routes/commerce.css',
['aksrt-tokens'],
(string) filemtime($commerce_css)
);
}
}
// 订单中心:独立页 / 虚拟 rewrite;用户中心在上方按可用 tab 预载。
$is_orders_surface = is_page_template('templates/pages/page-orders.php')
|| (bool) get_query_var('aksrt_orders');
if ($is_orders_surface) {
$orders_css = get_template_directory() . '/assets/css/routes/orders.css';
if (file_exists($orders_css)) {
wp_enqueue_style(
'aksrt-orders',
$base_uri . '/assets/css/routes/orders.css',
['aksrt-tokens'],
(string) filemtime($orders_css)
);
}
$order_center_js = get_template_directory() . '/assets/js/order-center.js';
if (file_exists($order_center_js)) {
wp_enqueue_script(
'aksrt-order-center',
$base_uri . '/assets/js/order-center.js',
['aksrt-script', 'aksrt-rehydrate', 'aksrt-core-request', 'aksrt-core-modal-runtime'],
(string) filemtime($order_center_js),
true
);
}
}
// 收益中心:旧路由重定向页 / 用户中心 tab=revenue。
$is_revenue_surface = is_page_template('templates/pages/page-revenue.php')
|| (bool) get_query_var('aksrt_revenue')
|| (
(function_exists('aksrt_is_user_center_page') && aksrt_is_user_center_page())
&& isset($_GET['tab'])
&& 'revenue' === sanitize_key((string) wp_unslash($_GET['tab']))
);
if ($is_revenue_surface && !$is_profile_page) {
$revenue_js = get_template_directory() . '/assets/js/revenue.js';
wp_enqueue_script(
'aksrt-revenue',
$base_uri . '/assets/js/revenue.js',
['aksrt-script'],
file_exists($revenue_js) ? (string) filemtime($revenue_js) : $version,
true
);
}
// 消息中心页
if (is_page_template('templates/pages/page-messages.php')) {
$messages_css = get_template_directory() . '/assets/css/frontend/messages.css';
+1 -1
View File
@@ -264,7 +264,7 @@ trait ScriptsPart2 {
*/
private function resolve_frontend_routes(): array {
return [
'orders' => $this->resolve_template_page_url('templates/pages/page-orders.php', '/orders/'),
'orders' => function_exists('aksrt_get_user_center_tab_url') ? aksrt_get_user_center_tab_url('orders') : home_url('/user/orders/'),
'resources' => home_url('/resources/'),
];
}
-4
View File
@@ -39,17 +39,13 @@ class Templates {
'templates/pages/page-profile.php' => __('AKSRT - 个人中心', 'aksrt'),
'templates/pages/page-user-home.php' => __('AKSRT - 用户主页', 'aksrt'),
'templates/pages/page-archives.php' => __('AKSRT - 文章归档', 'aksrt'),
'templates/pages/page-documentnav.php' => __('AKSRT - 文档导航', 'aksrt'),
'templates/pages/page-categories.php' => __('AKSRT - 分类汇总', 'aksrt'),
'templates/pages/page-newposts.php' => __('AKSRT - 最新文章', 'aksrt'),
// 注意:page-newposts = 最新文章列表;投稿页是 page-submit(写文章/投稿)
'templates/pages/page-submit.php' => __('AKSRT - 写文章/投稿', 'aksrt'),
'templates/pages/page-posts-navs.php' => __('AKSRT - 文章导航', 'aksrt'),
'templates/pages/page-friends.php' => __('AKSRT - 友情链接', 'aksrt'),
'templates/pages/page-links.php' => __('AKSRT - 网址导航', 'aksrt'),
'templates/pages/page-ban-appeal.php' => __('AKSRT - 禁封申诉', 'aksrt'),
'templates/pages/page-orders.php' => __('AKSRT - 订单中心', 'aksrt'),
'templates/pages/page-revenue.php' => __('AKSRT - 收益中心', 'aksrt'),
'templates/pages/page-messages.php' => __('AKSRT - 消息中心', 'aksrt'),
];
}
+3 -15
View File
@@ -408,20 +408,8 @@ class Gateway {
}
private function orders_page_url(): string {
$pages = get_posts([
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => 1,
'meta_key' => '_wp_page_template',
'meta_value' => 'templates/pages/page-orders.php',
'fields' => 'ids',
'no_found_rows' => true,
]);
if (!empty($pages)) {
return (string) get_permalink((int) $pages[0]);
}
return home_url('/orders/');
return function_exists('aksrt_get_user_center_tab_url')
? aksrt_get_user_center_tab_url('orders')
: home_url('/user/orders/');
}
}
-7
View File
@@ -27,13 +27,6 @@ trait DomainGroups {
Integration::update_wechat_settings($settings);
}
/**
* 获取文档模式设置
*/
public static function get_docs_mode_settings(): array {
return Integration::get_docs_mode_settings();
}
/**
* 获取全局背景设置
*/
-51
View File
@@ -567,55 +567,4 @@ class Integration {
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']),
];
}
}
+22 -4
View File
@@ -141,6 +141,18 @@ class Center {
'priority' => 18,
'type' => 'panel',
],
'posts' => [
'label' => __('文章', 'aksrt'),
'icon' => 'file-alt',
'priority' => 20,
'type' => 'panel',
],
'follow' => [
'label' => __('粉丝', 'aksrt'),
'icon' => 'users',
'priority' => 25,
'type' => 'panel',
],
'comments' => [
'label' => __('我的评论', 'aksrt'),
'icon' => 'comment',
@@ -200,10 +212,7 @@ class Center {
];
$this->panels = [];
$configured = array_values(array_filter(
array_map('sanitize_key', (array) ($settings['tabs'] ?? [])),
static fn(string $key): bool => $key !== 'posts'
));
$configured = array_values(array_map('sanitize_key', (array) ($settings['tabs'] ?? [])));
if ($configured === []) {
$configured = ['profile', 'comments', 'favorites'];
}
@@ -232,6 +241,15 @@ class Center {
$order = array_values(array_filter($order, static fn(string $key): bool => $key !== 'creator'));
}
if (!in_array('posts', $order, true)) {
$insert_at = array_search('creator', $order, true);
array_splice($order, $insert_at === false ? 0 : (int) $insert_at + 1, 0, ['posts']);
}
if (!in_array('follow', $order, true)) {
$insert_at = array_search('posts', $order, true);
array_splice($order, $insert_at === false ? count($order) : (int) $insert_at + 1, 0, ['follow']);
}
// Growth level is a dedicated user-center surface, separate from spendable points.
if ($level_on && !in_array('level', $order, true)) {
$insert_at = array_search('profile', $order, true);