我們一起來看看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";
- } //Vevb.com
- 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";
- }
如果還有更簡單的方法,歡迎留言指教.
|
新聞熱點
疑難解答
圖片精選