feat(user-ban): frontend ban modal replaces the backend restrictions tab

1:1 replicate the reference theme user-ban flow on the frontend:

- Ban/unban modal rendered by inc/helpers/user-ban.php, opened via
  AksrtModalRuntime.openRemote (600px desktop dialog, 360px initial
  height, mobile bottom drawer, c-yellow colorful unban header).
- Three entry points wired: user homepage cover three-dot menu,
  comment section menu, article author card menu (ban item takes
  priority over report, matching the reference hook order).
- REST endpoints /user-ban/modal and /user-ban/set under aksrt/v1,
  guarded by check_permission, persisted through User\Restriction.
- Submit semantics match zib_ajax_set_user_ban: ban reloads the page,
  unban only closes the modal.

Cleanup (no dual-track): the backend ban-restrictions tab, its form
handlers and flash keys are removed; ticket processing links to the
frontend user homepage as the reference theme does; admin/report and
appeal notification URLs move to type/status query args.

Verification: 337/337 widget-system contract tests, 41/41 admin and
front-submit tests, php -l clean on all changed PHP files.
This commit is contained in:
kate522 committed 2026-09-20 18:42:53 +08:00
1 parent a1eb545bef
commit 7597972eea
18 files changed
+1080 -374

No files matched your search

+4 -340
View File
@@ -36,8 +36,6 @@ class UsersMenus {
add_action('admin_post_aksrt_users_review_verify', [$this, 'handle_review_verify']);
add_action('admin_post_aksrt_users_delete_verify', [$this, 'handle_delete_verify']);
add_action('admin_post_aksrt_users_update_report', [$this, 'handle_update_report']);
add_action('admin_post_aksrt_users_add_restriction', [$this, 'handle_add_restriction']);
add_action('admin_post_aksrt_users_remove_restriction', [$this, 'handle_remove_restriction']);
add_action('admin_post_aksrt_users_process_appeal', [$this, 'handle_process_appeal']);
add_action('admin_post_aksrt_users_mutate_vip', [$this, 'handle_mutate_vip']);
}
@@ -159,9 +157,6 @@ class UsersMenus {
'verify_failed' => __('认证审核失败。', 'aksrt'),
'report_updated' => __('举报状态已更新。', 'aksrt'),
'report_failed' => __('举报更新失败。', 'aksrt'),
'restriction_added' => __('限制已添加。', 'aksrt'),
'restriction_removed' => __('限制已移除。', 'aksrt'),
'restriction_failed' => __('限制操作失败。', 'aksrt'),
'appeal_approved' => __('申诉已通过,限制已解除。', 'aksrt'),
'appeal_rejected' => __('申诉已驳回。', 'aksrt'),
'appeal_failed' => __('申诉处理失败。', 'aksrt'),
@@ -287,247 +282,13 @@ class UsersMenus {
echo '<div class="wrap"><h2>' . esc_html__('用户禁封申诉及用户举报管理', 'aksrt') . '</h2>';
$this->flash();
$tab = isset($_GET['tab']) ? sanitize_key((string) wp_unslash($_GET['tab'])) : 'tickets';
if (!in_array($tab, ['tickets', 'restrictions'], true)) {
$tab = 'tickets';
}
echo '<h2 class="nav-tab-wrapper">';
printf('<a class="nav-tab%s" href="%s">%s</a>', $tab === 'tickets' ? ' nav-tab-active' : '', esc_url(admin_url('users.php?page=aksrt_user_ban')), esc_html__('申诉&举报', 'aksrt'));
printf('<a class="nav-tab%s" href="%s">%s</a>', $tab === 'restrictions' ? ' nav-tab-active' : '', esc_url(admin_url('users.php?page=aksrt_user_ban&tab=restrictions')), esc_html__('禁封限制', 'aksrt'));
echo '</h2>';
if ($tab === 'restrictions') {
$this->render_restrictions_tab();
} else {
$this->render_tickets_tab();
}
// 与参考主题一致:后台仅承载「申诉&举报」工单处理;禁封/解封操作
// 全部在前台完成(用户主页封面 / 评论区 / 文章作者栏三点菜单 →
// 封禁弹窗,REST /user-ban/modal + /user-ban/set)。
$this->render_tickets_tab();
echo '</div>';
}
/**
* 禁封限制页 — 1:1 对齐参考主题 zib_get_set_user_ban_modal:
* 禁封方式(拉入小黑屋/禁封用户)+ 禁封时间(1/7/14/30/100/永久)+
* 选择禁封原因(预置徽章 + 其它原因)+ 禁封说明 + 删除全部内容 +
* 禁止用户申诉(含说明);已禁封用户展示状态信息与解封留言表单。
* 参考主题无 scope 维度,禁封一律全局。
*/
private function render_restrictions_tab(): void {
if (!class_exists('\AKSRT\User\Restriction')) {
echo '<div class="notice notice-error"><p>' . esc_html__('限制模块未初始化。', 'aksrt') . '</p></div>';
return;
}
$svc = \AKSRT\User\Restriction::get_instance();
$page_url = admin_url('users.php?page=aksrt_user_ban&tab=restrictions');
$target_id = isset($_GET['user_id']) ? max(0, (int) $_GET['user_id']) : 0;
$unban = isset($_GET['action']) && sanitize_key((string) wp_unslash($_GET['action'])) === 'unban';
$target = $target_id > 0 ? get_userdata($target_id) : null;
// 页面级样式(wp-admin 不加载前端 kit,就地声明参考主题同款外观)
echo '<style>
.aksrt-ban-modal .muted-2-color{color:#777;}
.aksrt-ban-modal .author-set-left{min-width:80px;flex:0 0 auto;color:#777;}
.aksrt-ban-modal .author-set-right{margin-top:0;}
.aksrt-ban-modal .form-radio label{display:inline-block;margin:0 6px 6px 0;}
.aksrt-ban-modal .form-radio input[type=radio]{display:none;}
.aksrt-ban-modal .form-radio input[type=radio]+span{display:inline-block;padding:4px 10px;border:1px solid #dcdcde;border-radius:4px;background:#f6f7f7;cursor:pointer;}
.aksrt-ban-modal .form-radio input[type=radio]:checked+span{background:#2271b1;border-color:#2271b1;color:#fff;}
.aksrt-ban-modal .but-average.modal-buts{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:16px;max-width:480px;}
.aksrt-ban-modal .but-average.modal-buts .but{min-height:40px;text-align:center;border-radius:10px;border:1px solid #dcdcde;background:#f6f7f7;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;}
.aksrt-ban-modal .but-average.modal-buts .but.c-blue{background:#2271b1;border-color:#2271b1;color:#fff;}
.aksrt-ban-modal .but-average.modal-buts .but.c-yellow{background:#dba617;border-color:#dba617;color:#fff;}
.aksrt-ban-modal .switch-row{display:flex;align-items:center;margin:0 0 14px;font-weight:400;}
.aksrt-ban-modal .switch-row .switch-title{color:#777;margin-bottom:3px;}
.aksrt-ban-modal .switch-row .switch-help{color:#a7aaad;font-size:12px;}
.aksrt-ban-modal textarea,.aksrt-ban-modal input[type=text]{width:100%;max-width:560px;}
</style>';
// 当前生效中的全局禁封(ban 优先于 suspend,对齐参考主题单一状态语义)
$current = null;
if ($target_id > 0) {
$restrictions = $svc->get_user_restrictions($target_id, true);
foreach ($restrictions as $r) {
if (($r['scope'] ?? '') !== 'global' || !in_array($r['type'], ['ban', 'suspend'], true)) {
continue;
}
if ($current === null || ($r['type'] === 'ban' && $current['type'] !== 'ban')) {
$current = $r;
}
}
// 禁言解除视图:记录列表“解除禁言”进入(无更重的 ban/suspend 时生效)。
if ($unban && $current === null) {
foreach ($restrictions as $r) {
if (($r['type'] ?? '') === 'mute') {
$current = $r;
break;
}
}
}
}
echo '<div class="table-box aksrt-ban-modal" style="max-width:760px;padding:12px 16px;">';
if (!$target) {
echo '<p>' . esc_html__('请先通过“用户 ID”定位要禁封或解封的用户(也可从工单列表的“点击此处”进入)。', 'aksrt') . '</p>';
} elseif ($current !== null) {
// —— 已禁封视图(参考主题解封弹窗同构):状态信息 + 解封留言表单 ——
$unban_titles = [
'ban' => __('解封用户', 'aksrt'),
'suspend' => __('移出小黑屋', 'aksrt'),
'mute' => __('解除禁言', 'aksrt'),
];
$status_texts = [
'ban' => __('禁封中(禁止登录)', 'aksrt'),
'suspend' => __('小黑屋禁封中', 'aksrt'),
'mute' => __('禁言中', 'aksrt'),
];
$cur_type = (string) ($current['type'] ?? 'ban');
$unban_title = $unban_titles[$cur_type] ?? $unban_titles['ban'];
$status_text = $status_texts[$cur_type] ?? $status_texts['ban'];
$end_time = !empty($current['expires_at']) ? (string) $current['expires_at'] : __('永久', 'aksrt');
echo '<h2 style="margin-top:0;">' . esc_html($unban_title) . '</h2>';
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('用户', 'aksrt') . '</div><div class="author-set-right">' . esc_html($target->display_name) . '</div></div>';
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('状态', 'aksrt') . '</div><div class="author-set-right">' . esc_html($status_text) . '</div></div>';
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('开始时间', 'aksrt') . '</div><div class="author-set-right">' . esc_html((string) ($current['created_at'] ?? '')) . '</div></div>';
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('结束时间', 'aksrt') . '</div><div class="author-set-right">' . esc_html($end_time) . '</div></div>';
echo '<div class="mb10 flex"><div class="author-set-left">' . esc_html__('原因', 'aksrt') . '</div><div class="author-set-right">' . nl2br(esc_html((string) ($current['reason'] ?? ''))) . '</div></div>';
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
echo '<input type="hidden" name="action" value="aksrt_users_remove_restriction" />';
echo '<input type="hidden" name="user_id" value="' . esc_attr((string) $target_id) . '" />';
wp_nonce_field('aksrt_users_unban_' . $target_id);
echo '<p><textarea class="large-text" name="desc" rows="2" placeholder="' . esc_attr__('给用户的留言', 'aksrt') . '"></textarea></p>';
echo '<div class="but-average modal-buts">';
echo '<a class="but" href="' . esc_url($page_url) . '">' . esc_html__('取消', 'aksrt') . '</a>';
echo '<button type="submit" class="but c-yellow">' . esc_html(sprintf(__('确认%s', 'aksrt'), $unban_title)) . '</button>';
echo '</div>';
echo '</form>';
} else {
// —— 禁封表单(参考主题禁封弹窗同构) ——
echo '<h2 style="margin-top:0;">' . esc_html__('禁封用户', 'aksrt') . '</h2>';
echo '<form class="aksrt-ban-form" method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
echo '<input type="hidden" name="action" value="aksrt_users_add_restriction" />';
echo '<input type="hidden" name="user_id" value="' . esc_attr((string) $target_id) . '" />';
wp_nonce_field('aksrt_users_add_restriction');
echo '<div class="mt10 mb20 flex ac mb6">' . get_avatar($target_id, 40, '', '', ['class' => 'avatar-mini mr6']) . '<b>' . esc_html($target->display_name) . '</b></div>';
// 禁封方式
echo '<div class="mb6 muted-2-color">' . esc_html__('禁封方式', 'aksrt') . '</div>';
echo '<div class="form-radio form-but-radio">';
echo '<label><input type="radio" name="ban" value="1" checked="checked"><span class="p2-10 mr6">' . esc_html__('拉入小黑屋', 'aksrt') . '</span></label>';
echo '<label><input type="radio" name="ban" value="2"><span class="p2-10 mr6">' . esc_html__('禁封用户', 'aksrt') . '</span></label>';
echo '</div>';
echo '<div class="em09 c-red opacity8 mb10">';
echo '<div data-aksrt-ban-desc="1">' . esc_html__('将用户拉入小黑屋后,用户将失去所有的发布权限及大部分的操作权限,例如发帖、评论等', 'aksrt') . '</div>';
echo '<div data-aksrt-ban-desc="2" style="display:none;">' . esc_html__('禁封的用户将不能登录', 'aksrt') . '</div>';
echo '</div>';
// 禁封时间
echo '<div class="mb6 muted-2-color">' . esc_html__('禁封时间', 'aksrt') . '</div>';
echo '<div class="form-radio mb10 form-but-radio">';
foreach ([1 => __('1天', 'aksrt'), 7 => __('7天', 'aksrt'), 14 => __('14天', 'aksrt'), 30 => __('30天', 'aksrt'), 100 => __('100天', 'aksrt'), 0 => __('永久', 'aksrt')] as $days => $label) {
echo '<label><input type="radio" name="time_day" value="' . esc_attr((string) $days) . '"' . checked(7, $days, false) . '><span class="p2-10 mr6">' . esc_html($label) . '</span></label>';
}
echo '</div>';
// 选择禁封原因(预置原因 + 其它原因)
echo '<div class="mb6 muted-2-color">' . esc_html__('选择禁封原因', 'aksrt') . '</div>';
echo '<div class="form-radio mb10 form-but-radio">';
foreach (\AKSRT\Settings\UserRuntime::ban_settings()['reasons'] ?? [] as $reason) {
echo '<label><input type="radio" name="reason" value="' . esc_attr($reason['name']) . '"><span class="p2-10 mr6">' . esc_html($reason['name']) . '</span></label>';
}
echo '<label><input type="radio" name="reason" value="other"><span class="p2-10 mr6">' . esc_html__('其它原因', 'aksrt') . '</span></label>';
echo '</div>';
echo '<div class="aksrt-reason-other mb20" style="display:none;"><input type="text" class="regular-text" name="reason_other" placeholder="' . esc_attr__('请填写禁封原因', 'aksrt') . '"></div>';
// 禁封说明
echo '<div class="mb6 muted-2-color">' . esc_html__('禁封说明', 'aksrt') . '</div>';
echo '<p><textarea class="large-text" name="desc" rows="2" placeholder="' . esc_attr__('请输入禁封说明或给用户的留言', 'aksrt') . '"></textarea></p>';
// 删除全部内容
echo '<div class="switch-row"><label><input type="checkbox" name="delete_content" value="1"> <span class="flex1 mr20"><span class="switch-title">' . esc_html__('删除全部内容', 'aksrt') . '</span><br><span class="switch-help">' . esc_html__('将该用户发布的全部文章、帖子、评论移至回收站', 'aksrt') . '</span></span></label></div>';
// 禁止用户申诉
echo '<div class="switch-row"><label><input type="checkbox" name="no_appeal" value="1"> <span class="flex1 mr20"><span class="switch-title">' . esc_html__('禁止用户申诉', 'aksrt') . '</span><br><span class="switch-help">' . esc_html__('开启后用户将无法进行申诉', 'aksrt') . '</span></span></label></div>';
echo '<div class="aksrt-no-appeal-desc mb20" style="display:none;"><textarea class="large-text" name="no_appeal_desc" rows="2" placeholder="' . esc_attr__('请填写禁止申诉说明', 'aksrt') . '"></textarea></div>';
echo '<div class="but-average modal-buts">';
echo '<a class="but" href="' . esc_url($page_url) . '">' . esc_html__('取消', 'aksrt') . '</a>';
echo '<button type="submit" class="but c-blue">' . esc_html__('确认提交', 'aksrt') . '</button>';
echo '</div>';
echo '</form>';
}
echo '</div>';
// —— 限制记录列表(参考主题列语义:状态/开始/结束/原因) ——
global $wpdb;
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('user_restriction') : '';
if ($table === '') {
echo '<div class="notice notice-warning"><p>' . esc_html__('限制表不可用。', 'aksrt') . '</p></div>';
return;
}
$items = $wpdb->get_results("SELECT * FROM {$table} ORDER BY id DESC LIMIT 100", ARRAY_A);
$now = gmdate('Y-m-d H:i:s');
echo '<h2>' . esc_html__('限制记录', 'aksrt') . '</h2>';
echo '<table class="wp-list-table widefat fixed striped"><thead><tr>';
echo '<th>' . esc_html__('用户', 'aksrt') . '</th><th>' . esc_html__('禁封状态', 'aksrt') . '</th><th>' . esc_html__('开始时间', 'aksrt') . '</th><th>' . esc_html__('结束时间', 'aksrt') . '</th><th>' . esc_html__('原因', 'aksrt') . '</th><th>' . esc_html__('操作', 'aksrt') . '</th>';
echo '</tr></thead><tbody>';
if (!$items) {
echo '<tr><td colspan="6">' . esc_html__('暂无限制记录', 'aksrt') . '</td></tr>';
}
foreach ((array) $items as $r) {
$type = (string) ($r['type'] ?? '');
$expired = !empty($r['expires_at']) && (string) $r['expires_at'] <= $now;
$is_global = ($r['scope'] ?? '') === 'global' && in_array($type, ['ban', 'suspend'], true);
if ($expired) {
$status_html = '<span style="color:#a7aaad;">' . esc_html__('已过期', 'aksrt') . '</span>';
} elseif ($type === 'ban') {
$status_html = '<span style="color:#fb4444;">' . esc_html__('禁封中(禁止登录)', 'aksrt') . '</span>';
} elseif ($type === 'suspend') {
$status_html = '<span style="color:#fd6a11;">' . esc_html__('小黑屋禁封中', 'aksrt') . '</span>';
} elseif ($type === 'mute') {
$status_html = '<span style="color:#fd6a11;">' . esc_html__('禁言中', 'aksrt') . '</span>';
} else {
$status_html = '<span>' . esc_html__('警告', 'aksrt') . '</span>';
}
$r_user_id = (int) ($r['user_id'] ?? 0);
$r_user = $r_user_id > 0 ? get_userdata($r_user_id) : null;
echo '<tr>';
echo '<td>' . ($r_user ? esc_html($r_user->display_name) : esc_html((string) $r_user_id)) . '</td>';
echo '<td>' . $status_html . '</td>';
echo '<td>' . esc_html((string) ($r['created_at'] ?? '')) . '</td>';
echo '<td>' . esc_html(!empty($r['expires_at']) ? (string) $r['expires_at'] : __('永久', 'aksrt')) . '</td>';
echo '<td>' . nl2br(esc_html((string) ($r['reason'] ?? ''))) . '</td>';
echo '<td>';
if (!$expired && $is_global) {
echo '<a class="button" href="' . esc_url(add_query_arg(['action' => 'unban', 'user_id' => $r_user_id], $page_url)) . '">' . esc_html(($type === 'ban' ? __('解封', 'aksrt') : __('移出小黑屋', 'aksrt'))) . '</a>';
} elseif (!$expired && $type === 'mute') {
echo '<a class="button" href="' . esc_url(add_query_arg(['action' => 'unban', 'user_id' => $r_user_id], $page_url)) . '">' . esc_html__('解除禁言', 'aksrt') . '</a>';
}
echo '</td></tr>';
}
echo '</tbody></table>';
// 依赖联动(参考主题 dependency-box 同语义):禁封方式说明/其它原因/禁止申诉说明
echo '<script>
(function ($) {
function syncBanForm() {
$(".aksrt-ban-modal").each(function () {
var $box = $(this);
var ban = $box.find("input[name=\\"ban\\"]:checked").val();
$box.find("[data-aksrt-ban-desc]").each(function () {
$(this).toggle($(this).attr("data-aksrt-ban-desc") === ban);
});
$box.find(".aksrt-reason-other").toggle($box.find("input[name=\\"reason\\"]:checked").val() === "other");
$box.find(".aksrt-no-appeal-desc").toggle($box.find("input[name=\\"no_appeal\\"]").is(":checked"));
});
}
$(document).on("change", ".aksrt-ban-modal input", syncBanForm);
$(document).ready(syncBanForm);
})(jQuery);
</script>';
}
public function handle_update_report(): void {
if (!current_user_can(self::CAPABILITY)) {
@@ -541,103 +302,6 @@ class UsersMenus {
$this->redirect('aksrt_user_ban', $ok ? 'report_updated' : 'report_failed', ['tab' => 'tickets']);
}
public function handle_add_restriction(): void {
if (!current_user_can(self::CAPABILITY)) {
wp_die(esc_html__('权限不足', 'aksrt'));
}
check_admin_referer('aksrt_users_add_restriction');
$user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0;
if ($user_id <= 0 || !get_userdata($user_id)) {
$this->redirect('aksrt_user_ban', 'restriction_failed', ['tab' => 'restrictions']);
}
// 禁封方式(参考主题语义):1=拉入小黑屋(suspend) / 2=禁封用户(ban,禁止登录)
$ban = isset($_POST['ban']) ? (int) $_POST['ban'] : 1;
$type = $ban === 2 ? 'ban' : 'suspend';
$time_day = isset($_POST['time_day']) ? (int) $_POST['time_day'] : 0;
$desc = isset($_POST['desc']) ? sanitize_textarea_field((string) wp_unslash($_POST['desc'])) : '';
// 原因:预置徽章值或“其它原因”自定义文本
$reason = isset($_POST['reason']) ? sanitize_text_field((string) wp_unslash($_POST['reason'])) : '';
if ($reason === '' || $reason === 'other') {
$reason = isset($_POST['reason_other']) ? sanitize_text_field((string) wp_unslash($_POST['reason_other'])) : '';
}
if ($reason === '') {
$this->redirect('aksrt_user_ban', 'restriction_failed', ['tab' => 'restrictions', 'user_id' => $user_id]);
}
if ($desc !== '') {
$reason .= "\n" . sprintf(__('禁封说明:%s', 'aksrt'), $desc);
}
$no_appeal = !empty($_POST['no_appeal']);
$no_appeal_desc = isset($_POST['no_appeal_desc']) ? sanitize_textarea_field((string) wp_unslash($_POST['no_appeal_desc'])) : '';
if ($no_appeal && $no_appeal_desc === '') {
// 参考主题同校验:勾选禁止申诉必须填写说明
$this->redirect('aksrt_user_ban', 'restriction_failed', ['tab' => 'restrictions', 'user_id' => $user_id]);
}
$expires = $time_day > 0 ? date('Y-m-d H:i:s', strtotime('+' . $time_day . ' day', current_time('timestamp'))) : '';
$result = \AKSRT\User\Restriction::get_instance()->restrict($user_id, $type, $reason, 'global', $expires, get_current_user_id());
$ok = !empty($result['success']);
if ($ok) {
// 禁封状态变更站内信(参考主题 zib_updata_user_ban_msg 同语义)
$msg = $type === 'ban' ? __('您的账号已被禁封,将无法登录。', 'aksrt') : __('您已被拉入小黑屋,发布等相关权限已被限制。', 'aksrt');
if ($time_day > 0) {
$msg .= ' ' . sprintf(__('期限:%1$d 天,%2$s 起自动解封。', 'aksrt'), $time_day, $expires);
}
\AKSRT\Messages\Message::get_instance()->send($user_id, 'system', $msg, ['title' => __('账号限制', 'aksrt')]);
if ($no_appeal) {
update_user_meta($user_id, '_aksrt_no_appeal', [
'desc' => $no_appeal_desc,
'at' => current_time('mysql'),
]);
}
// 删除全部内容:文章/帖子/评论移至回收站(参考主题同行为)
if (!empty($_POST['delete_content'])) {
$post_ids = get_posts([
'author' => $user_id,
'post_type' => get_post_types(['public' => true]),
'post_status' => 'publish',
'numberposts' => -1,
'fields' => 'ids',
]);
foreach ($post_ids as $pid) {
wp_trash_post((int) $pid);
}
foreach (get_comments(['user_id' => $user_id, 'status' => 'approve', 'number' => 500]) as $comment) {
wp_trash_comment((int) $comment->comment_ID);
}
}
}
$this->redirect('aksrt_user_ban', $ok ? 'restriction_added' : 'restriction_failed', ['tab' => 'restrictions', 'user_id' => $user_id]);
}
public function handle_remove_restriction(): void {
if (!current_user_can(self::CAPABILITY)) {
wp_die(esc_html__('权限不足', 'aksrt'));
}
$user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0;
check_admin_referer('aksrt_users_unban_' . $user_id);
$desc = isset($_POST['desc']) ? sanitize_textarea_field((string) wp_unslash($_POST['desc'])) : '';
$removed = $user_id > 0 && class_exists('\AKSRT\User\Restriction')
? \AKSRT\User\Restriction::get_instance()->lift_user_restriction($user_id)
: 0;
delete_user_meta($user_id, '_aksrt_no_appeal');
// 解封站内信(含给用户的留言)
$msg = __('您的账号限制已解除。', 'aksrt');
if ($desc !== '') {
$msg .= ' ' . sprintf(__('留言:%s', 'aksrt'), $desc);
}
\AKSRT\Messages\Message::get_instance()->send($user_id, 'system', $msg, ['title' => __('限制解除', 'aksrt')]);
$this->redirect('aksrt_user_ban', $removed > 0 ? 'restriction_removed' : 'restriction_failed', ['tab' => 'restrictions', 'user_id' => $user_id]);
}
public function handle_process_appeal(): void {
if (!current_user_can(self::CAPABILITY)) {
wp_die(esc_html__('权限不足', 'aksrt'));
+3 -1
View File
@@ -477,7 +477,9 @@ trait UsersMenusTickets {
if (class_exists('\AKSRT\User\Restriction') && \AKSRT\User\Restriction::get_instance()->is_restricted($target_id)) {
echo $this->ticket_ban_info_html($target_id);
} else {
$ban_url = admin_url('users.php?page=aksrt_user_ban&tab=restrictions&user_id=' . $target_id);
// 与参考主题一致:跳转到前台该用户公开主页,经封面右下角三点
// 菜单的「禁封此用户」打开封禁弹窗完成处理(后台不提供禁封表单)。
$ban_url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url($target_id) : get_author_posts_url($target_id);
echo '<div style="color:#16a60a;">' . esc_html__('用户状态正常', 'aksrt') . '</div>';
echo '<p class="description">' . esc_html__('请查阅相关资料以及举证,如举报事实清楚,可以', 'aksrt');
echo ' <a target="_blank" href="' . esc_url($ban_url) . '">' . esc_html__('点击此处', 'aksrt') . '</a> ';