如何在WP_Query中按函数返回的平均评分对帖子降序排序?
问题:如何在WP_Query中按自定义平均评分函数的结果排序帖子
场景说明:
- 自定义文章类型
custom_post,用户可发表带评分的评论,评分存储在评论元字段rate中 - 已编写
gt3_get_average_ratings函数计算单篇帖子的平均评分,但直接将该函数传入WP_Query的orderby参数无法实现排序
为什么直接用函数排序无效
WP_Query的orderby参数仅支持内置排序规则(如date、meta_value)或特定格式的数组,无法直接调用PHP函数进行排序——因为WP_Query基于SQL查询执行,无法在数据库层面运行PHP代码。
可行方案
方案1:通过SQL钩子实时计算排序(适合小站点)
通过posts_join和posts_orderby钩子修改WP_Query的SQL语句,直接在数据库层面计算平均评分并排序,无需依赖PHP函数。
步骤1:添加SQL修改钩子
function gt3_order_by_avg_rating_join($join) { global $wpdb; // 关联评论表(仅已审核评论)和评论元表(仅rate字段) $join .= " LEFT JOIN {$wpdb->comments} c ON {$wpdb->posts}.ID = c.comment_post_ID AND c.comment_approved = '1' "; $join .= " LEFT JOIN {$wpdb->commentmeta} cm ON c.comment_ID = cm.comment_id AND cm.meta_key = 'rate' "; return $join; } function gt3_order_by_avg_rating_orderby($orderby) { global $wpdb; // 计算平均评分(转成数值避免字符串排序问题),降序排列;无评分的帖子按发布时间降序补位 $orderby = " COALESCE(AVG(CAST(cm.meta_value AS UNSIGNED)), 0) DESC, {$wpdb->posts}.post_date DESC "; return $orderby; }
步骤2:执行WP_Query并清理钩子
// 临时添加钩子,仅影响本次查询 add_filter('posts_join', 'gt3_order_by_avg_rating_join'); add_filter('posts_orderby', 'gt3_order_by_avg_rating_orderby'); // 构建查询参数 $args = array( 'post_type' => 'custom_post', 'posts_per_page' => -1, // 根据需求调整显示数量 ); $query = new WP_Query($args); // 移除钩子,防止影响后续查询 remove_filter('posts_join', 'gt3_order_by_avg_rating_join'); remove_filter('posts_orderby', 'gt3_order_by_avg_rating_orderby');
方案2:预存评分到文章元字段(推荐,性能更优)
在评论提交/更新/删除时自动计算平均评分,将结果存到文章的元字段(如average_rating),之后直接通过WP_Query的元字段排序规则实现需求,适合大流量或帖子较多的站点。
步骤1:添加评论触发的评分更新钩子
function gt3_update_post_avg_rating($comment_id) { $comment = get_comment($comment_id); if (!$comment || $comment->comment_post_ID <= 0) return; $post_id = $comment->comment_post_ID; // 调用现有函数计算平均评分 $avg_rating = gt3_get_average_ratings($post_id); // 保存到文章元字段,无评分则存0 update_post_meta($post_id, 'average_rating', $avg_rating ? $avg_rating : 0); } // 评论通过审核时更新评分 add_action('comment_approved', 'gt3_update_post_avg_rating'); // 评论删除时更新评分 add_action('deleted_comment', 'gt3_update_post_avg_rating'); // 评论编辑时更新评分 add_action('edit_comment', 'gt3_update_post_avg_rating');
步骤2:初始化现有帖子的评分(一次性执行)
将现有所有custom_post类型的帖子评分计算并保存到元字段,执行一次后即可注释掉:
function gt3_init_all_post_ratings() { $posts = get_posts(array( 'post_type' => 'custom_post', 'posts_per_page' => -1, 'post_status' => 'publish' )); foreach ($posts as $post) { $avg_rating = gt3_get_average_ratings($post->ID); update_post_meta($post->ID, 'average_rating', $avg_rating ? $avg_rating : 0); } } // 执行一次后注释此行 // gt3_init_all_post_ratings();
步骤3:使用WP_Query按元字段排序
$args = array( 'post_type' => 'custom_post', 'meta_key' => 'average_rating', 'orderby' => 'meta_value_num', // 按数值类型排序 'order' => 'DESC', // 可选:仅显示有评分的帖子 // 'meta_query' => array( // array( // 'key' => 'average_rating', // 'value' => 0, // 'compare' => '>' // ) // ) ); $query = new WP_Query($args);
内容的提问来源于stack exchange,提问作者lonerunner
相关产品推荐
相关产品推荐

