WordPress实现文章按照自定义字段排序
我们一起来看看WordPress实现文章按照自定义字段排序的方法,因为碰以一个朋友博客希望增加自定义字段之后再按这个字段排序了,下面是我整理了一个方法,希望能帮助到各位同学.
用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";
- }
如果还有更简单的方法,欢迎留言指教.