Files
wordpress-theme-aksrt/inc/classes/class-aksrt-credits-earn.php
T

230 lines
8.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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.
}
}