grant time (Y-m-d H:i:s)`, newest first. */ public const META_OWNED = 'aksrt_user_badges'; public const META_WEAR = 'aksrt_wear_badge'; private static $instance = null; private static ?array $dictionary_cache = null; /** @var array,owned:list,wear:string}> */ private static array $user_context_cache = []; 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('wp_ajax_aksrt_user_medal_info_modal', [$this, 'ajax_info_modal']); add_action('wp_ajax_nopriv_aksrt_user_medal_info_modal', [$this, 'ajax_info_modal']); add_action('wp_ajax_aksrt_single_medal_info_modal', [$this, 'ajax_single_modal']); add_action('wp_ajax_nopriv_aksrt_single_medal_info_modal', [$this, 'ajax_single_modal']); add_action('wp_ajax_aksrt_user_medal_manually_add_modal', [$this, 'ajax_grant_modal']); add_action('wp_ajax_aksrt_user_medal_wear', [$this, 'ajax_wear']); add_action('wp_ajax_nopriv_aksrt_user_medal_wear', [$this, 'ajax_wear']); add_action('wp_ajax_aksrt_user_medal_manually_add', [$this, 'ajax_grant']); add_action('wp_ajax_nopriv_aksrt_user_medal_manually_add', [$this, 'ajax_grant']); add_action('wp_ajax_aksrt_user_medal_manually_remove', [$this, 'ajax_revoke']); add_action('wp_ajax_nopriv_aksrt_user_medal_manually_remove', [$this, 'ajax_revoke']); add_action('aksrt_badge_granted', [$this, 'on_badge_granted_notify'], 10, 3); } private static function clear_context(int $user_id = 0): void { if ($user_id > 0) { unset(self::$user_context_cache[$user_id]); do_action('aksrt_badges_changed', $user_id); return; } self::$user_context_cache = []; } public static function invalidate_cache(int $user_id = 0): void { self::clear_context($user_id); } /** * Notify user when a badge is granted (zibll user_add_medal message). */ public function on_badge_granted_notify(int $user_id, string $slug, int $actor = 0): void { if ($user_id <= 0 || $slug === '') { return; } $map = self::get_dictionary_map(); if (!isset($map[$slug])) { return; } $label = (string) ($map[$slug]['label'] ?? $slug); $title = sprintf( /* translators: %s badge name */ __('恭喜您!获得新的徽章[%s]', 'aksrt'), $label ); $content = sprintf( /* translators: %s badge name */ __('恭喜您获得徽章「%s」', 'aksrt'), $label ); if (class_exists('\AKSRT\Messages\Message')) { \AKSRT\Messages\Message::get_instance()->send($user_id, 'medal', $content, [ 'title' => $title, 'target_url' => function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : home_url('/'), 'slug' => $slug, ]); } } public static function enabled(): bool { if (!class_exists('\AKSRT\Settings\Settings')) { return false; } $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); return !empty($settings['medal']['enabled']); } public static function public_display(): bool { if (!class_exists('\AKSRT\Settings\Settings')) { return false; } $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); return !empty($settings['medal']['enabled']) && !empty($settings['medal']['public_display']); } /** * @return list */ public static function get_dictionary(): array { if (self::$dictionary_cache !== null) { return self::$dictionary_cache; } if (!class_exists('\AKSRT\Settings\Settings')) { return self::$dictionary_cache = []; } $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); $medal = is_array($settings['medal'] ?? null) ? $settings['medal'] : []; $dict = []; foreach ((array) ($medal['items_by_slug'] ?? []) as $item) { if (!is_array($item)) { continue; } $dict[] = [ 'slug' => sanitize_key((string) ($item['slug'] ?? '')), 'label' => (string) ($item['name'] ?? $item['slug'] ?? ''), 'tone' => 'neutral', 'desc' => (string) ($item['desc'] ?? ''), 'icon_url' => (string) ($item['icon'] ?? ''), ]; } $out = []; foreach ($dict as $item) { $slug = sanitize_key((string) ($item['slug'] ?? '')); if ($slug === '') { continue; } $out[] = [ 'slug' => $slug, 'label' => (string) ($item['label'] ?? $slug), 'tone' => (string) ($item['tone'] ?? 'neutral'), 'desc' => (string) ($item['desc'] ?? ''), 'icon_url' => (string) ($item['icon_url'] ?? ''), ]; } return self::$dictionary_cache = $out; } /** * @return array */ public static function get_dictionary_map(): array { static $map = null; if ($map !== null) { return $map; } $map = []; foreach (self::get_dictionary() as $item) { $map[$item['slug']] = $item; } return $map; } /** @return array{owned_map:array,owned:list,wear:string} */ private static function user_context(int $user_id): array { if ($user_id <= 0) { return ['owned_map' => [], 'owned' => [], 'wear' => '']; } if (isset(self::$user_context_cache[$user_id])) { return self::$user_context_cache[$user_id]; } $raw = get_user_meta($user_id, self::META_OWNED, true); $raw = is_array($raw) ? $raw : []; $map = self::get_dictionary_map(); $owned_map = []; foreach ($raw as $slug => $time) { $slug = sanitize_key((string) $slug); if ($slug === '' || !isset($map[$slug])) { continue; } $owned_map[$slug] = is_string($time) ? $time : ''; } $owned = array_keys($owned_map); $wear = sanitize_key((string) get_user_meta($user_id, self::META_WEAR, true)); if ($wear === '') { $wear = $owned[0] ?? ''; } elseif (!in_array($wear, $owned, true)) { $wear = ''; } return self::$user_context_cache[$user_id] = [ 'owned_map' => $owned_map, 'owned' => $owned, 'wear' => $wear, ]; } /** * Owned badge map: slug => grant time (`Y-m-d H:i:s`), newest first. * * @return array */ public static function get_owned_map(int $user_id): array { return self::user_context($user_id)['owned_map']; } /** * Owned badge slugs, newest first. * * @return list */ public static function get_owned(int $user_id): array { return self::user_context($user_id)['owned']; } /** * Replace the owned set; existing slugs keep their grant time, new slugs * are stamped with the current time. Order follows the input list. * * @param list $slugs */ public static function set_owned(int $user_id, array $slugs): void { if ($user_id <= 0) { return; } $map = self::get_dictionary_map(); $existing = self::get_owned_map($user_id); $now = current_time('Y-m-d H:i:s'); $clean = []; foreach ($slugs as $slug) { $slug = sanitize_key((string) $slug); if ($slug === '' || !isset($map[$slug]) || isset($clean[$slug])) { continue; } $clean[$slug] = $existing[$slug] ?? $now; } update_user_meta($user_id, self::META_OWNED, $clean); $wear = self::get_wear($user_id); if ($wear !== '' && !isset($clean[$wear])) { delete_user_meta($user_id, self::META_WEAR); } self::clear_context($user_id); } public static function get_wear(int $user_id): string { return self::user_context($user_id)['wear']; } /** * @return true|\WP_Error */ public static function wear(int $user_id, string $slug) { if ($user_id <= 0) { return new \WP_Error('aksrt_badge_user', __('无效用户', 'aksrt'), ['status' => 400]); } if (!self::enabled()) { return new \WP_Error('aksrt_badge_disabled', __('徽章系统未启用', 'aksrt'), ['status' => 403]); } $slug = sanitize_key($slug); $map = self::get_dictionary_map(); if ($slug === '' || !isset($map[$slug])) { return new \WP_Error('aksrt_badge_unknown', __('徽章不存在', 'aksrt'), ['status' => 404]); } $owned = self::get_owned($user_id); if (!in_array($slug, $owned, true)) { return new \WP_Error('aksrt_badge_not_owned', __('尚未获得该徽章', 'aksrt'), ['status' => 403]); } update_user_meta($user_id, self::META_WEAR, $slug); self::clear_context($user_id); return true; } /** * @return true|\WP_Error */ public static function grant(int $user_id, string $slug, int $actor = 0) { if ($user_id <= 0) { return new \WP_Error('aksrt_badge_user', __('无效用户', 'aksrt'), ['status' => 400]); } if (!self::enabled()) { return new \WP_Error('aksrt_badge_disabled', __('徽章系统未启用', 'aksrt'), ['status' => 403]); } $slug = sanitize_key($slug); $map = self::get_dictionary_map(); if ($slug === '' || !isset($map[$slug])) { return new \WP_Error('aksrt_badge_unknown', __('徽章不存在', 'aksrt'), ['status' => 404]); } $owned = self::get_owned($user_id); if (in_array($slug, $owned, true)) { return true; } // Newest first (zibll medal ordering); grant time stamped by set_owned. self::set_owned($user_id, array_merge([$slug], $owned)); /** * Fires after a badge is granted. * * @param int $user_id * @param string $slug * @param int $actor */ do_action('aksrt_badge_granted', $user_id, $slug, $actor); return true; } /** * @return true|\WP_Error */ public static function revoke(int $user_id, string $slug, int $actor = 0) { if ($user_id <= 0) { return new \WP_Error('aksrt_badge_user', __('无效用户', 'aksrt'), ['status' => 400]); } $slug = sanitize_key($slug); $owned = self::get_owned($user_id); $owned = array_values(array_filter($owned, static function ($s) use ($slug) { return $s !== $slug; })); self::set_owned($user_id, $owned); /** * @param int $user_id * @param string $slug * @param int $actor */ do_action('aksrt_badge_revoked', $user_id, $slug, $actor); return true; } public static function can_manually_set(int $actor = 0): bool { $actor = $actor > 0 ? $actor : get_current_user_id(); if ($actor <= 0) { return false; } if (user_can($actor, 'manage_options')) { return true; } return false; } /** Build the privacy-aware catalog used by the server-rendered modal. */ public static function list_for_user(int $user_id, bool $include_private = false): array { $enabled = self::enabled(); $public = self::public_display(); $viewer = get_current_user_id(); $is_self = $viewer > 0 && $viewer === $user_id; $is_manager = self::can_manually_set($viewer); $can_see = $include_private || $public || $is_self || $is_manager; if (!$enabled || !$can_see || $user_id <= 0) { return [ 'enabled' => $enabled, 'public_display' => $public, 'is_self' => $is_self, 'can_wear' => $is_self, 'user_id' => $user_id, 'wear' => '', 'count' => 0, 'show_unearned' => false, 'categories' => [], ]; } $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); $medal = is_array($settings['medal'] ?? null) ? $settings['medal'] : []; $catalog = is_array($medal['categories'] ?? null) ? $medal['categories'] : []; $context = self::user_context($user_id); $owned_map = $context['owned_map']; $wear = $context['wear']; $show_private = $include_private || $is_self || $is_manager; $show_unearned = $show_private; $categories = []; foreach ($catalog as $cat) { $cat_name = (string) ($cat['cat_name'] ?? ''); $rows = is_array($cat['items'] ?? null) ? $cat['items'] : []; $has_rows = []; $no_rows = []; foreach ($rows as $row) { if (!is_array($row)) { continue; } $slug = sanitize_key((string) ($row['slug'] ?? '')); if ($slug === '') { continue; } $has = isset($owned_map[$slug]); if (!$has && !$show_unearned) { continue; } $item = [ 'slug' => $slug, 'label' => (string) ($row['name'] ?? $slug), 'desc' => (string) ($row['desc'] ?? ''), 'icon_url' => (string) ($row['icon'] ?? ''), 'owned' => $has, 'wear' => $has && $slug === $wear, 'time' => $has && $show_private ? (string) $owned_map[$slug] : '', 'get_type' => sanitize_key((string) ($row['get_type'] ?? 'manually_add')), ]; // Owned first within each category (zibll is-has / no-has order). if ($has) { $has_rows[] = $item; } else { $no_rows[] = $item; } } $items = array_merge($has_rows, $no_rows); if (!$items) { continue; } $categories[] = [ 'cat_name' => $cat_name, 'items' => $items, ]; } return [ 'enabled' => true, 'public_display' => $public, 'is_self' => $is_self, 'can_wear' => $is_self, 'user_id' => $user_id, 'wear' => $wear, 'count' => count($owned_map), 'show_unearned' => $show_unearned, 'categories' => $categories, ]; } private static function ajax_nonce(): string { return 'aksrt_public_nonce'; } private static function ajax_error(string $message): void { wp_send_json_error(['message' => $message]); } private static function ajax_require_nonce(): void { $nonce = isset($_REQUEST['nonce']) ? sanitize_text_field(wp_unslash((string) $_REQUEST['nonce'])) : ''; if (!$nonce || !wp_verify_nonce($nonce, self::ajax_nonce())) { self::ajax_error(__('请求已过期,请刷新页面后重试', 'aksrt')); } } private static function ajax_user_id(): int { return isset($_REQUEST['id']) ? absint($_REQUEST['id']) : 0; } private static function ajax_slug(): string { return isset($_REQUEST['slug']) ? sanitize_key(wp_unslash((string) $_REQUEST['slug'])) : ''; } private static function icon_html(array $item, string $class = 'img-icon medal-icon'): string { $icon = esc_url((string) ($item['icon_url'] ?? '')); $label = esc_attr((string) ($item['label'] ?? __('徽章', 'aksrt'))); if ($icon !== '') { return '' . $label . ''; } return ''; } private static function item_by_slug(array $data, string $slug): array { foreach ((array) ($data['categories'] ?? []) as $category) { foreach ((array) ($category['items'] ?? []) as $item) { if ((string) ($item['slug'] ?? '') === $slug) return $item; } } return []; } private static function modal_header(int $user_id, string $text): string { $avatar = function_exists('aksrt_get_avatar_html') ? aksrt_get_avatar_html($user_id, 42, ['class' => 'medal-modal__avatar']) : get_avatar($user_id, 42); return '
' . $avatar . '
' . $text . '
'; } private static function modal_info_html(int $user_id): string { $user = get_userdata($user_id); if (!$user) return '
' . esc_html__('用户不存在', 'aksrt') . '
'; if (!self::enabled()) return '
' . esc_html__('徽章系统未启用', 'aksrt') . '
'; $data = self::list_for_user($user_id); $name = $user_id === get_current_user_id() ? __('我的徽章', 'aksrt') : sprintf(__('%s的徽章', 'aksrt'), $user->display_name); $wear = self::item_by_slug($data, (string) ($data['wear'] ?? '')); if ($wear) $name .= self::icon_html($wear, 'img-icon medal-icon ml3'); elseif (!(int) ($data['count'] ?? 0)) $name .= '' . esc_html__('暂无徽章', 'aksrt') . ''; $html = '
' . self::modal_header($user_id, '' . wp_kses_post($name) . '') . '
'; $has = false; foreach ((array) ($data['categories'] ?? []) as $category) { $cards = ''; foreach ((array) ($category['items'] ?? []) as $item) { if (empty($item['owned']) && empty($data['show_unearned'])) continue; $has = true; $card = '
' . self::icon_html($item) . '
' . esc_html((string) $item['label']) . '
'; $url = add_query_arg(['action' => 'aksrt_single_medal_info_modal', 'name' => $item['slug'], 'user_id' => $user_id], admin_url('admin-ajax.php')); $cards .= ''; } if ($cards) $html .= '
' . esc_html((string) $category['cat_name']) . '
' . $cards . '
'; } if (!$has) $html .= '
' . esc_html__('暂无徽章', 'aksrt') . '
'; $html .= '
'; if ($user_id !== get_current_user_id()) { $mine = add_query_arg(['action' => 'aksrt_user_medal_info_modal', 'id' => get_current_user_id()], admin_url('admin-ajax.php')); $grant = add_query_arg(['action' => 'aksrt_user_medal_manually_add_modal', 'id' => $user_id], admin_url('admin-ajax.php')); $buttons = ''; if (get_current_user_id()) $buttons .= '' . esc_html__('查看我的徽章', 'aksrt') . ''; if (self::can_manually_set()) $buttons .= '' . esc_html__('授予徽章', 'aksrt') . ''; if ($buttons !== '') $html .= '
' . $buttons . '
'; } $html .= '
'; return $html; } private static function modal_single_html(int $user_id, string $slug): string { if (!$user_id || !get_userdata($user_id)) return '
' . esc_html__('用户不存在', 'aksrt') . '
'; if (!self::enabled()) return '
' . esc_html__('徽章系统未启用', 'aksrt') . '
'; $data = self::list_for_user($user_id); $item = self::item_by_slug($data, $slug); if (!$item) return '
' . esc_html__('参数传入错误或没有此徽章', 'aksrt') . '
'; $state = ''; if (!empty($item['owned']) && !empty($item['time'])) $state = '
' . esc_html(sprintf(__('%s 获得', 'aksrt'), $item['time'])) . '
'; elseif (empty($item['owned'])) $state = '
' . esc_html__('暂未获得', 'aksrt') . '
'; $html = '
' . self::icon_html($item) . '
' . esc_html($item['label']) . '
' . esc_html($item['desc']) . '
' . $state . '
'; if ($user_id === get_current_user_id() && !empty($item['owned'])) { if (!empty($item['wear'])) $html .= '
' . esc_html__('当前佩戴此徽章', 'aksrt') . '
'; else $html .= ''; } elseif ($user_id !== get_current_user_id() && self::can_manually_set() && !empty($item['owned'])) { $html .= ''; } elseif ($user_id !== get_current_user_id() && self::can_manually_set() && empty($item['owned']) && (($item['get_type'] ?? '') === 'manually_add')) { $html .= ''; } return $html . '
'; } public function ajax_info_modal(): void { echo self::modal_info_html(self::ajax_user_id()); exit; } public function ajax_single_modal(): void { echo self::modal_single_html(absint($_REQUEST['user_id'] ?? 0), sanitize_key(wp_unslash((string) ($_REQUEST['name'] ?? '')))); exit; } public function ajax_grant_modal(): void { $user_id = self::ajax_user_id(); if (!$user_id || !get_userdata($user_id)) { echo '
' . esc_html__('用户不存在', 'aksrt') . '
'; exit; } if (!self::enabled()) { echo '
' . esc_html__('徽章系统未启用', 'aksrt') . '
'; exit; } if (!self::can_manually_set()) { echo '
' . esc_html__('您没有此权限', 'aksrt') . '
'; exit; } $data = self::list_for_user($user_id, true); $html = '
' . self::modal_header($user_id, '' . sprintf(__('为%s授予新的徽章', 'aksrt'), esc_html(get_the_author_meta('display_name', $user_id))) . '') . '
'; $has = false; foreach ((array) ($data['categories'] ?? []) as $category) { $cards = ''; foreach ((array) ($category['items'] ?? []) as $item) { if (($item['get_type'] ?? '') !== 'manually_add') continue; $has = true; $action = !empty($item['owned']) ? 'revoke' : 'grant'; $label = $action === 'revoke' ? __('收回', 'aksrt') : __('授予', 'aksrt'); $cards .= '
' . self::icon_html($item) . '
' . esc_html($item['label']) . '
' . esc_html($item['desc']) . '
' . esc_html($label) . '
'; } if ($cards) $html .= '
' . esc_html($category['cat_name']) . '
' . $cards . '
'; } if (!$has) $html .= '
' . esc_html__('暂无可授予的徽章', 'aksrt') . '
'; echo $html . '
'; exit; } private function ajax_mutation(string $operation): void { self::ajax_require_nonce(); if (!is_user_logged_in()) self::ajax_error(__('请先登录', 'aksrt')); if (!self::enabled()) self::ajax_error(__('徽章系统未启用', 'aksrt')); $user_id = $operation === 'wear' ? get_current_user_id() : self::ajax_user_id(); $slug = self::ajax_slug(); if (!$user_id || !get_userdata($user_id) || !$slug) self::ajax_error(__('参数传入错误', 'aksrt')); if ($operation !== 'wear' && !self::can_manually_set()) self::ajax_error(__('暂无此权限', 'aksrt')); $item = self::item_by_slug(self::list_for_user($user_id, true), $slug); if (!$item) self::ajax_error(__('徽章不存在', 'aksrt')); if ($operation === 'grant' && ($item['get_type'] ?? '') !== 'manually_add') self::ajax_error(__('该徽章不可手动授予', 'aksrt')); if ($operation === 'revoke' && empty($item['owned'])) self::ajax_error(__('用户未获得该徽章', 'aksrt')); $result = $operation === 'wear' ? self::wear($user_id, $slug) : ($operation === 'grant' ? self::grant($user_id, $slug, get_current_user_id()) : self::revoke($user_id, $slug, get_current_user_id())); if (is_wp_error($result)) self::ajax_error($result->get_error_message()); $message = ['wear' => __('已佩戴徽章', 'aksrt'), 'grant' => __('已授予徽章', 'aksrt'), 'revoke' => __('已收回徽章', 'aksrt')][$operation]; wp_send_json_success(['message' => $message, 'reload' => true]); } public function ajax_wear(): void { $this->ajax_mutation('wear'); } public function ajax_grant(): void { $this->ajax_mutation('grant'); } public function ajax_revoke(): void { $this->ajax_mutation('revoke'); } /** * Auto-grant medals whose get_type metrics meet get_val (skip manually_add). */ public static function auto_evaluate(int $user_id): void { if ($user_id <= 0 || !self::enabled() || !class_exists('\AKSRT\Settings\Settings')) { return; } $settings = \AKSRT\Settings\Settings::get_user_identity_settings(); $medal = is_array($settings['medal'] ?? null) ? $settings['medal'] : []; $items = is_array($medal['items_by_slug'] ?? null) ? $medal['items_by_slug'] : []; if (!$items) { // Fall back to dictionary only — no get_type → nothing to auto-grant. return; } $owned = self::get_owned($user_id); $owned_map = array_fill_keys($owned, true); foreach ($items as $slug => $item) { if (!is_array($item)) { continue; } $slug = sanitize_key((string) $slug); if ($slug === '' || !empty($owned_map[$slug])) { continue; } $type = sanitize_key((string) ($item['get_type'] ?? 'manually_add')); if ($type === '' || $type === 'manually_add') { continue; } $need = max(0, (float) ($item['get_val'] ?? 0)); $have = (float) self::metric_value($user_id, $type); if ($have >= $need) { self::grant($user_id, $slug, 0); $owned_map[$slug] = true; } } } /** * Numeric metric for a medal get_type. */ public static function metric_value(int $user_id, string $type): float { switch ($type) { case 'registration_time': $user = get_userdata($user_id); if (!$user) { return 0.0; } $reg = get_date_from_gmt($user->user_registered, 'Y-m-d H:i:s'); $now = current_time('Y-m-d H:i:s'); return max(0.0, (strtotime($now) - strtotime($reg)) / 86400); case 'checkin_all_day': // Prefer dedicated check-in total meta if present. $v = get_user_meta($user_id, 'aksrt_checkin_all_day', true); if ($v === '' || $v === false) { $v = get_user_meta($user_id, 'checkin_all_day', true); } return max(0.0, (float) $v); case 'new_post': return (float) count_user_posts($user_id, 'post', true); case 'comment': $counts = get_comments(['user_id' => $user_id, 'count' => true, 'status' => 'approve']); return (float) $counts; case 'followed': if (class_exists('AKSRT\\User\\Follow')) { return (float) Follow::get_instance()->get_follower_count($user_id); } return 0.0; case 'like': return (float) get_user_meta($user_id, 'aksrt_posts_like_sum', true); case 'comment_like': return (float) get_user_meta($user_id, 'aksrt_comment_like_sum', true); case 'views': $sum = (float) get_user_meta($user_id, 'aksrt_posts_views_sum', true); if ($sum > 0) { return $sum; } // Lazy backfill once from postmeta. global $wpdb; $sum = (float) $wpdb->get_var($wpdb->prepare( "SELECT COALESCE(SUM(CAST(pm.meta_value AS UNSIGNED)),0) FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID AND pm.meta_key = 'aksrt_post_views' WHERE p.post_author = %d AND p.post_type = 'post' AND p.post_status = 'publish'", $user_id )); if ($sum > 0) { update_user_meta($user_id, 'aksrt_posts_views_sum', $sum); } return $sum; case 'pay_income': return (float) get_user_meta($user_id, 'aksrt_pay_income_sum', true); case 'pay_rebate': return (float) get_user_meta($user_id, 'aksrt_pay_rebate_sum', true); default: return 0.0; } } /** * @param string $user_login * @param \WP_User $user */ public function on_login($user_login, $user): void { $user_id = $user instanceof \WP_User ? (int) $user->ID : 0; if ($user_id > 0) { self::auto_evaluate($user_id); } } public function on_current_user_probe(): void { $uid = get_current_user_id(); if ($uid > 0) { self::auto_evaluate($uid); } } }