230 lines
8.2 KiB
PHP
230 lines
8.2 KiB
PHP
<?php
|
||
/**
|
||
* AKSRT Credits Earn
|
||
*
|
||
* 积分获取入口,挂载到 WordPress 钩子:
|
||
* - 注册赠送 → user_register
|
||
* - 评论奖励 → wp_insert_comment / transition_comment_status
|
||
* - 签到/邀请 → 由 AKSRT_Signin / AKSRT_Invite 独立处理(REST)
|
||
*
|
||
* 所有发放都受 aksrt_credit_settings.* 子开关控制,关闭后不发放。
|
||
*
|
||
* @package AKSRT
|
||
*/
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
class AKSRT_Credits_Earn {
|
||
|
||
private static $instance = null;
|
||
|
||
private function __construct() {}
|
||
|
||
public static function get_instance(): self {
|
||
if (null === self::$instance) self::$instance = new self();
|
||
return self::$instance;
|
||
}
|
||
|
||
public function init(): void {
|
||
// 注册赠送
|
||
add_action('user_register', [$this, 'on_user_register'], 10, 1);
|
||
|
||
// 评论奖励:on_approved 时机决定挂到哪个钩子
|
||
// 默认 on_approved=true → 仅审核通过后发;否则插入即发
|
||
add_action('wp_insert_comment', [$this, 'on_comment_inserted'], 10, 2);
|
||
add_action('transition_comment_status', [$this, 'on_comment_transition'], 10, 3);
|
||
|
||
// 论坛发帖奖励
|
||
add_action('aksrt_forum_topic_created', [$this, 'on_forum_topic_created'], 10, 2);
|
||
|
||
// 论坛回复奖励(§7.7)
|
||
add_action('comment_post', [$this, 'on_forum_reply_posted'], 20, 3);
|
||
|
||
// 论坛精华/热帖奖励(§7.7)
|
||
add_action('aksrt_forum_topic_featured', [$this, 'on_forum_topic_featured'], 10, 2);
|
||
}
|
||
|
||
/**
|
||
* 论坛发帖积分奖励
|
||
*/
|
||
public function on_forum_topic_created(int $user_id, int $post_id): void {
|
||
if (!class_exists('AKSRT_Credits') || !class_exists('AKSRT_Settings')) return;
|
||
$cfg = AKSRT_Settings::get_credit_settings();
|
||
if (empty($cfg['enabled'])) return;
|
||
$reward = $cfg['forum_topic_reward'] ?? [];
|
||
if (empty($reward['enabled'])) return;
|
||
|
||
$amount = (int) ($reward['amount'] ?? 0);
|
||
if ($amount <= 0) return;
|
||
|
||
$daily_limit = (int) ($reward['daily_limit'] ?? 5);
|
||
$today_count = $this->today_forum_reward_count($user_id, 'topic');
|
||
if ($today_count >= $daily_limit) return;
|
||
|
||
AKSRT_Credits::add($user_id, $amount, 'forum_topic', ['type' => 'post', 'id' => $post_id]);
|
||
}
|
||
|
||
/**
|
||
* 今日论坛奖励次数
|
||
*/
|
||
private function today_forum_reward_count(int $user_id, string $type = 'topic'): int {
|
||
global $wpdb;
|
||
$table = AKSRT_DB_Migrator::table('credit_log');
|
||
if (!$table) return 0;
|
||
|
||
$today = current_time('Y-m-d');
|
||
return (int) $wpdb->get_var($wpdb->prepare(
|
||
"SELECT COUNT(*) FROM {$table} WHERE user_id = %d AND reason = %s AND DATE(created_at) = %s",
|
||
$user_id, 'forum_' . $type, $today
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 注册赠送。
|
||
*/
|
||
public function on_user_register(int $user_id): void {
|
||
if (!class_exists('AKSRT_Credits') || !class_exists('AKSRT_Settings')) return;
|
||
$cfg = AKSRT_Settings::get_credit_settings();
|
||
if (empty($cfg['enabled'])) return;
|
||
$bonus = (int) ($cfg['register_bonus'] ?? 0);
|
||
if ($bonus <= 0) return;
|
||
|
||
AKSRT_Credits::add($user_id, $bonus, 'register', ['type' => 'user', 'id' => $user_id]);
|
||
}
|
||
|
||
/**
|
||
* 评论插入(直接发表无需审核场景)。
|
||
*/
|
||
public function on_comment_inserted(int $comment_id, $comment): void {
|
||
if (!class_exists('AKSRT_Settings')) return;
|
||
$cfg = AKSRT_Settings::get_credit_settings();
|
||
$reward = $cfg['comment_reward'] ?? [];
|
||
if (empty($cfg['enabled']) || empty($reward['enabled'])) return;
|
||
|
||
// 仅审核通过后发放 → 不在 insert 时处理
|
||
if (!empty($reward['on_approved'])) return;
|
||
|
||
$comment = $comment instanceof WP_Comment ? $comment : get_comment($comment_id);
|
||
if (!($comment instanceof WP_Comment)) return;
|
||
|
||
// 只奖励已批准的评论
|
||
if ((int) $comment->comment_approved !== 1) return;
|
||
|
||
$this->maybe_reward_comment($comment, $reward);
|
||
}
|
||
|
||
/**
|
||
* 评论状态流转。
|
||
*/
|
||
public function on_comment_transition($new_status, $old_status, $comment): void {
|
||
if (!class_exists('AKSRT_Settings')) return;
|
||
$cfg = AKSRT_Settings::get_credit_settings();
|
||
$reward = $cfg['comment_reward'] ?? [];
|
||
if (empty($cfg['enabled']) || empty($reward['enabled'])) return;
|
||
if (empty($reward['on_approved'])) return;
|
||
|
||
if ($new_status !== 'approved') return;
|
||
// 跳过已经处理过的:以 commentmeta 标记
|
||
if (!($comment instanceof WP_Comment)) return;
|
||
|
||
$this->maybe_reward_comment($comment, $reward);
|
||
}
|
||
|
||
/**
|
||
* 真正的评论奖励逻辑(含字数 / 每日上限 / 去重)。
|
||
*/
|
||
private function maybe_reward_comment(WP_Comment $comment, array $reward): void {
|
||
$user_id = (int) $comment->user_id;
|
||
if ($user_id <= 0) return;
|
||
|
||
// 防重复:commentmeta 标记
|
||
if (get_comment_meta($comment->comment_ID, 'aksrt_credit_rewarded', true)) return;
|
||
|
||
$min_length = (int) ($reward['min_length'] ?? 0);
|
||
if ($min_length > 0 && mb_strlen(strip_tags($comment->comment_content)) < $min_length) return;
|
||
|
||
$amount = (int) ($reward['amount'] ?? 0);
|
||
if ($amount <= 0) return;
|
||
|
||
// 每日上限
|
||
$cap = (int) ($reward['daily_cap'] ?? 0);
|
||
if ($cap > 0) {
|
||
$today_count = $this->today_comment_reward_count($user_id);
|
||
if ($today_count >= $cap) {
|
||
update_comment_meta($comment->comment_ID, 'aksrt_credit_rewarded', 'capped');
|
||
return;
|
||
}
|
||
}
|
||
|
||
$result = AKSRT_Credits::add(
|
||
$user_id,
|
||
$amount,
|
||
'comment',
|
||
['type' => 'comment', 'id' => (int) $comment->comment_ID]
|
||
);
|
||
if (!is_wp_error($result)) {
|
||
update_comment_meta($comment->comment_ID, 'aksrt_credit_rewarded', 1);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 当日评论奖励次数(查询 credit_log)。
|
||
*/
|
||
private function today_comment_reward_count(int $user_id): int {
|
||
global $wpdb;
|
||
if (!class_exists('AKSRT_DB_Migrator')) return 0;
|
||
$table = AKSRT_DB_Migrator::table('credit_log');
|
||
if (!$table) return 0;
|
||
|
||
// 站点时区当日 00:00 起
|
||
$tz = wp_timezone();
|
||
$today = (new DateTimeImmutable('today', $tz))->format('Y-m-d H:i:s');
|
||
// 转 UTC(数据库 created_at 用 mysql UTC)
|
||
$today_utc = (new DateTimeImmutable('today', $tz))->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||
|
||
return (int) $wpdb->get_var($wpdb->prepare(
|
||
"SELECT COUNT(*) FROM {$table} WHERE user_id = %d AND reason = 'comment' AND created_at >= %s",
|
||
$user_id,
|
||
$today_utc
|
||
));
|
||
}
|
||
|
||
// ================================================================
|
||
// Forum credits (§7.7)
|
||
// ================================================================
|
||
|
||
public function on_forum_reply_posted(int $comment_id, $approved, array $commentdata = []): void {
|
||
if (!class_exists('AKSRT_Credits') || !class_exists('AKSRT_Settings')) return;
|
||
if (!class_exists('AKSRT_Forum')) return;
|
||
|
||
$comment = get_comment($comment_id);
|
||
if (!$comment) return;
|
||
|
||
$post = get_post((int) $comment->comment_post_ID);
|
||
if (!$post || $post->post_type !== 'aksrt_forum_topic') return;
|
||
|
||
if ((int) $comment->comment_approved !== 1) return;
|
||
|
||
$user_id = (int) $comment->user_id;
|
||
if ($user_id <= 0) return;
|
||
|
||
$forum_cfg = AKSRT_Settings::get_forum_settings();
|
||
$amount = (int) ($forum_cfg['credits']['comment_new'] ?? 2);
|
||
if ($amount <= 0) return;
|
||
|
||
$daily_max = (int) ($forum_cfg['credits']['daily_max'] ?? 50);
|
||
$today_count = $this->today_forum_reward_count($user_id, 'reply');
|
||
if ($today_count >= $daily_max) return;
|
||
|
||
AKSRT_Credits::add($user_id, $amount, 'forum_reply', [
|
||
'type' => 'comment',
|
||
'id' => $comment_id,
|
||
]);
|
||
}
|
||
|
||
public function on_forum_topic_featured(int $topic_id, int $operator_id): void {
|
||
// Essence reward is handled in AKSRT_Forum::reward_essence().
|
||
// This hook is for additional integrations if needed.
|
||
}
|
||
}
|