diff --git a/assets/css/admin/native-ui.css b/assets/css/admin/native-ui.css index 6e46b34f..a9788f1a 100644 --- a/assets/css/admin/native-ui.css +++ b/assets/css/admin/native-ui.css @@ -486,15 +486,6 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone) .aksrt-native-text--info { color: var(--an-info); } .aksrt-native-text--warning { color: #c27c0e; } .aksrt-native-text--danger { color: var(--an-danger); } -.aksrt-native-clamp { max-height: 40px; overflow: hidden; } -/* 举报&禁封申诉页:宽表 + 排序箭头 */ -.aksrt-native-ban .aksrt-native-table-wrap > table { min-width: 1000px; } -.aksrt-native-ban .orderby-but { position: relative; display: inline-block; width: 0; height: 0; margin-left: 4px; } -.aksrt-native-ban .orderby-but > a { position: absolute; left: 0; bottom: .725em; padding-right: 1em; opacity: .4; transform: translateY(50%); transition: opacity .3s; } -.aksrt-native-ban .orderby-but > a + a { bottom: .075em; } -.aksrt-native-ban .orderby-but > a:hover { opacity: 1; } -.aksrt-native-ban .aksrt-native-toolbar + .subsubsub { float: none; margin: 10px 0 0; } -.aksrt-native-ban textarea { width: 95%; max-width: 500px; } .aksrt-native-amount { color: var(--an-text); font-weight: 600; font-variant-numeric: tabular-nums; } .aksrt-native-amount.is-positive { color: var(--an-primary); } .aksrt-native-amount.is-negative { color: var(--an-danger); } diff --git a/assets/css/admin/user-ban.css b/assets/css/admin/user-ban.css new file mode 100644 index 00000000..3f13515a --- /dev/null +++ b/assets/css/admin/user-ban.css @@ -0,0 +1,125 @@ +/* 举报与禁封申诉运营页。继承 native-ui.css 的后台颜色与表单令牌。 */ +.aksrt-ban-page [hidden], +.aksrt-ban-dialog [hidden] { display: none !important; } + +.aksrt-ban-toolbar { padding: 14px 20px; border-bottom: 1px solid var(--an-border-soft); } +.aksrt-ban-toolbar__top, +.aksrt-ban-toolbar__bottom { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 18px; } +.aksrt-ban-toolbar__bottom { margin-top: 14px; } +.aksrt-ban-types { display: inline-flex; flex-wrap: wrap; gap: 4px; padding: 3px; background: var(--an-bg-soft); border-radius: var(--an-radius-sm); } +.aksrt-ban-types a { padding: 6px 12px; color: var(--an-text-2); border-radius: 5px; text-decoration: none; } +.aksrt-ban-types a:hover { color: var(--an-primary); } +.aksrt-ban-types a[aria-current="page"] { color: var(--an-primary); background: var(--an-card); box-shadow: 0 1px 3px rgba(15, 23, 42, .08); font-weight: 600; } +.aksrt-ban-toolbar .subsubsub { margin: 0; padding: 0; box-shadow: none; } +.aksrt-ban-toolbar .aksrt-native-filters { margin: 0; } +.aksrt-ban-toolbar .aksrt-native-filters input[type="search"] { min-width: 240px; } +.aksrt-ban-filter-hint { margin: 12px 0 0; color: var(--an-text-2); font-size: 12px; } + +.aksrt-ban-page .aksrt-ban-table { min-width: 1160px; table-layout: fixed; } +.aksrt-ban-table .column-type { width: 11%; } +.aksrt-ban-table .column-user { width: 16%; } +.aksrt-ban-table .column-summary { width: 27%; } +.aksrt-ban-table .column-status { width: 10%; } +.aksrt-ban-table .column-time, +.aksrt-ban-table .column-updated { width: 13%; } +.aksrt-ban-table .column-actions { width: 10%; } +.aksrt-ban-page .aksrt-ban-table td { overflow-wrap: anywhere; } +.aksrt-ban-sort { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; } +.aksrt-ban-sort span { font-size: 14px; } +.aksrt-ban-page .aksrt-ban-table th[aria-sort] a, +.aksrt-ban-page .aksrt-ban-table th a:hover { color: var(--an-primary); } +.aksrt-ban-sub { margin-top: 5px; color: var(--an-text-2); font-size: 12px; line-height: 1.6; } +.aksrt-ban-summary { display: -webkit-box; max-height: 3.1em; margin-top: 5px; color: var(--an-text-2); line-height: 1.55; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } +.aksrt-ban-user-filter { display: inline-block; margin: 5px 0 0 36px; font-size: 12px; } +.aksrt-ban-table .column-actions .button { white-space: nowrap; } +.aksrt-ban-page :is(a, button, input):focus-visible, +.aksrt-ban-dialog :is(a, button, input, textarea):focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; } + +html.aksrt-ban-modal-open { overflow: hidden; scrollbar-gutter: stable; } +.aksrt-ban-dialog { + width: min(780px, calc(100vw - 32px)); + max-width: none; + max-height: calc(100vh - 40px); + max-height: calc(100dvh - 40px); + margin: auto; + padding: 0; + overflow: hidden; + color: var(--an-text-2); + background: var(--an-card); + border: 1px solid var(--an-border); + border-radius: var(--an-radius); + box-shadow: var(--an-shadow-hover); +} +.aksrt-ban-dialog::backdrop { background: rgba(15, 23, 42, .45); } +.aksrt-ban-dialog__frame { display: flex; flex-direction: column; min-height: 0; max-height: inherit; margin: 0; } +.aksrt-ban-dialog__head { display: flex; flex: none; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 19px 24px 17px; border-bottom: 1px solid var(--an-border-soft); } +.aksrt-ban-dialog .aksrt-ban-dialog__head h2 { margin: 0; padding: 0; color: var(--an-text); font-size: 18px; font-weight: 600; line-height: 1.45; } +.aksrt-ban-dialog__head p { max-width: 52ch; margin: 5px 0 0; font-size: 13px; line-height: 1.6; } +.aksrt-ban-dialog__close { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; color: var(--an-text-2); background: transparent; border: 0; border-radius: var(--an-radius-sm); cursor: pointer; } +.aksrt-ban-dialog__close:hover { color: var(--an-text); background: var(--an-bg-soft); } +.aksrt-ban-dialog__body { min-height: 0; padding: 20px 24px; overflow-y: auto; overscroll-behavior: contain; } +.aksrt-ban-dialog__foot { display: flex; flex: none; justify-content: flex-end; gap: 8px; padding: 14px 24px; background: var(--an-card); border-top: 1px solid var(--an-border-soft); } +.aksrt-ban-dialog__foot .button { min-width: 120px; } +.aksrt-ban-dialog .aksrt-ban-dialog__foot .button.is-danger { color: var(--an-card); background: var(--an-danger); border-color: var(--an-danger); } +.aksrt-ban-dialog .button:disabled, +.aksrt-ban-dialog__close:disabled { opacity: .65; cursor: not-allowed; } + +.aksrt-ban-applicant { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; margin-bottom: 18px; } +.aksrt-ban-meta { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px 18px; margin: 0; padding: 14px 16px; background: var(--an-bg-soft); border-radius: var(--an-radius-sm); } +.aksrt-ban-meta > div, +.aksrt-ban-materials > div { min-width: 0; } +.aksrt-ban-meta dt, +.aksrt-ban-materials dt { color: var(--an-text-2); font-size: 12px; line-height: 1.6; } +.aksrt-ban-meta dd, +.aksrt-ban-materials dd { margin: 3px 0 0; color: var(--an-text); white-space: pre-wrap; overflow-wrap: anywhere; } +.aksrt-ban-section { margin-top: 20px; } +.aksrt-ban-dialog .aksrt-ban-section h3, +.aksrt-ban-dialog .aksrt-ban-review > h3 { margin: 0 0 9px; color: var(--an-text); font-size: 14px; font-weight: 600; line-height: 1.5; } +.aksrt-ban-copy { color: var(--an-text-2); line-height: 1.75; white-space: pre-wrap; overflow-wrap: anywhere; } +.aksrt-ban-target { color: var(--an-text); font-weight: 600; overflow-wrap: anywhere; } +.aksrt-ban-materials { display: grid; gap: 12px; margin: 0; padding-left: 14px; border-left: 2px solid var(--an-border); } +.aksrt-ban-restrictions { display: grid; gap: 10px; margin: 0; padding: 0; list-style: none; } +.aksrt-ban-restrictions li { margin: 0; padding: 12px 14px; background: var(--an-bg-soft); border-radius: var(--an-radius-sm); } +.aksrt-ban-restriction__title { display: flex; align-items: center; gap: 10px; margin-bottom: 7px; font-size: 12px; } +.aksrt-ban-normal { margin: 0; color: var(--an-text-2); } +.aksrt-ban-profile-link { margin: 12px 0 18px; } +.aksrt-ban-history { margin: 0; padding-left: 14px; list-style: none; border-left: 2px solid var(--an-border); } +.aksrt-ban-history li { margin: 0 0 14px; } +.aksrt-ban-history li:last-child { margin-bottom: 0; } +.aksrt-ban-history__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin-bottom: 5px; font-size: 12px; } +.aksrt-ban-history__meta strong { color: var(--an-text); } +.aksrt-ban-dialog__body > .aksrt-native-callout { margin-top: 18px; } + +.aksrt-ban-review { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--an-border); } +.aksrt-ban-decisions { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 16px; padding: 0; border: 0; } +.aksrt-ban-decisions legend { width: 100%; margin-bottom: 8px; padding: 0; color: var(--an-text); font-weight: 600; } +.aksrt-ban-decisions label { position: relative; flex: 1 1 180px; cursor: pointer; } +.aksrt-ban-decisions input[type="radio"] { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); } +.aksrt-ban-decisions label > span { display: flex; align-items: center; min-height: 42px; padding: 9px 12px; color: var(--an-text-2); background: var(--an-card); border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); } +.aksrt-ban-decisions label:hover > span { border-color: var(--an-primary); } +.aksrt-ban-decisions input:checked + span { color: var(--an-primary); background: var(--an-primary-soft); border-color: var(--an-primary); font-weight: 600; } +.aksrt-ban-decisions input:focus-visible + span { outline: 2px solid var(--an-primary); outline-offset: 2px; } +.aksrt-ban-review textarea { resize: vertical; } +.aksrt-ban-review .aksrt-native-field__hint { margin-bottom: 0; color: var(--an-text-2); } + +@media (max-width: 782px) { + .aksrt-ban-toolbar { padding: 12px 14px; } + .aksrt-ban-toolbar__top, + .aksrt-ban-toolbar__bottom { align-items: flex-start; } + .aksrt-ban-toolbar .aksrt-native-filters { width: 100%; } + .aksrt-ban-toolbar .aksrt-native-filters input[type="search"] { min-width: 0; flex: 1 1 220px; } +} +@media (max-width: 600px) { + .aksrt-ban-dialog { width: calc(100vw - 24px); max-height: calc(100dvh - 24px); } + .aksrt-ban-dialog__head, + .aksrt-ban-dialog__body, + .aksrt-ban-dialog__foot { padding-left: 16px; padding-right: 16px; } + .aksrt-ban-meta { grid-template-columns: 1fr; gap: 10px; } + .aksrt-ban-decisions { flex-direction: column; } + .aksrt-ban-decisions label { flex-basis: auto; } + .aksrt-ban-dialog__foot .button { flex: 1; min-width: 0; } +} +@media (prefers-reduced-motion: reduce) { + .aksrt-ban-page *, + .aksrt-ban-dialog * { transition: none !important; } +} diff --git a/assets/js/admin-user-ban.js b/assets/js/admin-user-ban.js new file mode 100644 index 00000000..f724f5f1 --- /dev/null +++ b/assets/js/admin-user-ban.js @@ -0,0 +1,139 @@ +/** 举报与禁封申诉审核。仅在对应 native 后台页入队。 */ +(function () { + 'use strict'; + + var root = document.querySelector('.aksrt-ban-page'); + var dialog = document.getElementById('aksrt-ban-dialog'); + if (!root || !dialog || typeof dialog.showModal !== 'function') return; + + var opener = null; + var activeForm = null; + var submitting = false; + var pointerStartedOutside = false; + + function lockScroll() { + document.documentElement.classList.toggle('aksrt-ban-modal-open', !!dialog.open); + } + + function attribute(element, name) { + return element ? element.getAttribute(name) || '' : ''; + } + + function selectedDecision(form) { + var radios = form.querySelectorAll('input[type="radio"]'); + for (var index = 0; index < radios.length; index += 1) { + if (radios[index].checked) return radios[index].value; + } + return ''; + } + + function syncReview(form) { + if (submitting) return; + var decision = selectedDecision(form); + var rejected = decision === 'reject' || decision === 'dismissed'; + var note = form.querySelector('textarea[name="note"]'); + var label = form.querySelector('[data-aksrt-ban-note-label]'); + var submit = form.querySelector('[data-aksrt-ban-submit]'); + if (note) { + note.required = rejected; + note.setCustomValidity(rejected && !note.value.trim() ? attribute(note, 'data-required-error') : ''); + } + if (label) label.textContent = attribute(label, rejected ? 'data-required' : 'data-optional'); + if (submit) { + submit.disabled = !decision; + submit.textContent = attribute(submit, decision ? (rejected ? 'data-reject-label' : 'data-approve-label') : 'data-idle-label'); + submit.classList.toggle('is-danger', rejected); + } + } + + function setActionsDisabled(disabled) { + dialog.querySelectorAll('[data-aksrt-ban-submit], [data-aksrt-dialog-close]').forEach(function (button) { + button.disabled = disabled; + }); + } + + function setupReview(form) { + form.querySelectorAll('input[type="radio"]').forEach(function (radio) { radio.checked = false; }); + var note = form.querySelector('textarea[name="note"]'); + if (note) note.value = ''; + syncReview(form); + form.addEventListener('input', function () { syncReview(form); }); + form.addEventListener('change', function () { syncReview(form); }); + form.addEventListener('submit', function (event) { + if (submitting || form.dataset.submitting === '1') { + event.preventDefault(); + return; + } + syncReview(form); + if (!selectedDecision(form) || !form.reportValidity()) { + event.preventDefault(); + return; + } + submitting = true; + form.dataset.submitting = '1'; + form.setAttribute('aria-busy', 'true'); + setActionsDisabled(true); + var submit = form.querySelector('[data-aksrt-ban-submit]'); + if (submit) submit.textContent = attribute(submit, 'data-busy-label'); + }); + } + + root.querySelectorAll('[data-aksrt-ban-view]').forEach(function (button) { + button.addEventListener('click', function (event) { + event.preventDefault(); + if (submitting || dialog.open) return; + var template = document.getElementById('aksrt-ban-detail-' + attribute(button, 'data-aksrt-ban-view')); + if (!template || !template.content) return; + dialog.replaceChildren(template.content.cloneNode(true)); + opener = button; + pointerStartedOutside = false; + activeForm = dialog.querySelector('form[data-aksrt-ban-review]'); + if (activeForm) setupReview(activeForm); + dialog.showModal(); + lockScroll(); + }); + }); + + function isOutside(event) { + var rect = dialog.getBoundingClientRect(); + return event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom; + } + + dialog.addEventListener('pointerdown', function (event) { + pointerStartedOutside = event.target === dialog && isOutside(event); + }); + dialog.addEventListener('pointercancel', function () { pointerStartedOutside = false; }); + dialog.addEventListener('click', function (event) { + var close = event.target.closest('[data-aksrt-dialog-close]'); + if (close || (pointerStartedOutside && event.target === dialog && isOutside(event))) { + event.preventDefault(); + if (!submitting) dialog.close(); + } + pointerStartedOutside = false; + }); + dialog.addEventListener('cancel', function (event) { + event.preventDefault(); + if (!submitting) dialog.close(); + }); + dialog.addEventListener('close', function () { + dialog.replaceChildren(); + activeForm = null; + submitting = false; + pointerStartedOutside = false; + lockScroll(); + var previousOpener = opener; + opener = null; + if (previousOpener && previousOpener.isConnected) previousOpener.focus(); + }); + + window.addEventListener('pageshow', function () { + submitting = false; + if (activeForm) { + delete activeForm.dataset.submitting; + activeForm.removeAttribute('aria-busy'); + setActionsDisabled(false); + syncReview(activeForm); + } + lockScroll(); + }); +})(); diff --git a/src/Admin/Native/UsersMenus.php b/src/Admin/Native/UsersMenus.php index 13a651ce..6e28e8b3 100644 --- a/src/Admin/Native/UsersMenus.php +++ b/src/Admin/Native/UsersMenus.php @@ -12,7 +12,7 @@ class UsersMenus { use UsersMenusVerify; use UsersMenusVip; use UsersMenusInviteCode; - use UsersMenusTickets; + use UsersMenusBan; use UsersMenusTicketsCenter; use UsersMenusMessages; @@ -47,6 +47,7 @@ class UsersMenus { add_action('admin_enqueue_scripts', [$this, 'enqueue_message_assets']); add_action('admin_enqueue_scripts', [$this, 'enqueue_invite_assets']); add_action('admin_enqueue_scripts', [$this, 'enqueue_verify_assets']); + add_action('admin_enqueue_scripts', [$this, 'enqueue_ban_assets']); add_action('admin_enqueue_scripts', [$this, 'enqueue_vip_assets']); } @@ -202,6 +203,9 @@ class UsersMenus { if ($code === 'verify_failed' && isset($_GET['aksrt_verify_error'])) { $message = sanitize_text_field((string) wp_unslash($_GET['aksrt_verify_error'])); } + if (in_array($code, ['report_failed', 'appeal_failed'], true) && isset($_GET['aksrt_ban_error'])) { + $message = sanitize_text_field((string) wp_unslash($_GET['aksrt_ban_error'])); + } if ($code === 'vip_failed' && isset($_GET['aksrt_vip_error'])) { $message = sanitize_text_field((string) wp_unslash($_GET['aksrt_vip_error'])); } @@ -221,101 +225,6 @@ class UsersMenus { exit; } - /* ------------------------------------------------------------------ - * Ban / reports - * ----------------------------------------------------------------*/ - - public function render_ban_page(): void { - $this->ensure_cap(); - NativeUi::page_open('aksrt-native-ban'); - NativeUi::header( - __('用户禁封申诉及用户举报管理', 'aksrt'), - __('处理用户举报与禁封申诉工单。禁封 / 解封操作在前台封禁弹窗完成。', 'aksrt'), - 'dashicons-shield' - ); - $this->flash(); - - // 与参考主题一致:后台仅承载「申诉&举报」工单处理;禁封/解封操作 - // 全部在前台完成(用户主页封面 / 评论区 / 文章作者栏三点菜单 → - // 封禁弹窗,REST /user-ban/modal + /user-ban/set)。 - // render_tickets_tab() 自带筛选控件 + 表格 + 分页,直接交给 .aksrt-native - // 作用域下的共享样式(.subsubsub / .widefat / .button / .tablenav)接管。 - $this->render_tickets_tab(); - - NativeUi::page_close(); - } - - - public function handle_update_report(): void { - if (!current_user_can(self::CAPABILITY)) { - wp_die(esc_html__('权限不足', 'aksrt')); - } - $id = isset($_POST['report_id']) ? (int) $_POST['report_id'] : 0; - $new_status = isset($_POST['new_status']) ? sanitize_key((string) wp_unslash($_POST['new_status'])) : ''; - $note = isset($_POST['note']) ? sanitize_textarea_field((string) wp_unslash($_POST['note'])) : ''; - check_admin_referer('aksrt_users_update_report_' . $id); - $ok = $id > 0 && class_exists('\AKSRT\Messages\ReportCenter') && \AKSRT\Messages\ReportCenter::get_instance()->update_status($id, $new_status, $note); - $this->redirect('aksrt_user_ban', $ok ? 'report_updated' : 'report_failed', ['tab' => 'tickets']); - } - - public function handle_process_appeal(): void { - if (!current_user_can(self::CAPABILITY)) { - wp_die(esc_html__('权限不足', 'aksrt')); - } - $user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0; - $decision = isset($_POST['decision']) ? sanitize_key((string) wp_unslash($_POST['decision'])) : ''; - $note = isset($_POST['note']) ? sanitize_textarea_field((string) wp_unslash($_POST['note'])) : ''; - check_admin_referer('aksrt_users_process_appeal_' . $user_id); - - if ($user_id <= 0 || !in_array($decision, ['approve', 'reject'], true) || !class_exists('\AKSRT\User\BanAppeal')) { - $this->redirect('aksrt_user_ban', 'appeal_failed', ['tab' => 'tickets', 'type' => 'appeal']); - } - - $status = $decision === 'approve' ? 'approved' : 'rejected'; - update_user_meta($user_id, \AKSRT\User\BanAppeal::META_STATUS, $status); - - $payload = \AKSRT\User\BanAppeal::get_payload($user_id); - $payload['admin_note'] = $note; - $payload['handled_at'] = current_time('Y-m-d H:i'); - $payload['handled_by'] = get_current_user_id(); - $payload['decision'] = $status; - update_user_meta($user_id, \AKSRT\User\BanAppeal::META_PAYLOAD, $payload); - - $history = get_user_meta($user_id, \AKSRT\User\BanAppeal::META_HISTORY, true); - $history = is_array($history) ? $history : []; - $history[] = $payload; - update_user_meta($user_id, \AKSRT\User\BanAppeal::META_HISTORY, array_slice($history, -30)); - - if ($decision === 'approve' && class_exists('\AKSRT\User\Restriction')) { - \AKSRT\User\Restriction::get_instance()->lift_user_restriction($user_id); - } - - if (class_exists('\AKSRT\Messages\Message')) { - $msg = $decision === 'approve' - ? __('你的禁封申诉已通过,限制已解除。', 'aksrt') - : __('你的禁封申诉未通过,可修改后重新提交。', 'aksrt'); - if ($note !== '') { - $msg .= ' ' . sprintf(__('备注:%s', 'aksrt'), $note); - } - \AKSRT\Messages\Message::get_instance()->send( - $user_id, - 'ban_appeal', - $msg, - [ - 'title' => $decision === 'approve' ? __('申诉通过', 'aksrt') : __('申诉驳回', 'aksrt'), - ] - ); - } - - do_action('aksrt_ban_appeal_processed', $user_id, $decision, $note); - - $this->redirect( - 'aksrt_user_ban', - $decision === 'approve' ? 'appeal_approved' : 'appeal_rejected', - ['tab' => 'tickets', 'type' => 'appeal'] - ); - } - private function pagination(int $pages, int $page_num): void { if ($pages <= 1) { return; diff --git a/src/Admin/Native/UsersMenusBan.php b/src/Admin/Native/UsersMenusBan.php new file mode 100644 index 00000000..112920be --- /dev/null +++ b/src/Admin/Native/UsersMenusBan.php @@ -0,0 +1,201 @@ +ensure_cap(); + $filters = $this->get_ban_filters($_GET); + $data = $this->query_ban_requests($filters, max(1, (int) ($_GET['paged'] ?? 1))); + $this->cache_ban_targets($data['items']); + $this->load_ban_restrictions($data['items']); + NativeUi::page_open('aksrt-ban-page'); + NativeUi::header( + __('举报与禁封申诉', 'aksrt'), + __('核对举报内容与申诉资料,在审核弹窗中记录处理结果。用户禁封操作仍在前台用户主页完成。', 'aksrt'), + 'dashicons-shield' + ); + $this->flash(); + NativeUi::card_open('', '', true, 'aksrt-ban-list-card'); + $this->render_ban_filters($filters, $data['counts']); + echo '
| '; + if ($sortable) { + $order = $active && $filters['order'] === 'DESC' ? 'ASC' : 'DESC'; + $title = sprintf($order === 'ASC' ? __('按%s升序排列', 'aksrt') : __('按%s降序排列', 'aksrt'), $label); + echo '' . esc_html($label) . ''; + } else { + echo esc_html($label); + } + echo ' | '; + } + echo '
|---|