前几天看到了,星空知发的在线用户,觉得挺不错,就想能不能把游客也显示出来
于是让AI改了一下,感觉似乎能用,也不知道准不准,反正能运行就不错了



// 初始化会话以追踪游客
function initialize_visitor_tracking() {
if (!session_id()) {
session_start();
}
}
add_action('init', 'initialize_visitor_tracking');
// 创建游客追踪表
function create_visitor_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'online_visitors';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
session_id varchar(255) NOT NULL,
ip_address varchar(45) NOT NULL,
user_agent text,
last_activity int(11) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY session_id (session_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 调试:检查表格是否创建成功
if($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
error_log("游客追踪表创建失败");
}
}
register_activation_hook(__FILE__, 'create_visitor_table');
// 追踪游客活动 - 修复计数问题
function track_visitor_activity() {
// 确保会话已启动
if (!session_id()) {
session_start();
}
if (!is_user_logged_in() && session_id()) {
global $wpdb;
$table_name = $wpdb->prefix . 'online_visitors';
$session_id = session_id();
$ip_address = $_SERVER['REMOTE_ADDR'];
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$current_time = time();
// 检查该会话是否已存在
$visitor = $wpdb->get_row(
$wpdb->prepare("SELECT id FROM $table_name WHERE session_id = %s", $session_id)
);
if ($visitor) {
// 更新现有游客
$wpdb->update(
$table_name,
array('last_activity' => $current_time),
array('session_id' => $session_id)
);
} else {
// 添加新游客
$wpdb->insert(
$table_name,
array(
'session_id' => $session_id,
'ip_address' => $ip_address,
'user_agent' => $user_agent,
'last_activity' => $current_time
)
);
}
// 清理过期游客数据(超过24小时)
$wpdb->query(
$wpdb->prepare("DELETE FROM $table_name WHERE last_activity < %d", $current_time - 86400)
);
}
}
// 提高优先级确保执行
add_action('init', 'track_visitor_activity', 5);
// 登录时设置活动状态
function track_user_login($user_login, $user) {
update_user_meta($user->ID, 'last_activity', time());
update_user_meta($user->ID, 'is_logged_in', '1');
// 登录后清除可能的游客记录
if (session_id()) {
global $wpdb;
$table_name = $wpdb->prefix . 'online_visitors';
$wpdb->delete(
$table_name,
array('session_id' => session_id())
);
}
}
add_action('wp_login', 'track_user_login', 10, 2);
// 每次页面加载时更新活动时间
function update_user_activity() {
if (is_user_logged_in()) {
$user_id = get_current_user_id();
update_user_meta($user_id, 'last_activity', time());
update_user_meta($user_id, 'is_logged_in', '1');
}
}
add_action('init', 'update_user_activity');
// 登出时更新状态
function track_user_logout() {
$user_id = get_current_user_id();
update_user_meta($user_id, 'is_logged_in', '0');
}
add_action('wp_logout', 'track_user_logout');
class Online_Users_Widget extends WP_Widget {
// 构造函数
function __construct() {
parent::__construct(
'online_users_widget',
__('在线用户', 'text_domain'),
array(
'description' => __('实时显示在线用户和游客列表', 'text_domain'),
'classname' => 'widget_online_users'
)
);
}
// 前端显示(带实时更新和悬浮效果)
public function widget($args, $instance) {
// 获取设置
$title = apply_filters('widget_title', empty($instance['title']) ? __('在线用户', 'text_domain') : $instance['title']);
$inactive_time = empty($instance['inactive_time']) ? 60 : absint($instance['inactive_time']);
$show_count = !empty($instance['show_count']);
$show_guests = !empty($instance['show_guests']);
$refresh_interval = empty($instance['refresh_interval']) ? 30 : absint($instance['refresh_interval']);
$guest_avatar_url = empty($instance['guest_avatar_url']) ? '' : esc_url($instance['guest_avatar_url']);
// 使用默认头像如果未设置
if (empty($guest_avatar_url)) {
$guest_avatar_url = plugins_url('guest-avatar.png', __FILE__);
}
// 生成唯一ID用于JS更新
$widget_id = 'online-users-widget-' . $this->id;
// 开始输出
echo $args['before_widget'];
echo '<div id="' . esc_attr($widget_id) . '" class="online-users-container">';
if (!empty($title)) {
echo $args['before_title'] . '<span class="online-title-icon">👥</span>' . esc_html($title) . $args['after_title'];
}
// 显示加载状态
echo '<div class="online-users-loading">';
echo '<div class="loading-spinner"></div>';
echo '<p>' . __('加载中...', 'text_domain') . '</p>';
echo '</div>';
// 内容将通过JS动态加载
echo '<div class="online-users-content" style="display: none;"></div>';
echo '</div>'; // .online-users-container
echo $args['after_widget'];
// 输出JS配置
?>
<script type="text/javascript">
// 在线用户组件配置
var onlineUsersConfig = {
widgetId: '<?php echo esc_js($widget_id); ?>',
inactiveTime: <?php echo esc_js($inactive_time); ?>,
showGuests: <?php echo esc_js($show_guests ? 'true' : 'false'); ?>,
showCount: <?php echo esc_js($show_count ? 'true' : 'false'); ?>,
refreshInterval: <?php echo esc_js($refresh_interval * 1000); ?>,
guestAvatarUrl: '<?php echo esc_js($guest_avatar_url); ?>',
ajaxUrl: '<?php echo esc_js(admin_url('admin-ajax.php')); ?>',
nonce: '<?php echo esc_js(wp_create_nonce('online_users_nonce')); ?>'
};
// 初始化并加载数据
document.addEventListener('DOMContentLoaded', function() {
loadOnlineUsersData(onlineUsersConfig);
// 设置定时刷新
setInterval(function() {
loadOnlineUsersData(onlineUsersConfig);
}, onlineUsersConfig.refreshInterval);
});
// 加载在线用户数据
function loadOnlineUsersData(config) {
var container = document.getElementById(config.widgetId);
var loading = container.querySelector('.online-users-loading');
var content = container.querySelector('.online-users-content');
// 显示加载状态
loading.style.display = 'block';
content.style.display = 'none';
// AJAX请求
var xhr = new XMLHttpRequest();
xhr.open('POST', config.ajaxUrl, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// 隐藏加载状态
loading.style.display = 'none';
if (xhr.status === 200) {
try {
var response = JSON.parse(xhr.responseText);
if (response.success) {
// 替换游客头像URL
var html = response.data.html;
if (config.guestAvatarUrl) {
html = html.replace(/guest-avatar\.png[^"]*/g, config.guestAvatarUrl);
}
content.innerHTML = html;
content.style.display = 'block';
// 添加淡入动画
content.style.opacity = '0';
var opacity = 0;
var interval = setInterval(function() {
if (opacity >= 1) {
clearInterval(interval);
}
content.style.opacity = opacity;
opacity += 0.1;
}, 30);
}
} catch (e) {
console.error('解析在线用户数据失败:', e);
}
}
}
};
// 发送请求数据
var data = 'action=get_online_users_data' +
'&nonce=' + encodeURIComponent(config.nonce) +
'&inactive_time=' + encodeURIComponent(config.inactiveTime) +
'&show_guests=' + encodeURIComponent(config.showGuests ? 1 : 0) +
'&show_count=' + encodeURIComponent(config.showCount ? 1 : 0);
xhr.send(data);
}
</script>
<?php
}
// 相对时间显示
private function relative_time($timestamp) {
$current_time = time();
$diff = $current_time - $timestamp;
if ($diff < 60) {
return __('刚刚在线', 'text_domain');
} elseif ($diff < 3600) {
return sprintf(__('%d分钟前', 'text_domain'), floor($diff/60));
} elseif ($diff < 86400) {
return sprintf(__('%d小时前', 'text_domain'), floor($diff/3600));
} else {
return date(__('Y年m月d日', 'text_domain'), $timestamp);
}
}
// 后台表单 - 新增游客头像设置
public function form($instance) {
$defaults = array(
'title' => __('在线用户', 'text_domain'),
'inactive_time' => 60,
'show_count' => true,
'show_guests' => true,
'refresh_interval' => 30,
'guest_avatar_url' => '' // 游客头像URL设置
);
$instance = wp_parse_args((array) $instance, $defaults);
?>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('标题:'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
name="<?php echo $this->get_field_name('title'); ?>"
type="text" value="<?php echo esc_attr($instance['title']); ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id('inactive_time'); ?>"><?php _e('视为在线的时间(秒):'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('inactive_time'); ?>"
name="<?php echo $this->get_field_name('inactive_time'); ?>"
type="number" min="60" value="<?php echo esc_attr($instance['inactive_time']); ?>" />
<small><?php _e('默认60秒'); ?></small>
</p>
<p>
<label for="<?php echo $this->get_field_id('refresh_interval'); ?>"><?php _e('刷新间隔(秒):'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('refresh_interval'); ?>"
name="<?php echo $this->get_field_name('refresh_interval'); ?>"
type="number" min="5" value="<?php echo esc_attr($instance['refresh_interval']); ?>" />
<small><?php _e('默认30秒,建议不小于5秒'); ?></small>
</p>
<p>
<label for="<?php echo $this->get_field_id('guest_avatar_url'); ?>"><?php _e('游客头像URL:'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('guest_avatar_url'); ?>"
name="<?php echo $this->get_field_name('guest_avatar_url'); ?>"
type="url" placeholder="https://example.com/guest-avatar.png"
value="<?php echo esc_attr($instance['guest_avatar_url']); ?>" />
<small><?php _e('留空则使用默认头像'); ?></small>
</p>
<p>
<input class="checkbox" type="checkbox" id="<?php echo $this->get_field_id('show_count'); ?>"
name="<?php echo $this->get_field_name('show_count'); ?>"
<?php checked($instance['show_count'], true); ?> />
<label for="<?php echo $this->get_field_id('show_count'); ?>"><?php _e('显示在线人数'); ?></label>
</p>
<p>
<input class="checkbox" type="checkbox" id="<?php echo $this->get_field_id('show_guests'); ?>"
name="<?php echo $this->get_field_name('show_guests'); ?>"
<?php checked($instance['show_guests'], true); ?> />
<label for="<?php echo $this->get_field_id('show_guests'); ?>"><?php _e('显示游客'); ?></label>
</p>
<?php
}
// 更新设置
public function update($new_instance, $old_instance) {
$instance = $old_instance;
$instance['title'] = sanitize_text_field($new_instance['title']);
$instance['inactive_time'] = absint($new_instance['inactive_time']);
$instance['show_count'] = !empty($new_instance['show_count']);
$instance['show_guests'] = !empty($new_instance['show_guests']);
$instance['refresh_interval'] = absint($new_instance['refresh_interval']);
$instance['guest_avatar_url'] = esc_url_raw($new_instance['guest_avatar_url']); // 保存游客头像URL
return $instance;
}
// 获取在线用户和游客 - 修复计数问题
public function get_online_data($inactive_time = 60, $show_guests = true) {
$current_time = time();
$online_users = array();
$online_guests = 0;
// 获取在线用户
$users = get_users(array(
'meta_query' => array(
array(
'key' => 'last_activity',
'compare' => 'EXISTS'
)
)
));
foreach ($users as $user) {
$last_activity = (int)get_user_meta($user->ID, 'last_activity', true);
$is_logged_in = get_user_meta($user->ID, 'is_logged_in', true);
if (($current_time - $last_activity <= $inactive_time) && $is_logged_in === '1') {
$online_users[$user->ID] = $user;
}
}
// 获取在线游客数量 - 修复计数逻辑
if ($show_guests) {
global $wpdb;
$table_name = $wpdb->prefix . 'online_visitors';
// 确保表格存在
if($wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name) {
$online_guests = $wpdb->get_var(
$wpdb->prepare("SELECT COUNT(*) FROM $table_name WHERE last_activity >= %d", $current_time - $inactive_time)
);
} else {
// 表格不存在时尝试重新创建
create_visitor_table();
$online_guests = 0;
error_log("游客表不存在,已尝试重新创建");
}
}
return array(
'users' => $online_users,
'guests' => $online_guests ? $online_guests : 0
);
}
// 生成在线用户列表HTML - 用于AJAX响应
public function generate_online_html($data, $show_count = true, $show_guests = true) {
$online_users = $data['users'];
$online_guests = $data['guests'];
$html = '';
// 显示用户和游客数量
if ($show_count) {
$html .= '<div class="online-users-count">';
$html .= '<span class="count-bubble">' . (count($online_users) + $online_guests) . '</span>';
$total = count($online_users) + $online_guests;
$users_text = sprintf(
_n(' %d 位用户', ' %d 位用户', count($online_users), 'text_domain'),
count($online_users)
);
$guests_text = '';
if ($show_guests) {
$guests_text = sprintf(
_n(',%d 位游客', ',%d 位游客', $online_guests, 'text_domain'),
$online_guests
);
}
$html .= sprintf(
__('当前共有 %d 位访问者' . $users_text . $guests_text, 'text_domain'),
$total
);
$html .= '</div>';
}
// 显示用户列表
if (!empty($online_users) || ($show_guests && $online_guests > 0)) {
$html .= '<ul class="online-users-list">';
// 显示登录用户
foreach ($online_users as $user) {
$display_name = !empty($user->display_name) ? $user->display_name : $user->user_login;
$avatar = get_avatar($user->ID, 96);
$user_link = get_author_posts_url($user->ID);
$last_active = $this->relative_time((int)get_user_meta($user->ID, 'last_activity', true));
$html .= '<li class="online-user">';
$html .= '<a href="' . esc_url($user_link) . '" rel="external nofollow" class="user-card" title="' . esc_attr($display_name) . '">';
$html .= '<div class="avatar-container">';
$html .= $avatar;
$html .= '<span class="online-status user-status" title="用户在线"></span>';
$html .= '</div>';
$html .= '<span class="online-user-name">' . esc_html($display_name) . '</span>';
// 悬浮卡片
$html .= '<div class="user-hover-card">';
$html .= '<div class="hover-avatar">' . get_avatar($user->ID, 120) . '</div>';
$html .= '<h4>' . esc_html($display_name) . '</h4>';
$html .= '<p><i class="activity-icon"></i> ' . esc_html($last_active) . '</p>';
$html .= '<p class="user-type">' . __('注册用户', 'text_domain') . '</p>';
$html .= '</div>';
$html .= '</a>';
$html .= '</li>';
}
// 显示游客
if ($show_guests && $online_guests > 0) {
$html .= '<li class="online-guest">';
$html .= '<div class="guest-card" title="' . sprintf(__('%d位游客在线', 'text_domain'), $online_guests) . '">';
$html .= '<div class="avatar-container">';
$html .= '<img src="guest-avatar.png" alt="' . __('游客', 'text_domain') . '" class="avatar guest-avatar">';
$html .= '<span class="online-status guest-status" title="游客在线"></span>';
$html .= '</div>';
$html .= '<span class="online-guest-count">' . sprintf(__('%d位游客', 'text_domain'), $online_guests) . '</span>';
// 游客悬浮卡片
$html .= '<div class="guest-hover-card">';
$html .= '<h4>' . __('在线游客', 'text_domain') . '</h4>';
$html .= '<p>' . sprintf(__('当前有 %d 位游客正在访问', 'text_domain'), $online_guests) . '</p>';
$html .= '</div>';
$html .= '</div>';
$html .= '</li>';
}
$html .= '</ul>';
} else {
$html .= '<div class="no-online-users">';
$html .= '<div class="empty-state">';
$html .= '<span class="empty-icon">👻</span>';
$html .= '<p>' . __('当前没有用户和游客在线', 'text_domain') . '</p>';
$html .= '</div>';
$html .= '</div>';
}
return $html;
}
}
// 注册小工具
function register_online_users_widget() {
register_widget('Online_Users_Widget');
}
add_action('widgets_init', 'register_online_users_widget');
// AJAX处理函数 - 用于实时获取在线用户数据
function handle_online_users_ajax() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'online_users_nonce')) {
wp_send_json_error(array('message' => '验证失败'));
}
// 获取参数
$inactive_time = isset($_POST['inactive_time']) ? absint($_POST['inactive_time']) : 60;
$show_guests = isset($_POST['show_guests']) ? (bool)$_POST['show_guests'] : true;
$show_count = isset($_POST['show_count']) ? (bool)$_POST['show_count'] : true;
// 实例化小工具类并获取数据
$widget = new Online_Users_Widget();
$online_data = $widget->get_online_data($inactive_time, $show_guests);
$html = $widget->generate_online_html($online_data, $show_count, $show_guests);
// 返回结果
wp_send_json_success(array('html' => $html));
}
add_action('wp_ajax_get_online_users_data', 'handle_online_users_ajax');
add_action('wp_ajax_nopriv_get_online_users_data', 'handle_online_users_ajax'); // 允许未登录用户访问
//初始化用户状态
function initialize_user_status() {
if (!get_option('online_users_status_initialized')) {
$users = get_users();
foreach ($users as $user) {
if (!metadata_exists('user', $user->ID, 'is_logged_in')) {
update_user_meta($user->ID, 'is_logged_in', '0');
}
if (!metadata_exists('user', $user->ID, 'last_activity')) {
update_user_meta($user->ID, 'last_activity', time());
}
}
// 确保游客表已创建
create_visitor_table();
update_option('online_users_status_initialized', true);
}
}
add_action('admin_init', 'initialize_user_status');
// CSS样式 - 深色模式改为#323335
function online_users_widget_styles() {
?>
<style>
/* 基础样式 - 优化阴影 */
.widget_online_users {
background: linear-gradient(135deg, #f5f7fa 0%, #f8fafc 100%);
border-radius: 16px;
box-shadow:
0 1px 1px rgba(0,0,0,0.02),
0 2px 2px rgba(0,0,0,0.02),
0 4px 4px rgba(0,0,0,0.02),
0 8px 8px rgba(0,0,0,0.03),
0 16px 16px rgba(0,0,0,0.03);
padding: 25px;
margin-bottom: 30px;
border: 1px solid rgba(255,255,255,0.5);
backdrop-filter: blur(8px);
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.widget_online_users:hover {
box-shadow:
0 1px 1px rgba(0,0,0,0.03),
0 2px 2px rgba(0,0,0,0.03),
0 4px 4px rgba(0,0,0,0.03),
0 8px 8px rgba(0,0,0,0.04),
0 16px 16px rgba(0,0,0,0.04),
0 24px 24px rgba(0,0,0,0.05);
transform: translateY(-3px) scale(1.005);
}
/* 标题样式 */
.widget_online_users .widget-title {
font-size: 1.3em;
color: #2d3748;
margin-bottom: 20px;
padding-bottom: 12px;
border-bottom: 1px solid rgba(0,0,0,0.05);
display: flex;
align-items: center;
font-weight: 600;
}
.online-title-icon {
margin-right: 10px;
font-size: 1.2em;
filter: drop-shadow(0 1px 1px rgba(0,0,0,0.1));
}
/* 在线人数统计 */
.widget_online_users .online-users-count {
background: rgba(74, 85, 104, 0.1);
padding: 8px 15px;
border-radius: 50px;
font-size: 0.9em;
color: #4a5568;
margin-bottom: 20px;
display: inline-flex;
align-items: center;
transition: all 0.3s ease;
}
.widget_online_users .online-users-count:hover {
background: rgba(74, 85, 104, 0.2);
}
.count-bubble {
background: linear-gradient(135deg, #4CAF50 0%, #81C784 100%);
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
margin-right: 8px;
font-size: 0.8em;
font-weight: bold;
box-shadow:
0 1px 1px rgba(76, 175, 80, 0.2),
0 2px 2px rgba(76, 175, 80, 0.15),
0 4px 4px rgba(76, 175, 80, 0.1);
}
/* 用户列表 */
.widget_online_users .online-users-list {
list-style: none;
padding: 0;
margin: 0 -5px;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
/* 单个用户项 */
.widget_online_users .online-user,
.widget_online_users .online-guest {
display: flex;
flex-direction: column;
align-items: center;
width: 80px;
margin: 0 5px 15px;
position: relative;
}
.widget_online_users .user-card,
.widget_online_users .guest-card {
display: flex;
flex-direction: column;
align-items: center;
text-decoration: none;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
position: relative;
will-change: transform;
}
.widget_online_users .user-card:hover,
.widget_online_users .guest-card:hover {
transform: translateY(-5px);
}
/* 头像容器 */
.widget_online_users .avatar-container {
position: relative;
margin-bottom: 8px;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
will-change: transform;
}
.widget_online_users .user-card:hover .avatar-container,
.widget_online_users .guest-card:hover .avatar-container {
transform: scale(1.05);
}
/* 用户头像和游客头像 */
.widget_online_users .online-user img.avatar,
.widget_online_users .guest-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
object-fit: cover;
border: 3px solid white;
box-shadow:
0 1px 1px rgba(0,0,0,0.05),
0 2px 2px rgba(0,0,0,0.05),
0 4px 4px rgba(0,0,0,0.05),
0 6px 6px rgba(0,0,0,0.06);
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.widget_online_users .guest-avatar {
background-color: #e2e8f0;
padding: 8px;
box-sizing: border-box;
}
.widget_online_users .user-card:hover img.avatar,
.widget_online_users .guest-card:hover .guest-avatar {
box-shadow:
0 2px 2px rgba(0,0,0,0.06),
0 4px 4px rgba(0,0,0,0.06),
0 8px 8px rgba(0,0,0,0.07),
0 12px 12px rgba(0,0,0,0.08);
}
/* 在线状态指示器 */
.widget_online_users .online-status {
position: absolute;
bottom: 5px;
right: 5px;
width: 14px;
height: 14px;
border-radius: 50%;
box-shadow:
0 0 0 1px rgba(76, 175, 80, 0.2),
0 0 0 2px rgba(76, 175, 80, 0.15);
animation: pulse 1.5s infinite;
z-index: 2;
}
.widget_online_users .user-status {
background: linear-gradient(135deg, #4CAF50 0%, #81C784 100%);
border: 2px solid white;
}
.widget_online_users .guest-status {
background: linear-gradient(135deg, #FFB74D 0%, #FFCC80 100%);
border: 2px solid white;
}
/* 用户名和游客数量 */
.widget_online_users .online-user-name,
.widget_online_users .online-guest-count {
font-size: 0.8em;
color: #4a5568;
text-align: center;
word-break: break-word;
line-height: 1.4;
font-weight: 500;
transition: all 0.3s ease;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.widget_online_users .user-card:hover .online-user-name,
.widget_online_users .guest-card:hover .online-guest-count {
color: #2d3748;
font-weight: 600;
}
/* 用户类型标签 */
.widget_online_users .user-type {
font-size: 0.8em;
color: #718096;
margin-top: 5px;
padding-top: 5px;
border-top: 1px dashed rgba(0,0,0,0.05);
}
/* 悬浮卡片 */
.widget_online_users .user-hover-card,
.widget_online_users .guest-hover-card {
position: absolute;
bottom: calc(100% + 10px);
left: 50%;
transform: translateX(-50%) translateY(10px);
width: 180px;
background: white;
border-radius: 12px;
padding: 15px;
opacity: 0;
visibility: hidden;
transition:
opacity 0.3s ease-out,
transform 0.4s cubic-bezier(0.23, 1, 0.32, 1);
z-index: 10;
pointer-events: none;
text-align: center;
}
.widget_online_users .user-card:hover .user-hover-card,
.widget_online_users .guest-card:hover .guest-hover-card {
opacity: 1;
visibility: visible;
transform: translateX(-50%) translateY(0);
}
/* 加载状态样式 */
.online-users-loading {
text-align: center;
padding: 20px 0;
}
.loading-spinner {
width: 40px;
height: 40px;
margin: 0 auto 10px;
border: 3px solid rgba(76, 175, 80, 0.2);
border-radius: 50%;
border-top-color: #4CAF50;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* 添加卡片升起时的微光效果 */
.widget_online_users .user-hover-card::before,
.widget_online_users .guest-hover-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 40%;
background: linear-gradient(to bottom, rgba(255,255,255,0.8) 0%, rgba(255,255,255,0) 100%);
border-radius: 12px 12px 0 0;
opacity: 0;
transition: opacity 0.4s ease;
}
.widget_online_users .user-card:hover .user-hover-card::before,
.widget_online_users .guest-card:hover .guest-hover-card::before {
opacity: 0.6;
}
/* 优化卡片内容过渡 */
.widget_online_users .user-hover-card > *,
.widget_online_users .guest-hover-card > * {
transform: translateY(5px);
opacity: 0.9;
transition:
transform 0.4s cubic-bezier(0.23, 1, 0.32, 1),
opacity 0.4s ease;
}
.widget_online_users .user-card:hover .user-hover-card > *,
.widget_online_users .guest-card:hover .guest-hover-card > * {
transform: translateY(0);
opacity: 1;
}
/* 延迟子元素动画 */
.widget_online_users .user-hover-card .hover-avatar,
.widget_online_users .guest-hover-card h4 {
transition-delay: 0.05s;
}
.widget_online_users .user-hover-card h4,
.widget_online_users .guest-hover-card p {
transition-delay: 0.1s;
}
.widget_online_users .user-hover-card p {
transition-delay: 0.15s;
}
.activity-icon {
display: inline-block;
width: 12px;
height: 12px;
background: #4CAF50;
border-radius: 50%;
margin-right: 5px;
animation: pulse 1.5s infinite;
}
/* 无用户状态 */
.widget_online_users .no-online-users {
padding: 20px 0;
}
.widget_online_users .empty-state {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.widget_online_users .empty-icon {
font-size: 2em;
opacity: 0.5;
margin-bottom: 10px;
filter: drop-shadow(0 1px 1px rgba(0,0,0,0.1));
}
.widget_online_users .empty-state p {
margin: 0;
color: #718096;
font-size: 0.9em;
}
@keyframes pulse {
0% {
transform: scale(0.95);
box-shadow:
0 0 0 0 rgba(76, 175, 80, 0.4),
0 0 0 1px rgba(76, 175, 80, 0.3);
}
70% {
transform: scale(1.05);
box-shadow:
0 0 0 4px rgba(76, 175, 80, 0.1),
0 0 0 6px rgba(76, 175, 80, 0);
}
100% {
transform: scale(0.95);
box-shadow:
0 0 0 0 rgba(76, 175, 80, 0),
0 0 0 1px rgba(76, 175, 80, 0.1);
}
}
@media (max-width: 480px) {
.widget_online_users {
padding: 20px 15px;
border-radius: 12px;
}
.widget_online_users .online-user,
.widget_online_users .online-guest {
width: 70px;
}
.widget_online_users .online-user img.avatar,
.widget_online_users .guest-avatar {
width: 50px;
height: 50px;
}
.widget_online_users .user-hover-card,
.widget_online_users .guest-hover-card {
width: 160px;
padding: 12px;
}
}
/* Zibll主题夜间模式适配(使用#323335深色) */
.dark-theme .widget_online_users {
background: #323335;
border-color: rgba(255,255,255,0.08);
}
.dark-theme .widget_online_users .widget-title {
color: #e2e8f0;
border-bottom-color: rgba(255,255,255,0.08);
}
.dark-theme .widget_online_users .online-title-icon {
filter: drop-shadow(0 1px 1px rgba(0,0,0,0.3));
}
.dark-theme .widget_online_users .online-users-count {
background: rgba(255,255,255,0.08);
color: #e2e8f0;
}
.dark-theme .widget_online_users .online-users-count:hover {
background: rgba(255,255,255,0.12);
}
.dark-theme .widget_online_users .online-user-name,
.dark-theme .widget_online_users .online-guest-count {
color: #cbd5e0;
}
.dark-theme .widget_online_users .user-card:hover .online-user-name,
.dark-theme .widget_online_users .guest-card:hover .online-guest-count {
color: #f7fafc;
}
.dark-theme .widget_online_users .online-user img.avatar,
.dark-theme .widget_online_users .guest-avatar {
border-color: #323335;
box-shadow:
0 1px 1px rgba(0,0,0,0.2),
0 2px 2px rgba(0,0,0,0.2),
0 4px 4px rgba(0,0,0,0.2);
}
.dark-theme .widget_online_users .guest-avatar {
background-color: #4a5568;
}
.dark-theme .widget_online_users .user-status {
border-color: #323335;
}
.dark-theme .widget_online_users .guest-status {
border-color: #323335;
}
.dark-theme .widget_online_users .user-type {
color: #a0aec0;
border-top-color: rgba(255,255,255,0.05);
}
.dark-theme .widget_online_users .user-hover-card,
.dark-theme .widget_online_users .guest-hover-card {
background: #323335;
border: 1px solid rgba(255,255,255,0.08);
}
.dark-theme .widget_online_users .user-hover-card::before,
.dark-theme .widget_online_users .guest-hover-card::before {
background: linear-gradient(to bottom, rgba(50,51,53,0.9) 0%, rgba(50,51,53,0) 100%);
}
.dark-theme .online-users-loading p {
color: #e2e8f0;
}
.dark-theme .loading-spinner {
border-color: rgba(76, 175, 80, 0.1);
border-top-color: #81C784;
}
.dark-theme .widget_online_users .empty-state p {
color: #a0aec0;
}
.dark-theme .widget_online_users .empty-icon {
filter: drop-shadow(0 1px 1px rgba(0,0,0,0.3));
}
</style>
<?php
}
add_action('wp_head', 'online_users_widget_styles');




我用腾飞博客的访客纪录

