PHP
<?php /**
* WordPress Post Like/Dislike System
*
* Plugin Name: Post Like Dislike System
* Description: Add like and dislike functionality to posts
* Version: 1.0.0
* Author: Claude
*
* Instructions:
* 1. Add this code to your theme's functions.php file
* 2. Make sure to enqueue the styles in your theme
* 3. Call the display_like_dislike_buttons() function in your theme's single.php or content.php
*/
// Add necessary scripts and styles
function enqueue_like_dislike_scripts() {
wp_enqueue_script('jquery');
wp_enqueue_script('like-dislike-js', get_template_directory_uri() . '/js/like-dislike.js', array('jquery'), '1.0.0', true);
// Add AJAX URL for JavaScript use
wp_localize_script('like-dislike-js', 'like_dislike_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('like_dislike_nonce')
));
// Enqueue styles
wp_enqueue_style('like-dislike-css', get_template_directory_uri() . '/css/like-dislike.css');
}
add_action('wp_enqueue_scripts', 'enqueue_like_dislike_scripts');
// Initialize post meta for like/dislike counts
function initialize_like_dislike_counts() {
$args = array(
'post_type' => 'post',
'posts_per_page' => -1
);
$posts = get_posts($args);
foreach ($posts as $post) {
$likes = get_post_meta($post->ID, '_post_like_count', true);
$dislikes = get_post_meta($post->ID, '_post_dislike_count', true);
if (empty($likes)) {
add_post_meta($post->ID, '_post_like_count', '0', true);
}
if (empty($dislikes)) {
add_post_meta($post->ID, '_post_dislike_count', '0', true);
}
}
}
add_action('init', 'initialize_like_dislike_counts');
// Process like/dislike AJAX requests
function process_post_like_dislike() {
// Check nonce for security
check_ajax_referer('like_dislike_nonce', 'nonce');
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
$action_type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : '';
if (!$post_id || !in_array($action_type, array('like', 'dislike'))) {
wp_send_json_error('Invalid data');
exit;
}
// Get current user IP
$user_ip = get_client_ip();
// Check if user already voted
$voted_IPs = get_post_meta($post_id, "_voted_IPs", true);
if (!$voted_IPs) {
$voted_IPs = array();
}
$response = array();
// If user hasn't voted before
if (!isset($voted_IPs[$user_ip]) || empty($voted_IPs[$user_ip])) {
$meta_key = ($action_type === 'like') ? '_post_like_count' : '_post_dislike_count';
$current_count = get_post_meta($post_id, $meta_key, true);
$updated_count = $current_count ? $current_count + 1 : 1;
update_post_meta($post_id, $meta_key, $updated_count);
// Mark this IP as voted
$voted_IPs[$user_ip] = $action_type;
update_post_meta($post_id, "_voted_IPs", $voted_IPs);
$response['success'] = true;
$response['count'] = $updated_count;
}
// If user already voted but for a different action
elseif ($voted_IPs[$user_ip] !== $action_type) {
// Remove the previous vote
$old_meta_key = ($voted_IPs[$user_ip] === 'like') ? '_post_like_count' : '_post_dislike_count';
$old_count = get_post_meta($post_id, $old_meta_key, true);
if ($old_count > 0) {
update_post_meta($post_id, $old_meta_key, $old_count - 1);
}
// Add the new vote
$new_meta_key = ($action_type === 'like') ? '_post_like_count' : '_post_dislike_count';
$new_count = get_post_meta($post_id, $new_meta_key, true);
$updated_count = $new_count ? $new_count + 1 : 1;
update_post_meta($post_id, $new_meta_key, $updated_count);
// Update user's vote type
$voted_IPs[$user_ip] = $action_type;
update_post_meta($post_id, "_voted_IPs", $voted_IPs);
$response['success'] = true;
$response['count'] = $updated_count;
}
// User already voted for the same action
else {
$response['success'] = false;
$response['message'] = 'You already ' . $action_type . 'd this post';
}
// Return both like and dislike counts
$response['likes'] = get_post_meta($post_id, '_post_like_count', true);
$response['dislikes'] = get_post_meta($post_id, '_post_dislike_count', true);
wp_send_json($response);
exit;
}
add_action('wp_ajax_post_like_dislike', 'process_post_like_dislike');
add_action('wp_ajax_nopriv_post_like_dislike', 'process_post_like_dislike');
// Helper function to get client IP
function get_client_ip() {
$ipaddress = '';
if (isset($_SERVER['HTTP_CLIENT_IP']))
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_X_FORWARDED']))
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
else if(isset($_SERVER['HTTP_FORWARDED']))
$ipaddress = $_SERVER['HTTP_FORWARDED'];
else if(isset($_SERVER['REMOTE_ADDR']))
$ipaddress = $_SERVER['REMOTE_ADDR'];
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
// Function to display like and dislike buttons
function display_like_dislike_buttons($post_id = null) {
if (!$post_id) {
$post_id = get_the_ID();
}
$like_count = get_post_meta($post_id, '_post_like_count', true) ?: 0;
$dislike_count = get_post_meta($post_id, '_post_dislike_count', true) ?: 0;
// Check if current user has voted
$user_ip = get_client_ip();
$voted_IPs = get_post_meta($post_id, "_voted_IPs", true);
$user_vote = isset($voted_IPs[$user_ip]) ? $voted_IPs[$user_ip] : '';
$like_active_class = $user_vote === 'like' ? 'active' : '';
$dislike_active_class = $user_vote === 'dislike' ? 'active' : '';
ob_start();
?>
<div class="post-like-dislike-wrapper" data-post-id="<?php echo esc_attr($post_id); ?>">
<div class="like-button-wrapper">
<button class="like-button <?php echo esc_attr($like_active_class); ?>" data-type="like">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-thumbs-up">
<path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"></path>
</svg>
<span class="like-count"><?php echo esc_html($like_count); ?></span>
</button>
</div>
<div class="dislike-button-wrapper">
<button class="dislike-button <?php echo esc_attr($dislike_active_class); ?>" data-type="dislike">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-thumbs-down">
<path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm10-13h3a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-3"></path>
</svg>
<span class="dislike-count"><?php echo esc_html($dislike_count); ?></span>
</button>
</div>
</div>
<?php
return ob_get_clean();
}
JS
/**
* JavaScript for like/dislike functionality
* Save this file as 'like-dislike.js' in your theme's js folder
*/
jQuery(document).ready(function($) {
// Handle click on like or dislike button
$('.like-button, .dislike-button').on('click', function(e) {
e.preventDefault();
var $this = $(this);
var $wrapper = $this.closest('.post-like-dislike-wrapper');
var postId = $wrapper.data('post-id');
var actionType = $this.data('type');
// Disable buttons temporarily
$wrapper.find('button').prop('disabled', true);
// AJAX request
$.ajax({
url: like_dislike_ajax.ajax_url,
type: 'POST',
data: {
action: 'post_like_dislike',
post_id: postId,
type: actionType,
nonce: like_dislike_ajax.nonce
},
success: function(response) {
// Re-enable buttons
$wrapper.find('button').prop('disabled', false);
if (response.success) {
// Update counts
$wrapper.find('.like-count').text(response.likes);
$wrapper.find('.dislike-count').text(response.dislikes);
// Update active states
if (actionType === 'like') {
$wrapper.find('.like-button').addClass('active');
$wrapper.find('.dislike-button').removeClass('active');
} else {
$wrapper.find('.dislike-button').addClass('active');
$wrapper.find('.like-button').removeClass('active');
}
// Add subtle animation
$this.addClass('voted');
setTimeout(function() {
$this.removeClass('voted');
}, 700);
} else {
// Show message if user already voted
if (response.message) {
showNotification(response.message);
}
}
},
error: function() {
// Re-enable buttons
$wrapper.find('button').prop('disabled', false);
showNotification('An error occurred. Please try again.');
}
});
});
// Simple notification function
function showNotification(message) {
var $notification = $('<div class="like-dislike-notification">' + message + '</div>');
$('body').append($notification);
setTimeout(function() {
$notification.addClass('show');
}, 10);
setTimeout(function() {
$notification.removeClass('show');
setTimeout(function() {
$notification.remove();
}, 300);
}, 2000);
}
});
CSS
/**
* CSS for like/dislike functionality
* Save this file as 'like-dislike.css' in your theme's css folder
*/
/* Main wrapper */
.post-like-dislike-wrapper {
display: flex;
align-items: center;
gap: 12px;
margin: 20px 0;
}
/* Button styling */
.like-button,
.dislike-button {
display: flex;
align-items: center;
gap: 5px;
padding: 8px 12px;
border: 1px solid #e0e0e0;
background-color: #f8f8f8;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
color: #555;
font-size: 14px;
}
.like-button:hover,
.dislike-button:hover {
background-color: #f0f0f0;
border-color: #ccc;
}
/* Active state */
.like-button.active {
background-color: #e1f5fe;
border-color: #81d4fa;
color: #0288d1;
}
.dislike-button.active {
background-color: #fbe9e7;
border-color: #ffab91;
color: #e64a19;
}
/* Count styling */
.like-count,
.dislike-count {
font-weight: 600;
}
/* Animation for clicked button */
.like-button.voted,
.dislike-button.voted {
transform: scale(1.1);
}
/* SVG icons */
.like-button svg,
.dislike-button svg {
width: 16px;
height: 16px;
}
.like-button.active svg {
stroke: #0288d1;
}
.dislike-button.active svg {
stroke: #e64a19;
}
/* Notification styling */
.like-dislike-notification {
position: fixed;
bottom: 20px;
right: 20px;
background-color: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 10px 15px;
border-radius: 4px;
font-size: 14px;
z-index: 9999;
opacity: 0;
transform: translateY(10px);
transition: all 0.3s ease;
}
.like-dislike-notification.show {
opacity: 1;
transform: translateY(0);
}
/* Responsive styling */
@media (max-width: 768px) {
.post-like-dislike-wrapper {
justify-content: center;
}
}
WP开发教程 WordPress导师在线教程