message; } } class WP_User { public $ID = 7; public $display_name = 'Test '; } class Redirect extends \RuntimeException {} function __($text, $domain = '') { return $text; } function esc_html($text) { return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8'); } function esc_attr($text) { return esc_html($text); } function esc_html__($text, $domain) { return esc_html($text); } function esc_attr__($text, $domain) { return esc_attr($text); } function esc_url($url) { return preg_match('/^javascript:/i', $url) ? '' : esc_attr($url); } function esc_url_raw($url) { return preg_match('/^javascript:/i', $url) ? '' : $url; } function sanitize_key($text) { return preg_replace('/[^a-z0-9_\-]/', '', strtolower($text)); } function sanitize_text_field($text) { return trim(strip_tags($text)); } function sanitize_textarea_field($text) { return trim(strip_tags($text)); } function sanitize_user($text) { return $text; } function wp_unslash($text) { return $text; } function absint($value) { return abs((int) $value); } function is_wp_error($value) { return $value instanceof WP_Error; } function is_email($value) { return filter_var($value, FILTER_VALIDATE_EMAIL); } function admin_url($path) { return 'https://example.test/wp-admin/' . $path; } function get_edit_user_link($id) { return admin_url('user-edit.php?user_id=' . $id); } function get_avatar_url($id, $args) { return 'https://example.test/avatar.png'; } function get_userdata($id) { return $id > 0 ? new WP_User() : false; } function get_user_by($key, $value) { return new WP_User(); } function cache_users($ids) { $GLOBALS['cache_calls'][] = $ids; } function number_format_i18n($count) { return number_format($count); } function human_time_diff($time) { return '1 分钟'; } function checked($actual, $expected, $echo = true) { return $actual === $expected ? ' checked' : ''; } function selected($actual, $expected, $echo = true) { return $actual === $expected ? ' selected' : ''; } function wp_nonce_field($action) { echo ''; } function check_admin_referer($action) { $GLOBALS['nonce_checked'][] = $action; } function wp_roles() { return new class { public $roles = ['subscriber' => [], 'editor' => [], 'author' => [], 'contributor' => []]; public function get_names() { return ['subscriber' => '订阅者', 'editor' => '编辑', 'author' => '作者', 'contributor' => '贡献者']; } }; } function translate_user_role($role) { return $role; } function count_users($strategy) { return ['avail_roles' => ['subscriber' => 3, 'editor' => 501, 'author' => 0, 'contributor' => 500]]; } function get_users($args) { return array_slice(range(1, $GLOBALS['role_count'] ?? 3), 0, $args['number']); } function wp_safe_redirect($url) { throw new Redirect($url); } function add_query_arg($args, $url) { return $url . '?' . http_build_query($args); } function submit_button($text, $type, $name, $wrap) { echo ''; } function current_datetime() { return new \DateTimeImmutable($GLOBALS['now'] ?? '2026-10-30 12:00:00', new \DateTimeZone($GLOBALS['zone'] ?? 'Asia/Shanghai')); } function get_gmt_from_date($local) { return (new \DateTimeImmutable($local, new \DateTimeZone($GLOBALS['zone'] ?? 'Asia/Shanghai')))->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s'); } function get_date_from_gmt($gmt, $format) { return (new \DateTimeImmutable($gmt, new \DateTimeZone('UTC')))->setTimezone(new \DateTimeZone('Asia/Shanghai'))->format($format); } function current_time($format, $gmt = false) { return '2026-10-30 04:00:00'; } class Database { public $prepared = []; public $queries = []; public function prepare($sql, ...$params) { $params = count($params) === 1 && is_array($params[0]) ? $params[0] : $params; $this->prepared[] = ['sql' => $sql, 'params' => $params]; return $sql; } public function get_var($sql) { return 2; } public function get_results($sql, $format) { return []; } public function get_row($sql, $format) { return ['total' => 2, 'unread' => 1, 'today' => 1, 'recipients' => 2]; } public function get_col($sql) { return ['system', 'asset_balance_increase', 'asset_balance_decrease', 'asset_points_increase', 'asset_points_decrease']; } public function query($sql) { $this->queries[] = $sql; return 1; } public function esc_like($text) { return addcslashes($text, '_%\\'); } } $wpdb = new Database(); require $root . '/src/Messages/MessageTypes.php'; require $root . '/src/Messages/AdminBroadcast.php'; require $root . '/src/Messages/NotificationAdminQuery.php'; require $root . '/src/Admin/Native/NativeUi.php'; require $root . '/src/Admin/Native/UsersMenusMessagesList.php'; require $root . '/src/Admin/Native/UsersMenusMessagesCompose.php'; require $root . '/src/Admin/Native/UsersMenusMessages.php'; class Probe { use \Jio\Admin\Native\UsersMenusMessages; public $cap_checked = 0; private function ensure_cap(): void { $this->cap_checked++; } public function invoke($method, ...$args) { return $this->$method(...$args); } public function html($method, ...$args) { ob_start(); $this->$method(...$args); return ob_get_clean(); } } $probe = new Probe(); $out = []; $filters = $probe->invoke('message_filters', ['period' => 'today', 'status' => 'unread', 's' => 'a%_']); $out['filters'] = $filters; $out['bad_period'] = $probe->invoke('message_filters', ['period' => 'evil']); $out['query_filters'] = $probe->invoke('message_query_filters', $filters); $out['compose'] = $probe->html('render_message_compose'); $out['dialogs'] = $probe->html('render_message_dialogs'); $out['overview'] = $probe->html('render_message_overview'); $out['filter_form'] = $probe->html('render_message_filter_form', $filters); $out['views'] = $probe->invoke('message_views_html', $filters, ['all' => 2, 'unread' => 1, 'read' => 1]); $row = ['id' => 8, 'user_id' => 7, 'type' => 'system', 'title' => '', 'description' => str_repeat('完整内容', 100) . "\n", 'target_url' => 'javascript:alert(1)', 'is_read' => 0, 'created_at' => '2026-10-30 03:00:00', 'read_at' => null]; $out['table'] = $probe->html('render_message_table', [$row, array_merge($row, ['id' => 9, 'is_read' => 1, 'read_at' => '2026-10-30 03:30:00'])], $filters, 3, false); $out['empty'] = $probe->html('render_message_table', [], $filters, 1, false); $out['cache_calls'] = $GLOBALS['cache_calls']; $out['asset_table'] = $probe->html('render_message_table', [array_merge($row, ['type' => 'asset_balance_increase'])], $filters, 1, false); foreach (['asset_balance_increase', 'asset_balance_decrease', 'asset_points_increase', 'asset_points_decrease'] as $type) { $out['asset_types'][$type] = [\Jio\Messages\MessageTypes::label($type), \Jio\Messages\MessageTypes::tone($type)]; } $wpdb->prepared = []; \Jio\Messages\NotificationAdminQuery::paginate($out['query_filters'], 1); \Jio\Messages\NotificationAdminQuery::status_counts($out['query_filters']); \Jio\Messages\NotificationAdminQuery::overview(); $out['sql'] = $wpdb->prepared; $GLOBALS['zone'] = 'America/New_York'; $GLOBALS['now'] = '2026-11-01 12:00:00'; $wpdb->prepared = []; \Jio\Messages\NotificationAdminQuery::overview(); $out['dst_sql'] = $wpdb->prepared; $base = ['recipient_mode' => 'role', 'role' => 'subscriber', 'content' => 'Hello', 'title' => 'Title']; $cases = [ 'unconfirmed' => $base, 'changed_count' => $base + ['confirmed_role' => 'subscriber', 'confirmed_count' => 2], 'changed_role' => $base + ['confirmed_role' => 'editor', 'confirmed_count' => 3], 'confirmed' => $base + ['confirmed_role' => 'subscriber', 'confirmed_count' => 3], 'too_large' => $base + ['confirmed_role' => 'subscriber', 'confirmed_count' => 501], 'users' => ['recipient_mode' => 'users', 'users' => '7', 'content' => 'Hello'], 'long_title' => array_merge($base, ['title' => str_repeat('字', 192)]), ]; foreach ($cases as $name => $post) { $_POST = $post; $GLOBALS['role_count'] = $name === 'too_large' ? 501 : 3; \Jio\Messages\Message::$sent = []; try { $probe->handle_send_message(); } catch (Redirect $redirect) { parse_str(parse_url($redirect->getMessage(), PHP_URL_QUERY), $query); $out['send'][$name] = ['redirect' => $query, 'sent' => count(\Jio\Messages\Message::$sent)]; } } $_POST = ['bulk_action' => 'delete', 'message_id' => 8, 'ids' => [9, 10], 'period' => 'today', 'status' => 'unread', 'paged' => 3]; $wpdb->prepared = []; try { $probe->handle_bulk_messages(); } catch (Redirect $redirect) { parse_str(parse_url($redirect->getMessage(), PHP_URL_QUERY), $query); $out['single_delete'] = ['redirect' => $query, 'sql' => $wpdb->prepared]; } $out['cap_checked'] = $probe->cap_checked; $out['nonce_checked'] = $GLOBALS['nonce_checked']; echo json_encode($out, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); }