一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

WordPress实现文章按照自定义字段排序

时间:2022-06-25 18:55:09 编辑:袖梨 来源:一聚教程网

用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";
}

如果还有更简单的方法,欢迎留言指教。

热门栏目