WordPress电影评分系统:未登录/已评分警告弹窗不显示求助
WordPress电影评分系统警告弹窗不显示问题排查
我在WordPress上开发了一套电影评分系统,评分功能可正常运行,但存在以下两个问题:
- 用户未登录时,本该弹出的「请先登录再评分」警告无法显示
- 用户已评分后,本该弹出的「你已经给这部电影评过分了」警告也无法显示
控制台无任何报错信息,以下是相关代码,恳请帮忙排查。
rating-script.js
jQuery(document).ready(function($) { // Function to handle rating submission function handleRatingSubmission(postID, ratingValue) { // Check if user is logged in if (ratingAjax.isLoggedIn === false) { // User is not logged in, show error message $('.rating-error-message').text('Please login first before rating.').fadeIn().delay(3000).fadeOut(); return; } // Send AJAX request to check if user has already rated $.ajax({ url: ratingAjax.ajaxurl, type: 'POST', data: { action: 'check_already_rated', post_id: postID }, success: function(response) { if (response.alreadyRated) { // User has already rated, show error message $('.rating-error-message').text('You have already rated this movie.').fadeIn().delay(3000).fadeOut(); } else { // User has not rated, proceed with rating submission // Send AJAX request to update rating $.ajax({ url: ratingAjax.ajaxurl, type: 'POST', data: { action: 'update_rating', post_id: postID, rating_value: ratingValue * 2 // Multiply the rating by 2 to convert it back to the original scale of 1-10 }, success: function(response) { if (response.success) { // Rating updated successfully // Display success message $('.rating-success-message').fadeIn().delay(3000).fadeOut(); // Update the rating display updateRatingDisplay(postID, ratingValue); // Update the average rating display var averageRating = parseFloat(response.average_rating).toFixed(2); $('.rating-info[data-post-id="' + postID + '"] .average-rating').text('Average Rating: ' + averageRating); // Update the total ratings display var totalRatings = response.total_ratings; $('.rating-info[data-post-id="' + postID + '"] .total-ratings').text('Total Ratings: ' + totalRatings); } else { // Error occurred during rating update // You can add additional error handling logic here } }, error: function() { // Error occurred during AJAX request // You can add additional error handling logic here } }); } }, error: function() { // Error occurred during AJAX request // You can add additional error handling logic here } }); } // Function to update the rating display function updateRatingDisplay(postID, ratingValue) { // Add your code here to update the rating display // This function should update the visual representation of the rating based on the given rating value and post ID // You can modify the DOM elements to reflect the updated rating } // Handle hover effect on rating stars $('.rating-stars .star').hover(function() { var value = $(this).data('value'); $(this).prevAll().addBack().addClass('hover'); $(this).nextAll().removeClass('hover'); $(this).parent().next('.rating-hover-text').text(value); }, function() { $(this).prevAll().addBack().removeClass('hover'); $(this).parent().next('.rating-hover-text').text(''); }); // Handle rating submission $('.rating-stars .star').click(function() { var postID = $(this).data('post-id'); var ratingValue = $(this).data('value'); // Handle rating submission for logged-in users only handleRatingSubmission(postID, ratingValue); }); });
functions.php
<?php // Enqueue necessary scripts and styles function enqueue_rating_scripts() { wp_enqueue_script('jquery'); wp_enqueue_script('rating-script', get_template_directory_uri() . '/js/rating-script.js', array('jquery'), false); // Localize the script to pass the ajaxurl value wp_localize_script('rating-script', 'ratingAjax', array( 'ajaxurl' => admin_url('admin-ajax.php'), 'isLoggedIn' => is_user_logged_in() // Add this line to pass the user login status )); wp_enqueue_style('rating-style', get_template_directory_uri() . '/css/rating-style.css'); wp_register_style('main', get_template_directory_uri() . '/css/main.css', array(), false, 'all'); wp_enqueue_style('main'); wp_enqueue_style( 'google-fonts', 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Lora&family=Roboto:wght@900&display=swap', array(), null ); wp_register_script('script', get_template_directory_uri() . '/js/script.js', array('jquery'),'1.1', true); wp_enqueue_script('script'); wp_enqueue_style( 'font-awesome', 'https://use.fontawesome.com/releases/v6.1.1/css/all.css', array(), null ); } add_action('wp_enqueue_scripts', 'enqueue_rating_scripts'); // AJAX handler to check if user has already rated function check_already_rated() { if (!is_user_logged_in()) { wp_send_json_error(array('alreadyRated' => false)); // User is not logged in, return false } $post_id = $_POST['post_id']; $user_id = get_current_user_id(); $ratings = get_field('ratings', $post_id); foreach ($ratings as $rating) { if ($rating['user_id'] == $user_id) { wp_send_json_error(array('alreadyRated' => true)); // User has already rated, return true } } wp_send_json_success(array('alreadyRated' => false)); // User has not rated, return false } add_action('wp_ajax_check_already_rated', 'check_already_rated'); add_action('wp_ajax_nopriv_check_already_rated', 'check_already_rated'); // AJAX handler for updating ratings function update_rating() { if (!is_user_logged_in()) { wp_send_json_error(array('message' => 'Please login first before rating.')); // Send error response if user is not logged in } $post_id = $_POST['post_id']; $rating_value = $_POST['rating_value']; // Check if user has already rated $user_id = get_current_user_id(); $ratings = get_field('ratings', $post_id); foreach ($ratings as $rating) { if ($rating['user_id'] == $user_id) { wp_send_json_error(array('message' => 'You have already rated this movie.')); // Send error response if user has already rated } } // Update ACF repeater field for the post $new_rating = array( 'rating_value' => min($rating_value, 5), // Set the rating value to a maximum of 5 'user_id' => $user_id, 'timestamp' => current_time('Y-m-d H:i:s') ); $ratings[] = $new_rating; update_field('ratings', $ratings, $post_id); // Recalculate average rating and update ACF field $rating_values = wp_list_pluck($ratings, 'rating_value'); $average_rating = count($rating_values) > 0 ? round(array_sum($rating_values) / count($rating_values), 2) : null; // Round the average rating to 2 decimal places update_field('average_rating', $average_rating, $post_id); // Return success response with updated average rating and total ratings $response = array( 'success' => true, 'average_rating' => $average_rating, 'total_ratings' => count($ratings) ); wp_send_json($response); } add_action('wp_ajax_update_rating', 'update_rating'); add_action('wp_ajax_nopriv_update_rating', 'update_rating'); function display_rating_stars() { $post_id = get_the_ID(); $rating_value = get_field('rating', $post_id); $ratings = get_field('ratings', $post_id); $average_rating = get_field('average_rating', $post_id); // Calculate the maximum number of stars (5) $max_stars = 5; // Calculate the number of full stars $full_stars = 0; if (is_array($ratings)) { // Check if $ratings is an array before counting $full_stars = min(floor($rating_value), $max_stars); // Limit the full stars to a maximum of 5 } // Output the rating stars HTML echo '<div class="rating-stars">'; for ($i = 1; $i <= $max_stars; $i++) { $star_class = ($i <= $full_stars) ? 'star active' : 'star'; echo '<span class="' . $star_class . '" data-value="' . $i . '" data-post-id="' . $post_id . '">★</span>'; } echo '</div>'; // Output the average rating and total ratings echo '<div class="rating-info">'; if (!is_null($average_rating)) { echo 'Average Rating: ' . number_format($average_rating, 2); } if (!is_null($ratings) && is_array($ratings)) { // Check if $ratings is an array before counting echo 'Total Ratings: ' . count($ratings); } echo '</div>'; }
acf-input.js
(function($) { acf.add_action('ready', function() { // Enable the ACF Number field for the rating ACF field $('.acf-field-number input[type="number"]').on('input', function() { var $input = $(this); var $field = $input.closest('.acf-field'); var $label = $field.find('.acf-label'); if ($input.val()) { $label.addClass('active'); } else { $label.removeClass('active'); } }); }); })(jQuery);
single.php
<div class="rating-success-message" style="display: none;"> Rating submitted successfully! </div> <div class="rating-error-message" style="display: none;"></div>
问题排查与修复方案
1. AJAX返回值处理错误
后端使用wp_send_json_error返回已评分状态时,前端success回调中直接读取response.alreadyRated是错误的——wp_send_json_error返回的数据会被包裹在data字段下。
- 修复前端代码:将
if (response.alreadyRated)修改为if (response.data.alreadyRated) - 或后端统一返回格式:改用
wp_send_json替代wp_send_json_error,避免混淆回调逻辑。
2. 未登录用户的AJAX逻辑冲突
虽然前端先判断了ratingAjax.isLoggedIn,但后端check_already_rated中未登录用户会触发wp_send_json_error,导致前端进入error回调(当前为空,无任何提示)。建议:
- 保留前端的
isLoggedIn判断,确保未登录时直接显示警告,不发起AJAX请求。 - 在前端AJAX的
error回调中添加调试代码,比如:error: function(xhr, status, error) { console.log('AJAX错误:', status, error); console.log('响应内容:', xhr.responseText); }
3. DOM选择器范围问题
全局选择器$('.rating-error-message')可能无法精准定位当前电影的提示框,建议给提示框添加关联标识:
- 修改single.php:
<div class="rating-success-message" data-post-id="<?php echo get_the_ID(); ?>" style="display: none;"> 评分提交成功! </div> <div class="rating-error-message" data-post-id="<?php echo get_the_ID(); ?>" style="display: none;"></div> - 修改JS选择器:将
$('.rating-error-message')改为$('.rating-error-message[data-post-id="' + postID + '"]'),确保只操作当前电影的提示框。
4. 后端ACF字段空值判断缺失
当ratings字段为空时,get_field会返回false,此时foreach循环会报错,但未被捕获。需添加数组判断:
- 修改functions.php中的check_already_rated函数:
function check_already_rated() { if (!is_user_logged_in()) { wp_send_json_error(array('alreadyRated' => false)); } $post_id = $_POST['post_id']; $user_id = get_current_user_id(); $ratings = get_field('ratings', $post_id); // 先判断是否为数组,避免循环报错 if (is_array($ratings)) { foreach ($ratings as $rating) { if ($rating['user_id'] == $user_id) { wp_send_json_error(array('alreadyRated' => true)); } } } wp_send_json_success(array('alreadyRated' => false)); }
5. 验证ratingAjax对象传递
在浏览器控制台执行console.log(ratingAjax),确认isLoggedIn值是否正确传递。如果未定义,检查functions.php中wp_localize_script是否绑定到正确的脚本(必须在wp_enqueue_script之后调用)。
内容的提问来源于stack exchange,提问作者payaman
相关产品推荐
相关产品推荐

