like-dislike function 集成主题

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;
    }
}
×
like-dislike function 集成主题

like-dislike function 集成主题

PHP <?php /** * W...