用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"; }
如果还有更简单的方法,欢迎留言指教。
妹妹问个问题:我vps上的mysql最近用show full processlist发现,总是有这么一条语句在执行,造成系统运行很慢,该语句是,
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = ‘post’ AND (wp_posts.post_status = ‘publish’) ORDER BY wp_posts.post_date DESC LIMIT 0, 15
这条语句在后台反复执行,这究竟是咋回事呢?
不胜感激。
这个没什么,只要显示博客日志都会运行这条语句,而且这个不费资源,最后的”limit 0,15“保证了这一点。
如果你网站很慢,先安装debug bar,看一下内存占用多少,每个页面大概执行多少条sql查询,是否耗费时间的查询。并不是查询次数越多越慢,一条复杂的sql语句拆分成几条简单语句说不定还能提升性能呢。
当数据库内容很多时,进行select all查询会很耗资源。
看博客名字是个女博主?果然厉害。
sola老师:
冒昧地再请教您一下,我安装了WP-PostRatings插件,创建了一个普通页面,结合https://wordpress.org/plugins/wp-postratings/faq/ 中倒数第二个提示,想按照评分由高到低顺序输出id为79分类下的所有文章,输出排序正常,现在遇到的问题是分页出现问题,“上一页”“下一页”地址栏变了,但是输出的内容不变,从下面代码能看出我哪里做的不对吗?谢谢,希望您空闲时间帮忙看看
代码发不了,附上图片 http://newwebzen.com/sola.jpg
(错发两次评论,麻烦您删了吧)
你没保存分页的query变量,所以分页信息丢了。
文档http://codex.wordpress.org/Function_Reference/query_posts
看reserving Existing Query Parameters哪一段
代码应该类似这样
好了,解决了,代码如下,谢谢sola老师 😉
$paged = (get_query_var(‘paged’)) ? get_query_var(‘paged’) : 1;
$args = array(
‘meta_key’ => ‘ratings_average’,
‘orderby’ => ‘meta_value_num’,
‘order’ => ‘DESC’,
‘showposts’ => 10,
‘cat’=>79,
‘paged’ =>$paged
);
query_posts($args);
慢慢学习!!看看姐的评论提交要刷新么? 最近评论做完了,才发现还有ajax提交评论。据说页面不用刷新诶!!!!看看姐的
ajax提交评论不是啥新鲜货了,老早以前用过,体验也不是特别好,所以还是老实的用默认的了。你可以看看www.ludou.org,他的是ajax提交评论
算了 我还是用默认的算了 , 姐 现在我的评论遗留个小问题,看你们的评论点击回复后立马可以在下面就回复,为什么我的老是跳到最上面的评论表单,这个怎么在回复后面跟随呢?
您好,我遇到一個很神奇的問題
我的文章會重複顯示! 同時造成有的文章沒有顯示!
debug很久很久..文章確實只有一個(但卻重複顯示)
資料庫看也確實沒錯..
後來才發現原來是添加了
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’ );
造成的!!!!!
真的不明白為什麼..
我首頁也沒有用到其他query
在我localhost測試時也曾發生過
在我專案上現在又發生了
但時好時壞(好像把文章都砍掉清除重新到一次文章時又好了)
我有大量文章要倒入..不可能一又發生這問題就全砍掉重倒..
我不知道到底是哪邊出了問題..
會有可能是 meta_key 在搞鬼媽?? (可能我文章曾經重複po過造成?)
還是到底哪邊出了問題呢…(用的主題是pinpress)
抱歉,補充一下
我有修改Function: Add Rating Custom Fields 的預設值
ratings_users(有多少人評價這篇文章)改為1;
ratings_score(這篇文章的總得分)改為3;
ratings_average(這篇文章的平均得分)改為3
不知道有沒有影響?
還有
我試了您的暫時解決方法
卻會造成掛掉@@…….???
真的不知道是哪裡出了問題….哎..
这你只能自己调试,把mysql语句打出来,直接到phpmyadmin里去执行,看结果。post重复可能是没有group by post_id这句话。
另外正常的WordPress Meta Query不应该造成post重复现象,建议你不要开启无关插件,用默认主题测试,功能测试好了再换主题,逐个开启你需要的插件。如果主题里有影响main query的代码,冲突一下也不无可能。
好的,還是非常感謝您!!
前來支持一下~~不明覺厲!
大侠,求助。我在使用其他woocommerce主题时,填写订单联系人信息了,不见有支付宝选择。但是使用系统原来的主题Twenty Twelve,就能提交订单去支付宝付款。为啥情况,望指点明津。
没遇到过这种情况,你用的什么主题,试过多少个第三方主题。