展示效果

代码(补充说明,添加代码到当前的主题的function底部,后台新建小工具调用就行了):
<?php
// WordPress文章点赞功能 - 修复今日点赞统计问题
class Post_Likes_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'post_likes_widget',
'文章点赞',
array(
'description' => '在侧边栏显示文章点赞功能',
'classname' => 'post-likes-widget',
)
);
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
add_action('wp_ajax_post_like', array($this, 'handle_post_like'));
add_action('wp_ajax_nopriv_post_like', array($this, 'handle_post_like'));
// 初始化数据库表
add_action('init', array($this, 'init_db_table'));
}
// 初始化数据库表
public function init_db_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'post_likes';
$charset_collate = $wpdb->get_charset_collate();
// 检查表是否存在,不存在则创建
if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
post_id mediumint(9) NOT NULL,
user_ip varchar(45) NOT NULL,
user_id bigint(20) DEFAULT 0,
like_date datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY post_id (post_id),
KEY user_ip (user_ip),
KEY user_id (user_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
}
// 修复的AJAX处理函数 - 解决用户识别问题
public function handle_post_like() {
// 设置正确的header
header('Content-Type: application/json');
// 验证nonce
if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'like_nonce')) {
wp_send_json_error('安全验证失败');
return;
}
// 验证post_id
if (!isset($_POST['post_id']) || empty($_POST['post_id'])) {
wp_send_json_error('文章ID不能为空');
return;
}
$post_id = intval($_POST['post_id']);
$user_ip = $this->get_user_ip();
$user_id = is_user_logged_in() ? get_current_user_id() : 0;
// 验证文章是否存在
if (!get_post($post_id)) {
wp_send_json_error('文章不存在');
return;
}
global $wpdb;
$table_name = $wpdb->prefix . 'post_likes';
// ========== 修复核心逻辑 ==========
// 检查是否已经点赞 - 区分登录用户和游客
$already_liked = false;
if ($user_id > 0) {
// 登录用户:使用user_id检查
$already_liked = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE post_id = %d AND user_id = %d",
$post_id, $user_id
));
// 清理可能存在的相同IP的游客记录(避免重复)
$wpdb->delete(
$table_name,
array(
'post_id' => $post_id,
'user_ip' => $user_ip,
'user_id' => 0
),
array('%d', '%s', '%d')
);
} else {
// 游客:使用user_ip检查
$already_liked = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE post_id = %d AND user_ip = %s AND user_id = 0",
$post_id, $user_ip
));
// 清理可能存在的相同IP的登录用户记录(避免重复)
$wpdb->delete(
$table_name,
array(
'post_id' => $post_id,
'user_ip' => $user_ip,
'user_id' => array(0, '>')
),
array('%d', '%s', '%d')
);
}
$already_liked = intval($already_liked) > 0;
if (!$already_liked) {
// 添加点赞
$result = $wpdb->insert(
$table_name,
array(
'post_id' => $post_id,
'user_ip' => $user_ip,
'user_id' => $user_id
),
array('%d', '%s', '%d')
);
if ($result === false) {
wp_send_json_error('点赞失败');
return;
}
$liked = true;
$message = '感谢您的点赞!';
} else {
// 取消点赞
$where_params = array('post_id' => $post_id);
$where_format = array('%d');
if ($user_id > 0) {
$where_params['user_id'] = $user_id;
$where_format[] = '%d';
} else {
$where_params['user_ip'] = $user_ip;
$where_params['user_id'] = 0;
$where_format[] = '%s';
$where_format[] = '%d';
}
$result = $wpdb->delete($table_name, $where_params, $where_format);
if ($result === false) {
wp_send_json_error('取消点赞失败');
return;
}
$liked = false;
$message = '您已取消点赞';
}
// 获取更新后的点赞数
$like_count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE post_id = %d",
$post_id
));
// 获取全站今日点赞数(修复:统计所有文章,不只是当前文章)
$today_likes = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE DATE(like_date) = %s",
date('Y-m-d')
));
// 获取全站总点赞数
$total_likes = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
// 返回成功响应
wp_send_json_success(array(
'liked' => $liked,
'count' => $like_count,
'message' => $message,
'today_likes' => $today_likes,
'total_likes' => $total_likes
));
}
// 获取用户IP(修复版)
private function get_user_ip() {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
// 处理多个IP的情况(如经过代理)
if (strpos($ip, ',') !== false) {
$ips = explode(',', $ip);
$ip = trim($ips[0]);
}
return sanitize_text_field($ip);
}
public function widget($args, $instance) {
if (!is_single() && !is_page()) {
return;
}
$title = apply_filters('widget_title', empty($instance['title']) ? '' : $instance['title'], $instance, $this->id_base);
echo $args['before_widget'];
if ($title) {
echo $args['before_title'] . $title . $args['after_title'];
}
echo $this->get_likes_html();
echo $args['after_widget'];
}
public function form($instance) {
$instance = wp_parse_args((array) $instance, array(
'title' => '喜欢这篇文章?',
));
$title = sanitize_text_field($instance['title']);
?>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>">标题:</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($title); ?>" />
</p>
<?php
}
public function update($new_instance, $old_instance) {
$instance = $old_instance;
$instance['title'] = sanitize_text_field($new_instance['title']);
return $instance;
}
private function get_likes_html() {
$post_id = get_the_ID();
$like_count = $this->get_post_likes_count($post_id);
$already_liked = $this->has_user_liked_post($post_id);
$today_likes = $this->get_today_likes_count(); // 修复:获取全站今日点赞
$total_likes = $this->get_total_likes_count();
$liked_class = $already_liked ? 'liked' : '';
$current_button_text = $already_liked ? '已点赞' : '点赞';
$heart_icon = $already_liked ? 'fas' : 'far';
// 创建nonce
$nonce = wp_create_nonce('like_nonce');
ob_start();
?>
<div class="post-likes-widget-content">
<button class="like-widget-button <?php echo $liked_class; ?>"
id="likeWidgetButton-<?php echo $post_id; ?>"
data-post-id="<?php echo $post_id; ?>"
data-nonce="<?php echo $nonce; ?>">
<i class="like-widget-icon <?php echo $heart_icon; ?> fa-heart"></i>
<span class="like-widget-text"><?php echo $current_button_text; ?></span>
<span class="like-widget-count"><?php echo $like_count; ?></span>
</button>
<div class="like-widget-message" id="likeWidgetMessage-<?php echo $post_id; ?>">
已有<?php echo $like_count; ?>位读者点赞
</div>
<div class="like-widget-stats">
<div class="like-widget-stat">
<span class="stat-value" id="todayLikes-<?php echo $post_id; ?>"><?php echo $today_likes; ?></span>
<span class="stat-label">今日点赞</span>
</div>
<div class="like-widget-stat">
<span class="stat-value" id="totalLikes-<?php echo $post_id; ?>"><?php echo $total_likes; ?></span>
<span class="stat-label">总点赞数</span>
</div>
<div class="like-widget-stat">
<span class="stat-value" id="articleLikes-<?php echo $post_id; ?>"><?php echo $like_count; ?></span>
<span class="stat-label">本文点赞</span>
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
$('#likeWidgetButton-<?php echo $post_id; ?>').click(function() {
var button = $(this);
var post_id = button.data('post-id');
var nonce = button.data('nonce');
var messageEl = $('#likeWidgetMessage-<?php echo $post_id; ?>');
// 禁用按钮防止重复点击
button.prop('disabled', true).addClass('like-widget-loading');
$.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
type: 'POST',
data: {
action: 'post_like',
post_id: post_id,
security: nonce
},
success: function(response) {
if (response.success) {
var likeCountEl = button.find('.like-widget-count');
var likeTextEl = button.find('.like-widget-text');
var iconEl = button.find('.like-widget-icon');
// 更新点赞数
likeCountEl.text(response.data.count);
// 更新统计数据
$('#articleLikes-<?php echo $post_id; ?>').text(response.data.count);
$('#todayLikes-<?php echo $post_id; ?>').text(response.data.today_likes);
$('#totalLikes-<?php echo $post_id; ?>').text(response.data.total_likes);
if (response.data.liked) {
button.addClass('liked');
likeTextEl.text('已点赞');
iconEl.removeClass('far').addClass('fas');
} else {
button.removeClass('liked');
likeTextEl.text('点赞');
iconEl.removeClass('fas').addClass('far');
}
// 显示成功消息
messageEl.removeClass('error').addClass('success').text(response.data.message);
setTimeout(function() {
messageEl.removeClass('success').text('已有' + response.data.count + '位读者点赞');
}, 2000);
} else {
messageEl.removeClass('success').addClass('error').text(response.data);
}
},
error: function(xhr, status, error) {
console.error('AJAX Error:', status, error);
messageEl.removeClass('success').addClass('error').text('网络错误,请重试');
},
complete: function() {
button.prop('disabled', false).removeClass('like-widget-loading');
}
});
});
});
</script>
<?php
return ob_get_clean();
}
private function get_post_likes_count($post_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'post_likes';
$like_count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE post_id = %d",
$post_id
));
return $like_count ? $like_count : 0;
}
// 修复:获取全站今日点赞数,不是当前文章的今日点赞
private function get_today_likes_count() {
global $wpdb;
$table_name = $wpdb->prefix . 'post_likes';
$today = date('Y-m-d');
$like_count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE DATE(like_date) = %s",
$today
));
return $like_count ? $like_count : 0;
}
private function get_total_likes_count() {
global $wpdb;
$table_name = $wpdb->prefix . 'post_likes';
$total_likes = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
return $total_likes ? $total_likes : 0;
}
private function has_user_liked_post($post_id) {
$user_ip = $this->get_user_ip();
$user_id = is_user_logged_in() ? get_current_user_id() : 0;
global $wpdb;
$table_name = $wpdb->prefix . 'post_likes';
if ($user_id > 0) {
// 登录用户:使用user_id检查
$already_liked = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE post_id = %d AND user_id = %d",
$post_id, $user_id
));
} else {
// 游客:使用user_ip检查
$already_liked = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE post_id = %d AND user_ip = %s AND user_id = 0",
$post_id, $user_ip
));
}
return $already_liked > 0;
}
public function enqueue_scripts() {
if (is_active_widget(false, false, $this->id_base, true) && (is_single() || is_page())) {
wp_enqueue_script('jquery');
wp_enqueue_style('font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css', array(), '6.4.0');
// 添加内联样式
wp_add_inline_style('font-awesome', $this->get_widget_css());
}
}
private function get_widget_css() {
return "
.post-likes-widget .post-likes-widget-content {
text-align: center;
padding: 15px 0;
}
.like-widget-button {
display: inline-flex;
align-items: center;
justify-content: center;
background: #fff;
border: 2px solid #e74c3c;
border-radius: 50px;
padding: 10px 20px;
font-size: 1rem;
font-weight: 600;
color: #e74c3c;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 5px rgba(231, 76, 60, 0.1);
width: 100%;
max-width: 200px;
margin: 0 auto 10px;
}
.like-widget-button:hover {
background: #e74c3c;
color: white;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(231, 76, 60, 0.2);
}
.like-widget-button.liked {
background: #e74c3c;
color: white;
border-color: #c0392b;
}
.like-widget-button:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
.like-widget-button:active {
transform: translateY(0);
}
.like-widget-icon {
margin-right: 6px;
font-size: 1.1rem;
width: 16px;
text-align: center;
}
.like-widget-count {
font-size: 1.2rem;
font-weight: bold;
margin-left: 5px;
min-width: 25px;
text-align: center;
}
.like-widget-message {
font-size: 0.8rem;
color: #7f8c8d;
margin-bottom: 10px;
min-height: 18px;
}
.like-widget-stats {
display: flex;
justify-content: space-around;
border-top: 1px solid #eee;
padding-top: 10px;
}
.like-widget-stat {
text-align: center;
flex: 1;
}
.like-widget-stat .stat-value {
display: block;
font-size: 1.1rem;
font-weight: bold;
color: #2c3e50;
}
.like-widget-stat .stat-label {
display: block;
font-size: 0.7rem;
color: #7f8c8d;
margin-top: 2px;
}
.like-widget-loading {
opacity: 0.7;
}
.like-widget-message.success {
color: #27ae60;
}
.like-widget-message.error {
color: #e74c3c;
}
@media (max-width: 782px) {
.like-widget-button {
padding: 8px 16px;
font-size: 0.9rem;
}
.like-widget-stats {
flex-direction: column;
gap: 8px;
}
}
";
}
}
// 注册小工具
function register_post_likes_widget() {
register_widget('Post_Likes_Widget');
}
add_action('widgets_init', 'register_post_likes_widget');
// 清理重复点赞数据(可选,用于修复现有数据)
function cleanup_duplicate_likes() {
global $wpdb;
$table_name = $wpdb->prefix . 'post_likes';
// 清理同一IP的重复记录(保留user_id不为0的记录)
$wpdb->query("
DELETE t1 FROM $table_name t1
INNER JOIN $table_name t2
WHERE
t1.id < t2.id AND
t1.post_id = t2.post_id AND
t1.user_ip = t2.user_ip AND
t1.user_id = 0 AND
t2.user_id > 0
");
// 清理同一用户的重复记录
$wpdb->query("
DELETE t1 FROM $table_name t1
INNER JOIN $table_name t2
WHERE
t1.id < t2.id AND
t1.post_id = t2.post_id AND
t1.user_id = t2.user_id AND
t1.user_id > 0
");
}
// 可选:在插件激活时运行一次数据清理
// add_action('init', 'cleanup_duplicate_likes');
?>
貌似我在你文章这里没找到点赞的地方
我的博客目前还没添加,隔壁的朋友(知影燕xhxh.cool)需要这个功能,所以写了备注一下
你这整的太完整了,我就一个对当前文章点赞的。。。
可以完善一下