用Meta Query可以实现WordPress文章按照自定义排序,假设安装了WP-PostRatings给文章打分,该插件会把文章平均分存成名叫ratings_average的自定义字段,现在就来按照这个字段排序。
简洁优雅的方法
就是Meta Query,代码放在主题的functions.php里。
代码如下 | 复制代码 |
function sort_by_ratings( $query ){ if ( ( $query->is_home() || $query->is_archive() ) && $query->is_main_query() ) { $query->set( 'meta_key', 'ratings_average' ); $query->set( 'orderby', 'meta_value_num'); $query->set( 'order', 'DESC' ); } } add_action( 'pre_get_posts', 'sort_by_ratings' ); |
却有个严重的问题
该插件只会给打过分的文章创建ratings_average字段,而Meta Query只会选择带有这个字段的文章,也就是说所有没打过分的文章都会从blog首页和存档页消失。
解决的方法呢,直接点就是给每篇文章都创建这个字段,值为0。
复杂点呢,stackoverflow上有对这个问题的讨论,按照给出的方案改进了一下,找到一个暂时的解决方法如下,思路是直接修改sql语句。
代码如下 | 复制代码 |
function sort_by_ratings( $query ){ if ( ( $query->is_home() || $query->is_archive() ) && $query->is_main_query() ) { add_filter( 'posts_fields', 'ratings_fields' ); add_filter( 'posts_join', 'ratings_join' ); add_filter( 'posts_where', 'ratings_where' ); add_filter( 'posts_groupby', 'ratings_group' ); add_filter( 'posts_orderby', 'ratings_orderby' ); } } add_action( 'pre_get_posts', 'sort_by_ratings' ); function ratings_fields($fields){ $order_key = "mt1.meta_value"; return $fields . ",$order_key AS avg"; } function ratings_join($join){ global $wpdb; $new_join = " INNER JOIN $wpdb->postmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id LEFT JOIN $wpdb->postmeta AS mt1 ON ($wpdb->posts.ID = mt1.post_id AND mt1.meta_key = 'ratings_average') "; return $join . ' ' . $new_join; } function ratings_where($where){ global $wpdb; $new_where = " AND ($wpdb->postmeta.meta_key = 'ratings_average' OR mt1.post_id IS NULL )"; return $where . ' ' . $new_where; } function ratings_group( $group ){ global $wpdb; return "$wpdb->posts.ID"; } function ratings_orderby( $orderby ){ global $wpdb; return "ISNULL(avg), avg,$wpdb->posts.post_date ASC"; } |
生成的sql语句如下:
代码如下 | 复制代码 |
SELECT SQL_CALC_FOUND_ROWS wp_posts.*,mt1.meta_value AS avg FROM wp_posts INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id LEFT JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id AND mt1.meta_key = 'ratings_average') WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') AND (wp_postmeta.meta_key = 'ratings_average' OR mt1.post_id IS NULL ) GROUP BY wp_posts.ID ORDER BY ISNULL(avg), avg,wp_posts.post_date ASC LIMIT 0, 10 |
结果是分数按照从低分到高分排序,即使order by DESC也是升序排列。如果要让高分上前面,只能用点奇怪的方法,比如最大分数是5,把posts_fields改成这样
代码如下 | 复制代码 |
function ratings_fields($fields){ // 只能升序排列,所以要降序排列时先做一次运算 $max_rating = 5; $order_key = "$max_rating - mt1.meta_value"; return $fields . ",$order_key AS avg"; } |
如果还有更简单的方法,欢迎留言指教。
时间: 2024-09-28 16:53:06