Close identity 1:1 gaps after p1: user-center weixin/alipay tip QR upload+save, AKSRT_User_Metrics counters for medal get_type and level XP bridges, forum/revenue/signin hooks, comment moderate via user_caps, and clearer free-task deep links/status CTAs.
362 lines
11 KiB
PHP
362 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* User metric accumulators for medal get_type + integral XP.
|
|
*
|
|
* Maintains user_meta counters used by AKSRT_User_Badges::metric_value()
|
|
* and grants level XP / re-evaluates medals on the same events as free points.
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
class AKSRT_User_Metrics {
|
|
|
|
public const META_POST_LIKE_SUM = 'aksrt_posts_like_sum';
|
|
public const META_COMMENT_LIKE_SUM = 'aksrt_comment_like_sum';
|
|
public const META_POSTS_VIEWS_SUM = 'aksrt_posts_views_sum';
|
|
public const META_BBS_ADOPT = 'aksrt_bbs_adopt_count';
|
|
public const META_BBS_COMMENT_HOT = 'aksrt_bbs_comment_hot_count';
|
|
public const META_BBS_POST_HOT = 'aksrt_bbs_post_hot_count';
|
|
public const META_BBS_ESSENCE = 'aksrt_bbs_essence_count';
|
|
public const META_BBS_SCORE = 'aksrt_bbs_score_sum';
|
|
public const META_PAY_INCOME = 'aksrt_pay_income_sum';
|
|
public const META_PAY_REBATE = 'aksrt_pay_rebate_sum';
|
|
public const META_CHECKIN_ALL_DAY = 'aksrt_checkin_all_day';
|
|
|
|
/** @var self|null */
|
|
private static $instance = null;
|
|
|
|
public static function get_instance(): self {
|
|
if (null === self::$instance) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
public function init(): void {
|
|
add_action('aksrt_post_liked', [$this, 'on_post_liked'], 20, 3);
|
|
add_action('aksrt_comment_liked', [$this, 'on_comment_liked'], 20, 3);
|
|
add_action('aksrt_post_favorited', [$this, 'on_post_favorited'], 20, 3);
|
|
add_action('aksrt_user_followed', [$this, 'on_user_followed'], 20, 2);
|
|
add_action('aksrt_post_viewed', [$this, 'on_post_viewed'], 20, 2);
|
|
|
|
add_action('aksrt_forum_topic_featured', [$this, 'on_forum_topic_featured'], 20, 2);
|
|
add_action('aksrt_forum_reply_adopted', [$this, 'on_forum_reply_adopted'], 20, 3);
|
|
add_action('aksrt_forum_comment_hot', [$this, 'on_forum_comment_hot'], 20, 2);
|
|
add_action('aksrt_forum_topic_hot', [$this, 'on_forum_topic_hot'], 20, 2);
|
|
add_action('aksrt_forum_topic_scored', [$this, 'on_forum_topic_scored'], 20, 3);
|
|
|
|
add_action('aksrt_user_signed_in', [$this, 'on_user_signed_in'], 20, 1);
|
|
add_action('aksrt_creator_income_added', [$this, 'on_creator_income_added'], 20, 3);
|
|
add_action('aksrt_pay_rebate_added', [$this, 'on_pay_rebate_added'], 20, 3);
|
|
|
|
// Free-points / social hooks also feed level XP.
|
|
add_action('aksrt_post_liked', [$this, 'level_on_post_liked'], 25, 3);
|
|
add_action('aksrt_comment_liked', [$this, 'level_on_comment_liked'], 25, 3);
|
|
add_action('aksrt_post_favorited', [$this, 'level_on_post_favorited'], 25, 3);
|
|
add_action('aksrt_user_followed', [$this, 'level_on_user_followed'], 25, 2);
|
|
add_action('aksrt_forum_topic_featured', [$this, 'level_on_forum_topic_featured'], 25, 2);
|
|
add_action('aksrt_forum_reply_adopted', [$this, 'level_on_forum_reply_adopted'], 25, 3);
|
|
add_action('aksrt_forum_comment_hot', [$this, 'level_on_forum_comment_hot'], 25, 2);
|
|
add_action('aksrt_forum_topic_hot', [$this, 'level_on_forum_topic_hot'], 25, 2);
|
|
add_action('aksrt_forum_topic_scored', [$this, 'level_on_forum_topic_scored'], 25, 3);
|
|
add_action('aksrt_forum_topic_created', [$this, 'level_on_forum_topic_created'], 25, 2);
|
|
add_action('aksrt_user_signed_in', [$this, 'level_on_user_signed_in'], 25, 1);
|
|
}
|
|
|
|
public static function bump_user_meta(int $user_id, string $meta_key, float $delta = 1.0): float {
|
|
if ($user_id <= 0 || $meta_key === '' || $delta == 0.0) {
|
|
return 0.0;
|
|
}
|
|
$current = (float) get_user_meta($user_id, $meta_key, true);
|
|
$next = max(0.0, $current + $delta);
|
|
update_user_meta($user_id, $meta_key, $next);
|
|
return $next;
|
|
}
|
|
|
|
public static function reevaluate_medals(int $user_id): void {
|
|
if ($user_id > 0 && class_exists('AKSRT_User_Badges') && method_exists('AKSRT_User_Badges', 'auto_evaluate')) {
|
|
AKSRT_User_Badges::auto_evaluate($user_id);
|
|
}
|
|
}
|
|
|
|
public function on_post_liked(int $post_id, int $actor_id, bool $active): void {
|
|
$post = get_post($post_id);
|
|
if (!$post instanceof WP_Post || $post->post_type !== 'post') {
|
|
return;
|
|
}
|
|
$author = (int) $post->post_author;
|
|
if ($author <= 0 || $author === $actor_id) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($author, self::META_POST_LIKE_SUM, $active ? 1.0 : -1.0);
|
|
if ($active) {
|
|
self::reevaluate_medals($author);
|
|
}
|
|
}
|
|
|
|
public function on_comment_liked(int $comment_id, int $actor_id, bool $active): void {
|
|
$comment = get_comment($comment_id);
|
|
if (!$comment) {
|
|
return;
|
|
}
|
|
$author = (int) $comment->user_id;
|
|
if ($author <= 0 || $author === $actor_id) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($author, self::META_COMMENT_LIKE_SUM, $active ? 1.0 : -1.0);
|
|
if ($active) {
|
|
self::reevaluate_medals($author);
|
|
}
|
|
}
|
|
|
|
public function on_post_favorited(int $post_id, int $actor_id, bool $active): void {
|
|
unset($post_id, $actor_id, $active);
|
|
// Favorite is free-points / level only; no dedicated medal get_type.
|
|
}
|
|
|
|
public function on_user_followed(int $follower_id, int $following_id): void {
|
|
unset($follower_id);
|
|
if ($following_id > 0) {
|
|
self::reevaluate_medals($following_id);
|
|
}
|
|
}
|
|
|
|
public function on_post_viewed(int $post_id, int $viewer_id = 0): void {
|
|
unset($viewer_id);
|
|
$post = get_post($post_id);
|
|
if (!$post instanceof WP_Post || $post->post_type !== 'post') {
|
|
return;
|
|
}
|
|
$author = (int) $post->post_author;
|
|
if ($author <= 0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($author, self::META_POSTS_VIEWS_SUM, 1.0);
|
|
// Cheap throttle: reevaluate every 50 views on author sum.
|
|
$sum = (float) get_user_meta($author, self::META_POSTS_VIEWS_SUM, true);
|
|
if (((int) $sum % 50) === 0) {
|
|
self::reevaluate_medals($author);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param int $topic_id
|
|
* @param int $author_id
|
|
*/
|
|
public function on_forum_topic_featured($topic_id, $author_id = 0): void {
|
|
$author_id = (int) $author_id;
|
|
if ($author_id <= 0) {
|
|
$post = get_post((int) $topic_id);
|
|
$author_id = $post ? (int) $post->post_author : 0;
|
|
}
|
|
if ($author_id <= 0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($author_id, self::META_BBS_ESSENCE, 1.0);
|
|
self::reevaluate_medals($author_id);
|
|
}
|
|
|
|
/**
|
|
* @param int $topic_id
|
|
* @param int $comment_id
|
|
* @param int $adoptee_id
|
|
*/
|
|
public function on_forum_reply_adopted($topic_id, $comment_id, $adoptee_id): void {
|
|
unset($topic_id, $comment_id);
|
|
$adoptee_id = (int) $adoptee_id;
|
|
if ($adoptee_id <= 0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($adoptee_id, self::META_BBS_ADOPT, 1.0);
|
|
self::reevaluate_medals($adoptee_id);
|
|
}
|
|
|
|
/**
|
|
* @param int $comment_id
|
|
* @param int $author_id
|
|
*/
|
|
public function on_forum_comment_hot($comment_id, $author_id = 0): void {
|
|
$author_id = (int) $author_id;
|
|
if ($author_id <= 0) {
|
|
$c = get_comment((int) $comment_id);
|
|
$author_id = $c ? (int) $c->user_id : 0;
|
|
}
|
|
if ($author_id <= 0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($author_id, self::META_BBS_COMMENT_HOT, 1.0);
|
|
self::reevaluate_medals($author_id);
|
|
}
|
|
|
|
/**
|
|
* @param int $topic_id
|
|
* @param int $author_id
|
|
*/
|
|
public function on_forum_topic_hot($topic_id, $author_id = 0): void {
|
|
$author_id = (int) $author_id;
|
|
if ($author_id <= 0) {
|
|
$post = get_post((int) $topic_id);
|
|
$author_id = $post ? (int) $post->post_author : 0;
|
|
}
|
|
if ($author_id <= 0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($author_id, self::META_BBS_POST_HOT, 1.0);
|
|
self::reevaluate_medals($author_id);
|
|
}
|
|
|
|
/**
|
|
* @param int $topic_id
|
|
* @param int $author_id
|
|
* @param float $delta
|
|
*/
|
|
public function on_forum_topic_scored($topic_id, $author_id, $delta = 0): void {
|
|
unset($topic_id);
|
|
$author_id = (int) $author_id;
|
|
$delta = (float) $delta;
|
|
if ($author_id <= 0 || $delta == 0.0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($author_id, self::META_BBS_SCORE, $delta);
|
|
self::reevaluate_medals($author_id);
|
|
}
|
|
|
|
public function on_user_signed_in(int $user_id): void {
|
|
if ($user_id <= 0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($user_id, self::META_CHECKIN_ALL_DAY, 1.0);
|
|
self::reevaluate_medals($user_id);
|
|
}
|
|
|
|
/**
|
|
* @param int $user_id
|
|
* @param float $amount
|
|
* @param array $context
|
|
*/
|
|
public function on_creator_income_added($user_id, $amount, $context = []): void {
|
|
unset($context);
|
|
$user_id = (int) $user_id;
|
|
$amount = (float) $amount;
|
|
if ($user_id <= 0 || $amount <= 0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($user_id, self::META_PAY_INCOME, $amount);
|
|
self::reevaluate_medals($user_id);
|
|
}
|
|
|
|
/**
|
|
* @param int $user_id
|
|
* @param float $amount
|
|
* @param array $context
|
|
*/
|
|
public function on_pay_rebate_added($user_id, $amount, $context = []): void {
|
|
unset($context);
|
|
$user_id = (int) $user_id;
|
|
$amount = (float) $amount;
|
|
if ($user_id <= 0 || $amount <= 0) {
|
|
return;
|
|
}
|
|
self::bump_user_meta($user_id, self::META_PAY_REBATE, $amount);
|
|
self::reevaluate_medals($user_id);
|
|
}
|
|
|
|
/* ---------- level XP bridges ---------- */
|
|
|
|
private static function level_add(int $user_id, string $key): void {
|
|
if ($user_id > 0 && class_exists('AKSRT_User_Level')) {
|
|
AKSRT_User_Level::add($user_id, $key);
|
|
}
|
|
}
|
|
|
|
public function level_on_post_liked(int $post_id, int $actor_id, bool $active): void {
|
|
if (!$active) {
|
|
return;
|
|
}
|
|
$post = get_post($post_id);
|
|
if (!$post instanceof WP_Post) {
|
|
return;
|
|
}
|
|
$author = (int) $post->post_author;
|
|
if ($author > 0 && $author !== $actor_id) {
|
|
self::level_add($author, 'post_like');
|
|
}
|
|
}
|
|
|
|
public function level_on_comment_liked(int $comment_id, int $actor_id, bool $active): void {
|
|
if (!$active) {
|
|
return;
|
|
}
|
|
$c = get_comment($comment_id);
|
|
if (!$c) {
|
|
return;
|
|
}
|
|
$author = (int) $c->user_id;
|
|
if ($author > 0 && $author !== $actor_id) {
|
|
self::level_add($author, 'comment_like');
|
|
}
|
|
}
|
|
|
|
public function level_on_post_favorited(int $post_id, int $actor_id, bool $active): void {
|
|
if (!$active) {
|
|
return;
|
|
}
|
|
$post = get_post($post_id);
|
|
if (!$post instanceof WP_Post) {
|
|
return;
|
|
}
|
|
$author = (int) $post->post_author;
|
|
if ($author > 0 && $author !== $actor_id) {
|
|
self::level_add($author, 'post_favorite');
|
|
}
|
|
}
|
|
|
|
public function level_on_user_followed(int $follower_id, int $following_id): void {
|
|
unset($follower_id);
|
|
self::level_add((int) $following_id, 'followed');
|
|
}
|
|
|
|
public function level_on_forum_topic_featured($topic_id, $author_id = 0): void {
|
|
unset($topic_id);
|
|
self::level_add((int) $author_id, 'bbs_essence');
|
|
}
|
|
|
|
public function level_on_forum_reply_adopted($topic_id, $comment_id, $adoptee_id): void {
|
|
unset($topic_id, $comment_id);
|
|
self::level_add((int) $adoptee_id, 'bbs_adopt');
|
|
}
|
|
|
|
public function level_on_forum_comment_hot($comment_id, $author_id = 0): void {
|
|
unset($comment_id);
|
|
self::level_add((int) $author_id, 'bbs_comment_hot');
|
|
}
|
|
|
|
public function level_on_forum_topic_hot($topic_id, $author_id = 0): void {
|
|
unset($topic_id);
|
|
self::level_add((int) $author_id, 'bbs_posts_hot');
|
|
}
|
|
|
|
public function level_on_forum_topic_scored($topic_id, $author_id, $delta = 0): void {
|
|
unset($topic_id);
|
|
if ((float) $delta > 0) {
|
|
self::level_add((int) $author_id, 'bbs_score_extra');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param int $user_id
|
|
* @param int $topic_id
|
|
*/
|
|
public function level_on_forum_topic_created($user_id, $topic_id = 0): void {
|
|
unset($topic_id);
|
|
self::level_add((int) $user_id, 'bbs_posts_new');
|
|
}
|
|
|
|
public function level_on_user_signed_in(int $user_id): void {
|
|
// Sign-in XP: use sign_in key once/day via existing login guard path as well.
|
|
self::level_add($user_id, 'sign_in');
|
|
}
|
|
}
|