WordPress内建的排序方式有很多,比如按照标题排序、按评论数多少排序或者按照某个自定义字段的值排序。如果可以让访客自由选择网站文章的排序方式,可以帮助访客发现他们想要的资源,提高用户黏度。本文探讨如何实现访客选择文章排序方式,包括按照浏览次数和用户打分排序。
目录
目标
要实现的功能包括
- 用模板标签添加文章排序菜单,也就是用户能看到的前台部分
- 在header.php中添加模板标签,在首页和所有分类页面显示排序链接,支持对首页和所有分类页面排序,包括category、tag、author archive、 date archive等。
- 按照评论多少排序,这个只需要修改orderby参数,其它排序方式包括title、date、rand等等与之相同,所以选择评论数(comment_count)作为代表
- 按照浏览次数排序,其实就是按照自定义字段(custom field)排序,这里的自定义字段叫做views,也许你能猜到,要借助WP-PostViews插件
- 按照用户打分(Ratings)排序,同样是自定义字段排序的例子,借助WP-PostRatings插件
开始之前
1. WP PostViews插件自带排序功能,所以无需重新写这部分代码,详情参阅《WP-PostViews浏览次数统计插件使用详解》
2. WP PostRatings也自带排序功能,使用的参数是r_sortby,WP PostViews使用的是v_sortby,要求参数统一的情况下只能取其一,就选WP PostViews的参数,正好练习一下如何利用custom field排序的方法
3. 排序在query_post执行之前完成,也就是说我们不用去模板文件里写query_post()或者new WP_Query,而是在主循环输出之前就改变排序顺序,这样可以减少数据库查询次数,这也是WP PostViews的做法。
4. 将代码封装在Class中,我们的代码看起来是这样
class Sola_Sort_Posts { //代码 }
使用Class封装可以有效避免全局变量的使用,减少与其它插件冲突的机会,只要Class的名字不重复就没事。
声明Class,写构造函数
class Sola_Sort_Posts { private $sort_views; private $sort_ratings; function __construct() { If (in_array( 'wp-postviews/wp-postviews.php',apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) $this->sort_views = true; If (in_array( 'wp-postratings/wp-postratings.php',apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) $this->sort_ratings = true; add_action('pre_get_posts', array(&$this, 'posts_sorting') ); add_filter('query_vars', array(&$this, 'add_sorting_vars') ); }
构造函数前两句检测与该插件有依赖关系的两个插件是否启用,如果没启用,后面就不会显示按照浏览次数和打分的链接。
按照评分(Ratings)排序
这部分的实现代码如下
function posts_sorting($local_wp_query) { $sortby = $local_wp_query->get('v_sortby'); $is_valid = is_home() || is_archive(); if( $sortby && $is_valid ) { if( $this->sort_ratings && $sortby == 'ratings') { add_filter( 'posts_fields', array(&$this, 'ratings_fields') ); add_filter( 'posts_join', array(&$this, 'ratings_join') ); add_filter( 'posts_where', array(&$this, 'ratings_where') ); add_filter( 'posts_orderby', array(&$this, 'ratings_orderby') ); } else if( $sortby == 'comment_count' ) { add_filter( 'posts_orderby', array(&$this, 'comment_count_orderby') ); } } }
这部分代码将在action: pre_get_posts处执行,排序只能用于首页或者archive(分类、tag、作者archive、日期archive等)页面,所以检测一下是否在这些页面,如果不是就不要执行。
检测一下当前的v_sortby的值,如果地址是https://www.solagirl.net?v_sortby=ratings,就是按照ratings排序,这时添加四个filters,修改主循环SQL语句,使主循环查询时
- SELECT时选出meta_value
- 联合wp_postmeta表查询
- 按照ratings_orderby排序,ratings_orderby是WP PostRatings插件记录平均值的数据库meta_key
- 增加一个Where条件
下面是实现上述四点的具体函数
/** Function: Modify Default WordPress Listing To Make It Sorted By Post Ratings */ function ratings_fields($content) { global $wpdb; $content .= ", ($wpdb->postmeta.meta_value+0) AS ratings_average"; return $content; } function ratings_join($content) { global $wpdb; $content .= " LEFT JOIN $wpdb->postmeta ON $wpdb->postmeta.post_id = $wpdb->posts.ID"; return $content; } function ratings_where($content) { global $wpdb; $content .= " AND $wpdb->postmeta.meta_key = 'ratings_average'"; return $content; } function ratings_orderby($content) { $orderby = trim(addslashes(get_query_var('v_orderby'))); if(empty($orderby) || ($orderby != 'asc' && $orderby != 'desc')) { $orderby = 'desc'; } $content = " ratings_average $orderby"; return $content; }
实现按照comment_count的方式就是修改一下orderby参数,不在赘述。
按照ratings排序的主循环查询语句将会是这样
SELECT SQL_CALC_FOUND_ROWS wp_posts . * , ( wp_postmeta.meta_value +0 ) AS ratings_average FROM wp_posts LEFT JOIN wp_postmeta ON wp_postmeta.post_id = wp_posts.ID 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' ORDER BY ratings_average DESC LIMIT 0 , 10
在模板中添加模板标签实现
在类中定义一个方法输出我们需要的排序链接
function print_menu() { ... }
在类结束后,实例化这个类,定义一个新的函数作为模板标签
/** Instance the class */ $sort_posts = new Sola_Sort_Posts(); /** Function: Template tags for displaying the sorting menu */ function sort_posts() { global $sort_posts; $sort_posts->print_menu(); }
这样用户只需要在模板中(例如header.php)添加函数sola_sort_posts()就可以在首页和所有分类页面显示排序链接,以twentyeleven为例,
//twentyeleven的header.php最后 <div id="main"> <?php if( function_exists('sola_sort_posts') ) sola_sort_posts(); ?>
效果
最终效果展示
按照评论排序
按照Ratings排序
控制样式
可以在主题的style.css中为排序表单添加样式,例如让表单横向排列,选中的以红色下划线字体显示
ul.post-sort li { float:left; margin-right:20px; } ul.post-sort .current-sort a { color:#FF0000; text-decoration:underline; }
插件下载
源代码以插件形式展现
[download id=37]
将sort-posts.php放在plugins目录下,后台激活插件,在header.php中添加如下代码即可使用
<?php if( function_exists('sola_sort_posts') ) sola_sort_posts(); ?>
扩展
在这段代码基础上,还可以扩展更多排序方式,包括
- 按照字母数顺序排序(post_name)
- 按照作者名字排序(post_author)
- 按照发布时间排序(post_date),这是默认的排序方式
- 按照文章修改时间排序(post_modified)
- 按照随机顺序排序(RAND())
- 按照贝叶斯平均排序,也就是在按照Ratings排序时考虑打分人数,参考文章《基于贝叶斯平均的产品排序方法》
注意:这里使用的orderby参数与WP Query文档中给出的参数不同,因为WP Query的排序是经过封装的,我们用的方法是直接修改SQL语句,所以要以数据库字段的实际名称为准。
同样的主题,启用插件后以前可以正常显示,现在显示不了,是不是WordPress版本升级了,插件不支持了呢
鉴于这文章两年前写的,你说的很有可能
您好,本身剛接觸wordpress沒多久..由於專案需要
需要做到在首頁就以ratinig來排序,並且在各分類中(or tag)達到分類的rating排序
原本是用rating widget但發現他好像做不到這樣的事情..
搜尋很久終於看到這篇好像看到救星一樣!! 於是改裝了wp-postrating @@
想請教幾個蠢問題
1. 聲明class Sola_Sort_Posts & 按照評分排序 function posts_sorting 這部分是放在function.php裡面媽??
2. 4個有關下sql語法的程式碼要放在哪裡,也是function.php裡面媽??
3. 在模板中添加模板標籤實現 => 定義一個function print_menu() {這function裡面的內容是..??} & 定義一個新的函數作為模板標籤 ~ 這邊的程式碼是要放置何處 ,,
最後再自己想要的地方使用 只有這邊看得懂….@@@@
可能是我太笨了看不懂這樣詳細的教學文..問題很多..希望能解決我現在遇到的問題..謝謝!!
在插件下载section提供了下载链接,是插件形式,用上传方法安装到wordpress里,激活后在主题模版里添加函数即可
这文章念头很久,代码也没更新过,我看了下有很多问题,虽然能排序,但如果文章没有ratings字段就直接不显示了。
这个问题的本质是按照custom field排序,你可以搜索相关文章。wp postratings插件负责给每篇文章添加平均分这个custom field(需要用户打分后才会产生),你需要用这个custom field做排序。
嘿~我能用了~~~
另外想請問一下
我有沒有辦法在wordpress預設首頁裡就直接帶參數來做這個效果呢
https://www.solagirl.net/wordpress-order-by-custom-fields-exists-or-not.html
你看下这篇文章
非常感謝!!!
我已經成功囉
但是我另外想要詢問一些問題..
後台中可顯示評分過的相關資訊log(每一筆誰給誰評分..等等)
我想要做到一個使用者評分排行榜(評分最多次的user)在側邊欄
感覺似乎是做的到的..我要怎麼做呢
甚至是顯示使用者評分過的對象..有相關資訊媽..要怎麼做呢??
博主你好啊,我装了你的插件,然后在class添加了 :
class Sola_Sort_Posts {
//代码
}
在header添加了
分类目录下显示的为什么是竖排的,而不是你的横排模式,演示地址
http://www.009blog.com/book/jiaocheng
是还需要添加什么吗
在header添加了
博主,你好,
我自定义了一个“post_type”,这种情况下应该怎么修改这个插件呢
谢谢
你试试在pre_get_post那里设定一下post type,用$query->set( ‘post_type’, ‘your_type’ );的方式。我没试过,你试试看。至于wp post views自带的排序,你要查查资料或读一下源代码,看它是不是支持custom post type
博主你好,访客文章排序(按自定义字段排序)可否做成下拉菜单形式,排序功能不要在链接里显示出来,这段代码可以实现 http://pastebin.com/LCFS945E 这个功能,但是无法分页,点击第2页或其它页后排序就无用了,而这段代码 https://gist.github.com/stompweb/3018263 可以实现无链接形式,但又不能以访客的方式选择,还是想用第一种方法结合 pre_get_posts 来做,博主有什么办法解决么?非常感谢!
分页以后排序无用是因为表单的值无法传递到分页后的页面,这个似乎用第一种或第二种都解决不了。
用session记录表单的选择,可以传递到分页后的页面。
将表单提交的数据变成query string的一部分,也可以在其它页面获取表单选择。
我感觉这个传值问题解决了,别的就好办了。
按你说的用第一种方法加pre_get_posts来实现,我觉得过程是这样:
用户选择排序顺序后,保单提交,页面重新加载,首先会执行pre_get_posts hook,将你第一段代码中处理表单提交数据的那段逻辑用在pre_get_posts那个函数中,用$query->set修改query string。
用自定义字段排序要使用meta query,参照第二段代码。
个人愚见,还望多多指教。
WP PostRatings 这插件很早的时侯也用过,感觉很占数据库体积,因为它还纪录打分的IP地址,不知道现在是不是还是这样的?
这种程序不大可能不占数据库,除非降低准确性。如果网站流量大,就应该交给第三方程序去完成,基于这个原因,WordPress一款很出色的插件Popularity Contest已经停止更新,而且不推荐使用了http://wordpress.org/extend/plugins/popularity-contest/
很不错的方法 有时间再集成到我的主题
能问你一个问题吗?关于你在窦露博客留言中回复到的WP Favorite Posts 插件,当使用了你推荐的插件,在安装过程中好像就出现了问题,插件说是在新建页面中只要插入{{wp-favorite-posts}}即可,但并没有用,请问你知道是什么原因吗?
我刚在wp3.4试了一下,可以用啊。在page编辑页面插入{{wp-favorite-posts}},这个页面就会显示你收藏的文章,前提是你得先收藏几篇文章。你可以看看这个博客www.tiger-blog.com,他每篇文章标题下面有个链接叫添加到我的收藏夹,页面顶部的链接有“我的收藏夹”,这就是wp favorite posts的实际效果,我的收藏夹就是添加{{wp-favorite-posts}}的页面。
如果不能用,你就装在裸的wordpress上试试,可能是你网站的什么插件跟他冲突了,另外不要禁用cookie。
貌似贵站的评论时间有点问题,1楼的时间是12:36,而2楼回复的时间确实9:57
Ludou果然好眼力。
他的回复时间实际上是凌晨(00:36),我输出时间用的WordPress默认函数,后台设置的时间格式是a g:i这种,是WordPress默认选项里的第一个,貌似g的有效区域是1-12,所以00点会自动转换成12点,就出现这种奇怪的现象了。而且WordPress提供的选项都是带g的,就都存在这个问题。
我换成自定义的格式H:i,应该不会引起这种误会了。
万分感谢,又让我发现个以前没注意到的问题!
你好 很感谢您的回复,听了您的建议我。我采取了以下动作:
1、我进了你推荐的www.tiger-blog.com博客后收藏了几篇文章,然后就进“我的收藏夹”页面,但是里面就默认的写收藏夹已清空。用的是360浏览器也没设置自动清空cookie,不太清楚是什么原因。
2、我只装有3个插件,听了你的建议,我停用了那3个插件,然后再试,还是无法显示我收藏的文章。我的操作如下:
新建一个叫Favorite.php的文件,然后在后台“页面”-新建页面–选择Favorite page模板页。
Favorite page
模板页 内容如下:
{{wp-favorite-posts}}
但是当我点击”查看“此网页时,他就直接输出文本”{{wp-favorite-posts}}“的字样,就没有任何其他东西了
{{wp-favorite-posts}}直接输出说明你的wp没能解析这个shortcode,在网上看确实有人反映这个软件会和某些插件冲突导致不能用,tiger的以前能用的,最近不知道为啥不能用了。
不过我本地安装的wp,用默认主题,可以用。请问你的favorite.php文件怎么写的?建议你用默认主题的默认page模板试一下,如果你的模板文件代码有问题,也可能导致错误发生。
经过你的提示,我重新,新装的裸wordpress测试,能够正常收藏和取消收藏,但是在列出收藏页面时,就还是直接输出函数的字样,证明应该是我在新建页面插入{{wp-favorite-posts}}代码上有误。
您可以把你从怎样创建新页面到插入{{wp-favorite-posts}}这句代码的操作及代码的详细文件给我讲下吗? 如果真的从您的博客这得到了帮助并解决了问题,那就十分感谢了!
你说的情况,除了你加的shortcode有错误之外,我想象不出别的原因。所以我装了一个测试站,安装了wp favorite posts插件,收藏功能和收藏夹页面我都加好了,你可以看一下。如果想看后台怎么加的,请你自己注册一个账户,就能看到收藏夹页面是怎么编辑的了。
测试站地址 http://demo.solagirl.net/
注册了 邮箱一直收不到密码!
兄弟啊,咱能不用qq邮箱不,俺这是国外服务器哦。
密码设置成你注册时用的qq号了,自己试试吧。
突然发现你在哪里都写不对露兜大神的名字啊,囧o(╯□╰)o
请问下 博客回复 是怎么实现的?如果是博客,就增加单独的样式吗
博主回复
需要修改wp_list_comments的回调函数,增加区分博主和普通访客的代码,具体可以看https://www.solagirl.net/wp_list_comments-comment-number-author-highlighter.html