在运营网站的过程中,了解实时访客情况是许多站长的需求。近日,一款基于子比主题开发的在线用户小工具应运而生,为站长们提供了便捷查看网站当前活跃用户的功能。
功能亮点
这款小工具的核心功能是展示当前在线用户信息,主要体现在前后端两个方面:
- 前端展示:会清晰显示 “当前有 X 位用户在线” 的信息,并列出在线用户名称。当没有用户在线时,则会显示 “当前没有用户在线” 的提示,直观呈现网站实时访客状态。
- 后端设置:可在首页主内容上方位置启用该工具,支持自定义标题(默认标题为 “在线用户”),并能设置视为在线的时间(默认 60 秒)。这个时间设置的作用是检测用户活动状态,每 60 秒进行一次检测,当用户超过设定时间未活动时,会被视为离线。
值得一提的是,该工具对未登录用户不进行记录,且运行时不会占用过多服务器资源,兼顾了实用性与资源友好性。
安装教程
安装这款小工具的步骤并不复杂:
- 首先进入网站的文件管理,找到路径 “网站文件 /******/wp-content/themes/zibll/functions.php”;
- 将对应代码复制到该文件中;
- 进入小工具设置界面启用该功能即可。
由于小工具可放置的位置较多,建议在设置时使用实时预览管理,以便选择最合适的展示位置。
/**
Plugin Name: 星空知-在线用户-开始
Plugin URI: https://www.xkzhi.cn/
Author: 空白(留点尊严)
**/
/*星空知-在线用户-开始-www.xkzhi.cn(留下我)*/
// 登录时设置活动状态
function track_user_login($user_login, $user) {
update_user_meta($user->ID, 'last_activity', time());
update_user_meta($user->ID, 'is_logged_in', '1');
}
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']);
// 开始输出
echo $args['before_widget'];
if (!empty($title)) {
echo $args['before_title'] . '<span class="online-title-icon">👥</span>' . esc_html($title) . $args['after_title'];
}
// 获取在线用户
$online_users = $this->get_online_users($inactive_time);
// 显示用户列表
if (!empty($online_users)) {
if ($show_count) {
echo '<div class="online-users-count">';
echo '<span class="count-bubble">' . count($online_users) . '</span>';
printf(
_n('当前有 %d 位用户在线', '当前有 %d 位用户在线', count($online_users), 'text_domain'),
count($online_users)
);
echo '</div>';
}
echo '<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));
echo '<li class="online-user">';
echo '<a href="' . esc_url($user_link) . '" rel="external nofollow" class="user-card" title="' . esc_attr($display_name) . '">';
echo '<div class="avatar-container">';
echo $avatar;
echo '<span class="online-status" title="在线"></span>';
echo '</div>';
echo '<span class="online-user-name">' . esc_html($display_name) . '</span>';
// 悬浮卡片
echo '<div class="user-hover-card">';
echo '<div class="hover-avatar">' . get_avatar($user->ID, 120) . '</div>';
echo '<h4>' . esc_html($display_name) . '</h4>';
echo '<p><i class="activity-icon"></i> ' . esc_html($last_active) . '</p>';
echo '</div>';
echo '</a>';
echo '</li>';
}
echo '</ul>';
} else {
echo '<div class="no-online-users">';
echo '<div class="empty-state">';
echo '<span class="empty-icon">👻</span>';
echo '<p>' . __('当前没有用户在线', 'text_domain') . '</p>';
echo '</div>';
echo '</div>';
}
echo $args['after_widget'];
}
// 相对时间显示
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
);
$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>
<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>
<?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']);
return $instance;
}
// 获取在线用户列表
private function get_online_users($inactive_time = 60) {
$current_time = time();
$online_users = array();
$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;
}
}
return $online_users;
}
}
// 注册小工具
function register_online_users_widget() {
register_widget('Online_Users_Widget');
}
add_action('widgets_init', 'register_online_users_widget');
//初始化用户状态
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());
}
}
update_option('online_users_status_initialized', true);
}
}
add_action('admin_init', 'initialize_user_status');
// CSS
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 {
display: flex;
flex-direction: column;
align-items: center;
width: 80px;
margin: 0 5px 15px;
position: relative;
}
.widget_online_users .user-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 {
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 {
transform: scale(1.05);
}
/* 用户头像 */
.widget_online_users .online-user img.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 .user-card:hover img.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;
background: linear-gradient(135deg, #4CAF50 0%, #81C784 100%);
border-radius: 50%;
border: 2px solid white;
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 .online-user-name {
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 {
color: #2d3748;
font-weight: 600;
}
.widget_online_users .user-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;
/* 已移除所有阴影相关属性 */
box-shadow: none;
filter: none;
}
.widget_online_users .user-card:hover .user-hover-card {
opacity: 1;
visibility: visible;
transform: translateX(-50%) translateY(0);
/* 已移除悬浮状态的阴影增强 */
box-shadow: none;
filter: none;
}
/* 添加卡片升起时的微光效果 */
.widget_online_users .user-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 {
opacity: 0.6;
}
/* 优化卡片内容过渡 */
.widget_online_users .user-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 > * {
transform: translateY(0);
opacity: 1;
}
/* 延迟子元素动画 */
.widget_online_users .user-hover-card .hover-avatar {
transition-delay: 0.05s;
}
.widget_online_users .user-hover-card h4 {
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 {
width: 70px;
}
.widget_online_users .online-user img.avatar {
width: 50px;
height: 50px;
}
.widget_online_users .user-hover-card {
width: 160px;
padding: 12px;
}
}
</style>
<?php
}
add_action('wp_head', 'online_users_widget_styles');
/*星空知-在线用户-结束-www.xkzhi.cn(留下我)*/
这款在线用户小工具是子比主题的一次实用二次开发,为站长实时了解网站动态提供了新的途径,对于提升网站运营效率有一定帮助。如果你正在使用子比主题,不妨尝试一下这款工具,或许能为你的网站管理带来便利。
没有回复内容