Mục lục
Nếu bạn không muốn sử dung plugin, ví dụ Tạo mục đánh giá bài viết đơn giản với KK Star Ratings, thì có thể tham khảo bài viết này.
1. Tạo bảng đánh giá (tuỳ chọn – nếu muốn lưu riêng)
CREATE TABLE wp_post_ratings (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
post_id BIGINT UNSIGNED NOT NULL,
rating TINYINT UNSIGNED NOT NULL,
ip_address VARCHAR(45),
rated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_rating (post_id, ip_address)
) DEFAULT CHARSET=utf8mb4;
Nếu không cần lưu chi tiết, bạn có thể bỏ qua và dùng post_meta như bước dưới.
2. Giao diện đánh giá
<div id="rating-box" data-post-id="<?php the_ID(); ?>">
<span data-rating="1">★</span>
<span data-rating="2">★</span>
<span data-rating="3">★</span>
<span data-rating="4">★</span>
<span data-rating="5">★</span>
</div>
<div id="rating-message"></div>
3. JavaScript AJAX gửi điểm đánh giá
document.querySelectorAll('#rating-box span').forEach(star => {
star.addEventListener('click', () => {
const rating = star.dataset.rating;
const postID = document.getElementById('rating-box').dataset.postId;
fetch(myRating.ajax_url, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `action=save_post_rating&rating=${rating}&post_id=${postID}&nonce=${myRating.nonce}`
})
.then(res => res.json())
.then(data => {
document.getElementById('rating-message').textContent = data.message;
});
});
});
Đừng quên enqueue và localize script:
function enqueue_rating_assets() {
wp_enqueue_script('rating-script', get_template_directory_uri() . '/rating.js', [], false, true);
wp_localize_script('rating-script', 'myRating', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('rate_nonce')
]);
}
add_action('wp_enqueue_scripts', 'enqueue_rating_assets');
4. Xử lý AJAX trong PHP
function save_post_rating() {
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'rate_nonce')) {
wp_send_json_error(['message' => 'Lỗi bảo mật.']);
}
$post_id = absint($_POST['post_id']);
$rating = absint($_POST['rating']);
$ip = $_SERVER['REMOTE_ADDR'];
if ($rating < 1 || $rating > 5) {
wp_send_json_error(['message' => 'Điểm không hợp lệ.']);
}
// Kiểm tra xem IP đã đánh giá chưa
$rated_ips = get_post_meta($post_id, '_rated_ips', true);
$rated_ips = is_array($rated_ips) ? $rated_ips : [];
if (in_array($ip, $rated_ips)) {
wp_send_json_error(['message' => 'Bạn đã đánh giá bài này.']);
}
// Cập nhật điểm trung bình
$total = (int) get_post_meta($post_id, '_rating_total', true);
$count = (int) get_post_meta($post_id, '_rating_count', true);
update_post_meta($post_id, '_rating_total', $total + $rating);
update_post_meta($post_id, '_rating_count', $count + 1);
// Ghi IP lại
$rated_ips[] = $ip;
update_post_meta($post_id, '_rated_ips', $rated_ips);
wp_send_json_success(['message' => 'Cảm ơn bạn đã đánh giá!']);
}
add_action('wp_ajax_save_post_rating', 'save_post_rating');
add_action('wp_ajax_nopriv_save_post_rating', 'save_post_rating');
5. Hiển thị điểm trung bình
$total = (int) get_post_meta(get_the_ID(), '_rating_total', true);
$count = (int) get_post_meta(get_the_ID(), '_rating_count', true);
if ($count > 0) {
$average = round($total / $count, 1);
echo '<div>Đánh giá trung bình: ' . $average . '/5 (' . $count . ' lượt)</div>';
}
Tổng kết
- Bạn đã có một hệ thống đánh giá bài viết cơ bản nhưng đủ an toàn
- Có thể nâng cấp lưu vào database riêng để phân tích sâu hơn
- Giao diện có thể dễ dàng tùy biến theo UIkit, Tailwind, Bootstrap…
Nếu muốn mở rộng, bạn có thể thêm đánh giá có nội dung, thống kê theo ngày, hoặc kết hợp với Google Rich Snippets để hiển thị kết quả trên SERP!
Bình luận