593 lines
23 KiB
PHP
593 lines
23 KiB
PHP
<?php
|
||
/**
|
||
* AKSRT User Notifications
|
||
*
|
||
* Notification CRUD, AJAX handlers, and event-driven notification creators.
|
||
*
|
||
* @package AKSRT
|
||
*/
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
if (!function_exists('aksrt_get_user_notifications')) :
|
||
/**
|
||
* 获取用户提醒列表(即时提醒,不持久化)
|
||
*
|
||
* 当前通知源:评论待审核。
|
||
*
|
||
* @param int $user_id 用户 ID,默认当前用户
|
||
* @return array<int, array{type:string,title:string,desc:string,url:string,count:int}>
|
||
*/
|
||
function aksrt_get_user_notifications(int $user_id = 0): array {
|
||
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
|
||
if ($user_id <= 0) {
|
||
return [];
|
||
}
|
||
|
||
$items = [];
|
||
|
||
$pending_comments = (int) get_comments([
|
||
'user_id' => $user_id,
|
||
'count' => true,
|
||
'status' => 'hold',
|
||
]);
|
||
|
||
if ($pending_comments > 0 && (!class_exists('\AKSRT\Settings\Settings') || \AKSRT\Settings\Settings::notification_enabled('pending_comments'))) {
|
||
$items[] = [
|
||
'type' => 'pending_comments',
|
||
'title' => __('评论待审核', 'aksrt'),
|
||
'desc' => sprintf(__('你有 %d 条评论正在等待审核。', 'aksrt'), $pending_comments),
|
||
'url' => aksrt_get_user_center_url('comments'),
|
||
'count' => $pending_comments,
|
||
];
|
||
}
|
||
|
||
return $items;
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_notification_type_label')) :
|
||
/** 通知类型中文标签 */
|
||
function aksrt_notification_type_label(string $type): string {
|
||
$map = [
|
||
'comment_reply' => __('评论回复', 'aksrt'),
|
||
'comment_approved' => __('评论审核', 'aksrt'),
|
||
'download_ready' => __('下载就绪', 'aksrt'),
|
||
'asset_points_increase' => __('积分增加', 'aksrt'),
|
||
'asset_points_decrease' => __('积分扣减', 'aksrt'),
|
||
'asset_balance_increase' => __('余额增加', 'aksrt'),
|
||
'asset_balance_decrease' => __('余额扣减', 'aksrt'),
|
||
'pending_comments' => __('待审核评论', 'aksrt'),
|
||
'notice' => __('通知', 'aksrt'),
|
||
];
|
||
return $map[$type] ?? $type;
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_get_user_notification_count')) :
|
||
/** 获取用户提醒总数 */
|
||
function aksrt_get_user_notification_count(int $user_id = 0): int {
|
||
$items = aksrt_get_user_notifications($user_id);
|
||
$count = 0;
|
||
foreach ($items as $item) {
|
||
$count += max(0, (int) ($item['count'] ?? 0));
|
||
}
|
||
return $count;
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_get_user_inbox_notifications')) :
|
||
/** 获取用户通知收件箱 */
|
||
function aksrt_get_user_inbox_notifications(int $user_id = 0): array {
|
||
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
|
||
if ($user_id <= 0) return [];
|
||
|
||
global $wpdb;
|
||
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('notification') : '';
|
||
if ($table === '') {
|
||
$items = get_user_meta($user_id, 'aksrt_notifications', true);
|
||
return is_array($items) ? array_values($items) : [];
|
||
}
|
||
|
||
static $migrated = [];
|
||
if (empty($migrated[$user_id])) {
|
||
$legacy = get_user_meta($user_id, 'aksrt_notifications', true);
|
||
if (is_array($legacy) && !empty($legacy)) {
|
||
foreach ($legacy as $item) {
|
||
aksrt_add_user_notification($user_id, [
|
||
'id' => $item['id'] ?? '',
|
||
'type' => $item['type'] ?? 'notice',
|
||
'title' => $item['title'] ?? '',
|
||
'desc' => $item['desc'] ?? '',
|
||
'url' => $item['url'] ?? '',
|
||
'read' => !empty($item['read']),
|
||
'created_at' => $item['created_at'] ?? current_time('mysql', true),
|
||
]);
|
||
}
|
||
delete_user_meta($user_id, 'aksrt_notifications');
|
||
}
|
||
$migrated[$user_id] = true;
|
||
}
|
||
|
||
$rows = $wpdb->get_results($wpdb->prepare(
|
||
"SELECT id, type, title, description, target_url, is_read, created_at, read_at
|
||
FROM {$table}
|
||
WHERE user_id = %d
|
||
ORDER BY created_at DESC, id DESC
|
||
LIMIT 50",
|
||
$user_id
|
||
), ARRAY_A);
|
||
|
||
if (!is_array($rows)) return [];
|
||
|
||
return array_map(static function ($row) {
|
||
return [
|
||
'id' => (string) ($row['id'] ?? ''),
|
||
'type' => (string) ($row['type'] ?? 'notice'),
|
||
'title' => (string) ($row['title'] ?? ''),
|
||
'desc' => (string) ($row['description'] ?? ''),
|
||
'url' => (string) ($row['target_url'] ?? ''),
|
||
'read' => !empty($row['is_read']) ? 1 : 0,
|
||
'created_at' => (string) ($row['created_at'] ?? ''),
|
||
'read_at' => (string) ($row['read_at'] ?? ''),
|
||
];
|
||
}, $rows);
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_schedule_notification_cleanup')) :
|
||
/** 注册通知清理定时任务 */
|
||
function aksrt_schedule_notification_cleanup(): void {
|
||
if (!wp_next_scheduled('aksrt_notification_cleanup')) {
|
||
$next = (new DateTimeImmutable('tomorrow 04:10', wp_timezone()))->getTimestamp();
|
||
wp_schedule_event($next, 'daily', 'aksrt_notification_cleanup');
|
||
}
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_cleanup_notifications')) :
|
||
/**
|
||
* 清理通知表:
|
||
* - 已读通知保留 30 天
|
||
* - 未读通知保留 180 天
|
||
* - 每个用户最多保留最近 200 条通知
|
||
*/
|
||
function aksrt_cleanup_notifications(): void {
|
||
global $wpdb;
|
||
|
||
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('notification') : '';
|
||
if ($table === '') {
|
||
return;
|
||
}
|
||
|
||
$settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_notification_settings() : [
|
||
'read_retention_days' => 30,
|
||
'unread_retention_days' => 180,
|
||
'max_per_user' => 200,
|
||
];
|
||
|
||
$read_retention_days = max(1, (int) ($settings['read_retention_days'] ?? 30));
|
||
$unread_retention_days = max(7, (int) ($settings['unread_retention_days'] ?? 180));
|
||
$max_per_user = max(20, (int) ($settings['max_per_user'] ?? 200));
|
||
|
||
$read_cutoff = (new DateTimeImmutable('-' . $read_retention_days . ' days', new DateTimeZone('UTC')))->format('Y-m-d H:i:s');
|
||
$unread_cutoff = (new DateTimeImmutable('-' . $unread_retention_days . ' days', new DateTimeZone('UTC')))->format('Y-m-d H:i:s');
|
||
|
||
$wpdb->query($wpdb->prepare(
|
||
"DELETE FROM {$table} WHERE is_read = 1 AND created_at < %s",
|
||
$read_cutoff
|
||
));
|
||
|
||
$wpdb->query($wpdb->prepare(
|
||
"DELETE FROM {$table} WHERE is_read = 0 AND created_at < %s",
|
||
$unread_cutoff
|
||
));
|
||
|
||
$user_ids = $wpdb->get_col("SELECT DISTINCT user_id FROM {$table}");
|
||
if (empty($user_ids)) {
|
||
return;
|
||
}
|
||
|
||
foreach ($user_ids as $user_id) {
|
||
$user_id = (int) $user_id;
|
||
if ($user_id <= 0) continue;
|
||
|
||
$ids = $wpdb->get_col($wpdb->prepare(
|
||
"SELECT id FROM {$table} WHERE user_id = %d ORDER BY created_at DESC, id DESC LIMIT %d, 1000",
|
||
$user_id,
|
||
$max_per_user
|
||
));
|
||
|
||
if (empty($ids)) {
|
||
continue;
|
||
}
|
||
|
||
$ids = array_map('absint', $ids);
|
||
$ids = array_filter($ids, static function ($id) { return $id > 0; });
|
||
if (empty($ids)) {
|
||
continue;
|
||
}
|
||
|
||
$wpdb->query("DELETE FROM {$table} WHERE id IN (" . implode(',', $ids) . ")");
|
||
}
|
||
}
|
||
endif;
|
||
|
||
add_action('wp', 'aksrt_schedule_notification_cleanup');
|
||
add_action('aksrt_notification_cleanup', 'aksrt_cleanup_notifications');
|
||
|
||
if (!function_exists('aksrt_write_user_inbox_notifications')) :
|
||
/** 写入用户通知收件箱 */
|
||
function aksrt_write_user_inbox_notifications(int $user_id, array $items): void {
|
||
if ($user_id <= 0) return;
|
||
global $wpdb;
|
||
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('notification') : '';
|
||
if ($table === '') {
|
||
update_user_meta($user_id, 'aksrt_notifications', array_values(array_slice($items, 0, 50)));
|
||
return;
|
||
}
|
||
|
||
$wpdb->delete($table, ['user_id' => $user_id], ['%d']);
|
||
$items = array_values(array_slice($items, 0, 50));
|
||
foreach ($items as $item) {
|
||
$wpdb->insert($table, [
|
||
'user_id' => $user_id,
|
||
'type' => sanitize_key((string) ($item['type'] ?? 'notice')),
|
||
'title' => sanitize_text_field((string) ($item['title'] ?? '')),
|
||
'description' => sanitize_text_field((string) ($item['desc'] ?? '')),
|
||
'target_url' => esc_url_raw((string) ($item['url'] ?? '')),
|
||
'is_read' => !empty($item['read']) ? 1 : 0,
|
||
'created_at' => (string) ($item['created_at'] ?? current_time('mysql', true)),
|
||
'read_at' => !empty($item['read']) ? current_time('mysql', true) : null,
|
||
], ['%d', '%s', '%s', '%s', '%s', '%d', '%s', '%s']);
|
||
}
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_add_user_notification')) :
|
||
/** 添加一条用户通知 */
|
||
function aksrt_add_user_notification(int $user_id, array $payload): void {
|
||
if ($user_id <= 0) return;
|
||
$type = sanitize_key((string) ($payload['type'] ?? 'notice'));
|
||
if (class_exists('\AKSRT\Settings\Settings') && !\AKSRT\Settings\Settings::notification_enabled($type)) {
|
||
return;
|
||
}
|
||
|
||
global $wpdb;
|
||
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('notification') : '';
|
||
$created_at = (string) ($payload['created_at'] ?? current_time('mysql', true));
|
||
|
||
if ($table === '') {
|
||
$items = aksrt_get_user_inbox_notifications($user_id);
|
||
array_unshift($items, [
|
||
'id' => isset($payload['id']) && $payload['id'] !== '' ? sanitize_text_field((string) $payload['id']) : uniqid('notif_', true),
|
||
'type' => $type,
|
||
'title' => sanitize_text_field((string) ($payload['title'] ?? '')),
|
||
'desc' => sanitize_text_field((string) ($payload['desc'] ?? '')),
|
||
'url' => esc_url_raw((string) ($payload['url'] ?? '')),
|
||
'read' => !empty($payload['read']) ? 1 : 0,
|
||
'created_at' => $created_at,
|
||
]);
|
||
aksrt_write_user_inbox_notifications($user_id, $items);
|
||
return;
|
||
}
|
||
|
||
$wpdb->insert($table, [
|
||
'user_id' => $user_id,
|
||
'type' => $type,
|
||
'title' => sanitize_text_field((string) ($payload['title'] ?? '')),
|
||
'description' => sanitize_text_field((string) ($payload['desc'] ?? '')),
|
||
'target_url' => esc_url_raw((string) ($payload['url'] ?? '')),
|
||
'is_read' => !empty($payload['read']) ? 1 : 0,
|
||
'created_at' => $created_at,
|
||
'read_at' => !empty($payload['read']) ? current_time('mysql', true) : null,
|
||
], ['%d', '%s', '%s', '%s', '%s', '%d', '%s', '%s']);
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_mark_user_notification_read')) :
|
||
/** 标记通知已读 */
|
||
function aksrt_mark_user_notification_read(int $user_id, string $notification_id = '', bool $mark_all = false): void {
|
||
if ($user_id <= 0) return;
|
||
global $wpdb;
|
||
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('notification') : '';
|
||
if ($table === '') {
|
||
$items = aksrt_get_user_inbox_notifications($user_id);
|
||
foreach ($items as &$item) {
|
||
if ($mark_all || (($item['id'] ?? '') === $notification_id)) {
|
||
$item['read'] = 1;
|
||
}
|
||
}
|
||
unset($item);
|
||
aksrt_write_user_inbox_notifications($user_id, $items);
|
||
return;
|
||
}
|
||
|
||
if ($mark_all) {
|
||
$wpdb->update(
|
||
$table,
|
||
['is_read' => 1, 'read_at' => current_time('mysql', true)],
|
||
['user_id' => $user_id, 'is_read' => 0],
|
||
['%d', '%s'],
|
||
['%d', '%d']
|
||
);
|
||
return;
|
||
}
|
||
|
||
$wpdb->update(
|
||
$table,
|
||
['is_read' => 1, 'read_at' => current_time('mysql', true)],
|
||
['id' => absint($notification_id), 'user_id' => $user_id],
|
||
['%d', '%s'],
|
||
['%d', '%d']
|
||
);
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_delete_user_notification')) :
|
||
/** 删除一条用户通知 */
|
||
function aksrt_delete_user_notification(int $user_id, string $notification_id): void {
|
||
if ($user_id <= 0 || $notification_id === '') return;
|
||
global $wpdb;
|
||
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('notification') : '';
|
||
if ($table === '') {
|
||
$items = aksrt_get_user_inbox_notifications($user_id);
|
||
$items = array_values(array_filter($items, static function ($item) use ($notification_id) {
|
||
return (string) ($item['id'] ?? '') !== $notification_id;
|
||
}));
|
||
aksrt_write_user_inbox_notifications($user_id, $items);
|
||
return;
|
||
}
|
||
$wpdb->delete($table, ['id' => absint($notification_id), 'user_id' => $user_id], ['%d', '%d']);
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_delete_user_notifications')) :
|
||
/** 批量删除用户通知 */
|
||
function aksrt_delete_user_notifications(int $user_id, array $notification_ids): void {
|
||
if ($user_id <= 0 || empty($notification_ids)) return;
|
||
$ids = array_values(array_filter(array_map('absint', $notification_ids), static function ($id) { return $id > 0; }));
|
||
if (empty($ids)) return;
|
||
|
||
global $wpdb;
|
||
$table = class_exists('\AKSRT\Core\DBMigrator') ? \AKSRT\Core\DBMigrator::table('notification') : '';
|
||
if ($table === '') {
|
||
$items = aksrt_get_user_inbox_notifications($user_id);
|
||
$items = array_values(array_filter($items, static function ($item) use ($ids) {
|
||
return !in_array(absint($item['id'] ?? 0), $ids, true);
|
||
}));
|
||
aksrt_write_user_inbox_notifications($user_id, $items);
|
||
return;
|
||
}
|
||
|
||
$wpdb->query(
|
||
"DELETE FROM {$table} WHERE user_id = " . (int) $user_id . " AND id IN (" . implode(',', $ids) . ")"
|
||
);
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_get_user_unread_notification_count')) :
|
||
/** 获取用户未读通知数 */
|
||
function aksrt_get_user_unread_notification_count(int $user_id = 0): int {
|
||
$items = aksrt_get_user_inbox_notifications($user_id);
|
||
$count = 0;
|
||
foreach ($items as $item) {
|
||
if (empty($item['read'])) $count++;
|
||
}
|
||
return $count;
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_get_user_tab_badge_count')) :
|
||
/** user 底部 Tab 徽标计数:未读持久化通知 + 即时状态提醒 */
|
||
function aksrt_get_user_tab_badge_count(int $user_id = 0): int {
|
||
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
|
||
if ($user_id <= 0) {
|
||
return 0;
|
||
}
|
||
if (class_exists('\AKSRT\Settings\Settings') && !\AKSRT\Settings\Settings::notification_user_badge_enabled()) {
|
||
return 0;
|
||
}
|
||
|
||
$count = aksrt_get_user_unread_notification_count($user_id);
|
||
if (class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::notification_badge_include_stateful()) {
|
||
$count += aksrt_get_user_notification_count($user_id);
|
||
}
|
||
return $count;
|
||
}
|
||
endif;
|
||
|
||
if (!function_exists('aksrt_get_user_all_notifications')) :
|
||
/** 获取用户完整通知列表(持久化通知 + 即时提醒) */
|
||
function aksrt_get_user_all_notifications(int $user_id = 0): array {
|
||
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
|
||
if ($user_id <= 0) return [];
|
||
|
||
$inbox = aksrt_get_user_inbox_notifications($user_id);
|
||
$alerts = aksrt_get_user_notifications($user_id);
|
||
|
||
$normalized_alerts = [];
|
||
foreach ($alerts as $alert) {
|
||
$normalized_alerts[] = [
|
||
'id' => 'state_' . sanitize_key((string) ($alert['type'] ?? 'notice')),
|
||
'type' => sanitize_key((string) ($alert['type'] ?? 'notice')),
|
||
'title' => sanitize_text_field((string) ($alert['title'] ?? '')),
|
||
'desc' => sanitize_text_field((string) ($alert['desc'] ?? '')),
|
||
'url' => esc_url_raw((string) ($alert['url'] ?? '')),
|
||
'read' => 0,
|
||
'created_at' => current_time('mysql', true),
|
||
'count' => max(0, (int) ($alert['count'] ?? 0)),
|
||
'stateful' => 1,
|
||
];
|
||
}
|
||
|
||
return array_merge($inbox, $normalized_alerts);
|
||
}
|
||
endif;
|
||
|
||
add_action('wp_ajax_aksrt_mark_notification_read', function () {
|
||
if (!is_user_logged_in()) {
|
||
wp_send_json_error(['message' => __('请先登录', 'aksrt')], 401);
|
||
}
|
||
|
||
$nonce = isset($_POST['nonce']) ? (string) $_POST['nonce'] : '';
|
||
if (!wp_verify_nonce($nonce, 'aksrt_public_nonce')) {
|
||
wp_send_json_error(['message' => __('安全验证失败', 'aksrt')], 403);
|
||
}
|
||
|
||
$notification_id = sanitize_text_field((string) ($_POST['notification_id'] ?? ''));
|
||
$mark_all = !empty($_POST['mark_all']);
|
||
aksrt_mark_user_notification_read(get_current_user_id(), $notification_id, $mark_all);
|
||
wp_send_json_success([
|
||
'unread' => aksrt_get_user_unread_notification_count(get_current_user_id()),
|
||
]);
|
||
});
|
||
|
||
add_action('wp_ajax_aksrt_delete_notification', function () {
|
||
if (!is_user_logged_in()) {
|
||
wp_send_json_error(['message' => __('请先登录', 'aksrt')], 401);
|
||
}
|
||
|
||
$nonce = isset($_POST['nonce']) ? (string) $_POST['nonce'] : '';
|
||
if (!wp_verify_nonce($nonce, 'aksrt_public_nonce')) {
|
||
wp_send_json_error(['message' => __('安全验证失败', 'aksrt')], 403);
|
||
}
|
||
|
||
$notification_id = sanitize_text_field((string) ($_POST['notification_id'] ?? ''));
|
||
if ($notification_id === '') {
|
||
wp_send_json_error(['message' => __('参数错误', 'aksrt')], 400);
|
||
}
|
||
|
||
aksrt_delete_user_notification(get_current_user_id(), $notification_id);
|
||
wp_send_json_success([
|
||
'unread' => aksrt_get_user_unread_notification_count(get_current_user_id()),
|
||
]);
|
||
});
|
||
|
||
add_action('wp_ajax_aksrt_delete_notifications', function () {
|
||
if (!is_user_logged_in()) {
|
||
wp_send_json_error(['message' => __('请先登录', 'aksrt')], 401);
|
||
}
|
||
|
||
$nonce = isset($_POST['nonce']) ? (string) $_POST['nonce'] : '';
|
||
if (!wp_verify_nonce($nonce, 'aksrt_public_nonce')) {
|
||
wp_send_json_error(['message' => __('安全验证失败', 'aksrt')], 403);
|
||
}
|
||
|
||
$ids = isset($_POST['notification_ids']) ? (array) $_POST['notification_ids'] : [];
|
||
aksrt_delete_user_notifications(get_current_user_id(), $ids);
|
||
wp_send_json_success([
|
||
'unread' => aksrt_get_user_unread_notification_count(get_current_user_id()),
|
||
]);
|
||
});
|
||
|
||
add_action('wp_ajax_aksrt_check_new_notifications', function () {
|
||
if (!is_user_logged_in()) {
|
||
wp_send_json_error(['message' => __('请先登录', 'aksrt')], 401);
|
||
}
|
||
|
||
$nonce = isset($_POST['nonce']) ? (string) $_POST['nonce'] : '';
|
||
if (!wp_verify_nonce($nonce, 'aksrt_public_nonce')) {
|
||
wp_send_json_error(['message' => __('安全验证失败', 'aksrt')], 403);
|
||
}
|
||
|
||
$unread = aksrt_get_user_unread_notification_count(get_current_user_id());
|
||
wp_send_json_success([
|
||
'count' => $unread,
|
||
'unread' => $unread,
|
||
]);
|
||
});
|
||
add_action('wp_insert_comment', function ($comment_id, $comment) {
|
||
if (!$comment instanceof WP_Comment) return;
|
||
if ((int) $comment->comment_parent <= 0) return;
|
||
if ((int) $comment->comment_approved !== 1) return;
|
||
if (get_comment_meta($comment_id, 'aksrt_reply_notified', true)) return;
|
||
|
||
$parent = get_comment((int) $comment->comment_parent);
|
||
if (!$parent instanceof WP_Comment) return;
|
||
$target_user_id = (int) $parent->user_id;
|
||
if ($target_user_id <= 0 || $target_user_id === (int) $comment->user_id) return;
|
||
|
||
$post_id = (int) $comment->comment_post_ID;
|
||
$url = get_comment_link($comment);
|
||
aksrt_add_user_notification($target_user_id, [
|
||
'type' => 'comment_reply',
|
||
'title' => __('评论收到回复', 'aksrt'),
|
||
'desc' => sprintf(__('“%s” 回复了你的评论。', 'aksrt'), get_comment_author($comment)),
|
||
'url' => $url ?: get_permalink($post_id),
|
||
]);
|
||
update_comment_meta($comment_id, 'aksrt_reply_notified', 1);
|
||
}, 20, 2);
|
||
|
||
add_action('transition_comment_status', function ($new_status, $old_status, $comment) {
|
||
if (!$comment instanceof WP_Comment) return;
|
||
if ($new_status !== 'approve' || $old_status === 'approve') return;
|
||
|
||
$comment_owner_id = (int) $comment->user_id;
|
||
if ($comment_owner_id > 0 && !get_comment_meta($comment->comment_ID, 'aksrt_approved_notified', true)) {
|
||
aksrt_add_user_notification($comment_owner_id, [
|
||
'type' => 'comment_approved',
|
||
'title' => __('评论已通过审核', 'aksrt'),
|
||
'desc' => __('你的评论已通过审核,现已公开展示。', 'aksrt'),
|
||
'url' => get_comment_link($comment),
|
||
]);
|
||
update_comment_meta($comment->comment_ID, 'aksrt_approved_notified', 1);
|
||
}
|
||
|
||
if ((int) $comment->comment_parent <= 0) return;
|
||
if (get_comment_meta($comment->comment_ID, 'aksrt_reply_notified', true)) return;
|
||
|
||
$parent = get_comment((int) $comment->comment_parent);
|
||
if (!$parent instanceof WP_Comment) return;
|
||
$target_user_id = (int) $parent->user_id;
|
||
if ($target_user_id <= 0 || $target_user_id === (int) $comment->user_id) return;
|
||
|
||
aksrt_add_user_notification($target_user_id, [
|
||
'type' => 'comment_reply',
|
||
'title' => __('评论收到回复', 'aksrt'),
|
||
'desc' => sprintf(__('“%s” 回复了你的评论。', 'aksrt'), get_comment_author($comment)),
|
||
'url' => get_comment_link($comment),
|
||
]);
|
||
update_comment_meta($comment->comment_ID, 'aksrt_reply_notified', 1);
|
||
}, 20, 3);
|
||
|
||
add_action('aksrt_asset_transaction_committed', function ($result, $command): void {
|
||
if (!$result instanceof \AKSRT\Ledger\LedgerResult || !$command instanceof \AKSRT\Ledger\LedgerCommand) {
|
||
return;
|
||
}
|
||
$changes = [];
|
||
foreach ($result->entries as $entry) {
|
||
$user_id = (int) ($entry['user_id'] ?? 0);
|
||
$asset = (string) ($entry['asset'] ?? '');
|
||
if ($user_id <= 0 || !in_array($asset, ['points', 'balance'], true)) continue;
|
||
$key = $user_id . ':' . $asset;
|
||
$changes[$key] ??= ['user_id' => $user_id, 'asset' => $asset, 'delta' => 0, 'balance' => 0];
|
||
$changes[$key]['delta'] += (int) ($entry['delta_minor'] ?? 0);
|
||
$changes[$key]['balance'] = (int) ($entry['balance_after_minor'] ?? 0);
|
||
}
|
||
foreach ($changes as $change) {
|
||
if ((int) $change['delta'] === 0) continue;
|
||
$is_points = $change['asset'] === 'points';
|
||
$positive = $change['delta'] > 0;
|
||
$amount = $is_points
|
||
? (string) abs((int) $change['delta'])
|
||
: \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, abs((int) $change['delta']))->decimal();
|
||
$balance = $is_points
|
||
? (string) $change['balance']
|
||
: \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, (int) $change['balance'])->decimal();
|
||
aksrt_add_user_notification((int) $change['user_id'], [
|
||
'type' => 'asset_' . $change['asset'] . '_' . ($positive ? 'increase' : 'decrease'),
|
||
'title' => $is_points ? __('积分变动', 'aksrt') : __('余额变动', 'aksrt'),
|
||
'desc' => sprintf(__('%1$s:%2$s%3$s,当前余额 %4$s。', 'aksrt'), \AKSRT\Ledger\LedgerPresentation::reason_label($command->reason), $positive ? '+' : '-', $amount, $balance),
|
||
'url' => aksrt_get_user_center_url('credits'),
|
||
]);
|
||
}
|
||
}, 10, 2);
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|