feat(user): complete growth level chain
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* Native WordPress user-level operations.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\User;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class LevelAdmin {
|
||||
|
||||
/** @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 {
|
||||
if (!is_admin()) {
|
||||
return;
|
||||
}
|
||||
add_filter('manage_users_columns', [$this, 'add_column']);
|
||||
add_filter('manage_users_custom_column', [$this, 'render_column'], 10, 3);
|
||||
add_filter('manage_users_sortable_columns', [$this, 'sortable_columns']);
|
||||
add_action('pre_get_users', [$this, 'sort_users']);
|
||||
add_filter('user_row_actions', [$this, 'add_row_action'], 25, 2);
|
||||
add_action('show_user_profile', [$this, 'render_section']);
|
||||
add_action('edit_user_profile', [$this, 'render_section']);
|
||||
add_action('personal_options_update', [$this, 'handle_update']);
|
||||
add_action('edit_user_profile_update', [$this, 'handle_update']);
|
||||
}
|
||||
|
||||
private function enabled(): bool {
|
||||
return class_exists(Level::class) && !empty(Level::settings()['enabled']);
|
||||
}
|
||||
|
||||
private function can_manage(int $user_id): bool {
|
||||
return current_user_can('manage_options') && current_user_can('edit_user', $user_id);
|
||||
}
|
||||
|
||||
public function add_column(array $columns): array {
|
||||
if ($this->enabled()) {
|
||||
$columns['aksrt_user_level'] = __('用户等级', 'aksrt');
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
public function render_column(string $output, string $column_name, int $user_id): string {
|
||||
if ($column_name !== 'aksrt_user_level' || !$this->enabled()) {
|
||||
return $output;
|
||||
}
|
||||
$level = Level::get_level($user_id);
|
||||
$icon = Level::get_badge_html($user_id, 'aksrt-user-level-icon--admin');
|
||||
return '<span style="display:inline-flex;align-items:center;gap:6px;">' . $icon
|
||||
. '<strong>' . esc_html(Level::get_level_name($level)) . '</strong>'
|
||||
. '<small>(' . esc_html((string) Level::get_integral($user_id)) . ' EXP)</small></span>';
|
||||
}
|
||||
|
||||
public function sortable_columns(array $columns): array {
|
||||
if ($this->enabled()) {
|
||||
$columns['aksrt_user_level'] = 'aksrt_user_level';
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
public function sort_users($query): void {
|
||||
if (!is_admin() || $query->get('orderby') !== 'aksrt_user_level') {
|
||||
return;
|
||||
}
|
||||
$query->set('meta_key', Level::META_INTEGRAL);
|
||||
$query->set('orderby', 'meta_value_num');
|
||||
}
|
||||
|
||||
public function add_row_action(array $actions, \WP_User $user): array {
|
||||
if ($this->enabled() && $this->can_manage((int) $user->ID)) {
|
||||
$url = get_edit_user_link((int) $user->ID);
|
||||
if ($url) {
|
||||
$actions['aksrt_edit_level'] = '<a href="' . esc_url($url . '#aksrt-user-level') . '">' . esc_html__('调整等级经验', 'aksrt') . '</a>';
|
||||
}
|
||||
}
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function render_section(\WP_User $user): void {
|
||||
if (!$this->enabled()) {
|
||||
return;
|
||||
}
|
||||
$progress = Level::get_progress((int) $user->ID);
|
||||
$can_manage = $this->can_manage((int) $user->ID);
|
||||
?>
|
||||
<a id="aksrt-user-level"></a>
|
||||
<h2><?php esc_html_e('用户等级(AKSRT)', 'aksrt'); ?></h2>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th><?php esc_html_e('当前等级', 'aksrt'); ?></th>
|
||||
<td>
|
||||
<span style="display:inline-flex;align-items:center;gap:8px;font-size:16px;">
|
||||
<?php echo Level::get_badge_html((int) $user->ID, 'aksrt-user-level-icon--admin'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<strong><?php echo esc_html((string) $progress['name']); ?></strong>
|
||||
</span>
|
||||
<p class="description"><?php printf(esc_html__('累计经验:%1$d;距离下一等级:%2$d', 'aksrt'), (int) $progress['integral'], (int) $progress['remaining']); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ($can_manage) : ?>
|
||||
<tr>
|
||||
<th><label for="aksrt_level_integral"><?php esc_html_e('累计经验值', 'aksrt'); ?></label></th>
|
||||
<td>
|
||||
<?php wp_nonce_field('aksrt_user_level_admin_' . (int) $user->ID, 'aksrt_user_level_nonce'); ?>
|
||||
<input type="number" class="regular-text" id="aksrt_level_integral" name="aksrt_level_integral" min="0" max="9999999999999999" step="1" value="<?php echo esc_attr((string) $progress['integral']); ?>">
|
||||
<p class="description"><?php esc_html_e('保存后按当前等级阈值重新计算等级。直接替换当前经验,不追加经验流水。', 'aksrt'); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function handle_update(int $user_id): void {
|
||||
if (!$this->enabled() || !$this->can_manage($user_id) || !isset($_POST['aksrt_user_level_nonce'])) {
|
||||
return;
|
||||
}
|
||||
$nonce = sanitize_text_field(wp_unslash((string) $_POST['aksrt_user_level_nonce']));
|
||||
if (!wp_verify_nonce($nonce, 'aksrt_user_level_admin_' . $user_id)) {
|
||||
return;
|
||||
}
|
||||
$integral = max(0, (int) ($_POST['aksrt_level_integral'] ?? 0));
|
||||
update_user_meta($user_id, Level::META_INTEGRAL, $integral);
|
||||
update_user_meta($user_id, Level::META_LEVEL, Level::resolve_level($integral));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user