文章筛选功能以前写过一个教程 WordPress 进阶教程 (四十): 文章筛选功能,通过加多个分类法来实现。
过了这么久,经常有人找我要定制文章筛选功能,现再放出代码使用自定义字段实现,而且用自定义字段实现文章筛选,比用分类法应该更简单,更强大。
以阿树自己建立的一个网站作为例子:游炎陵,这是为了推广家乡旅游建立的。示例页面:http://youyanling.com/destinations 。
前台效果:通过 url 传递参数。
后台效果:使用自定义字段。范例中使用自己的 ashuwp_framework 框架添加的自定义字段,都是复选框。
一、添加自定义字段
添加自定义字段的方法不再赘述,可以使用我们的框架,也可以使用自己的方法添加。
范例网站添加的两个自定义字段的名称分别为:destination_location 和 destination_season 。
自定义字段是复选框,所以值也是固定的,当然可能是字符串也可能是数组。
地域的值可能是 center 、 east 、 west 、 south,若多选了,保存的值是数组。
季节的值可能是 spring 、 summer 、 autumn 、 winter,若多选了,保存的值四号数组。
二、前台输出筛选地址
筛选列表各个项的 url 有多种可能:
刚打开页面时,筛选列表的 url,只需要一个参数。
西片->http://youyanling.com/destinations?area=west
南片->http://youyanling.com/destinations?area=south
...
春季->http://youyanling.com/destinations?season=spring
夏季->http://youyanling.com/destinations?season=summer
...
若点击了其中一项,比如点击了 「西片」 之后,此时筛选项目中地域的 url 不需要改变,但是季节的所有 url 都需要加上已经选中的 area=west 。如下
西片->http://youyanling.com/destinations?area=west
南片->http://youyanling.com/destinations?area=south
...
春节->http://youyanling.com/destinations?area=west&season=spring
夏季->http://youyanling.com/destinations?area=west&season=summer
...
同理,两种筛选都点击之后,此时每个筛选项目的 url 都需要带两个参数,且互相加上对方已经选中的参数。比如点击了 「西片」,「春季」 两项之后。
西片->http://youyanling.com/destinations?season=spring&area=west
南片->http://youyanling.com/destinations?season=spring&area=south
...
春节->http://youyanling.com/destinations?area=west&season=spring
夏季->http://youyanling.com/destinations?area=west&season=summer
...
而上面这种格式的 url 都是用 add_query_arg 函数输出。
用法范例 (输出我们需要的带两个参数的 url)
- <?php
- $base = 'http://youyanling.com/destinations';
- $params = array(
- 'area'=>'west',
- 'season'=>'spring',
- );
- //下面代码将会输出 http://youyanling.com/destinations?area=west&season=spring
- echo esc_url( add_query_arg( $params, $base ) );
- ?>
不管懂没懂,反正前台输出筛选列表得用如下代码 (下面代码是范例的真实代码加了注释),在需要出现筛选列表的位置加入如下代码。
- <?php
- $base = get_post_type_archive_link('destination'); //筛选页面的地址
- $area_sort = get_query_var('area'); //从 url 中获取地域参数
- $season_sort = get_query_var('season'); //从 url 中获取季节参数
- //注意,由于本筛选有两个参数,季节和地域,所以要将地域参数让如季节筛选的 url 中,季节的参数放入地域筛选的 url 中
- //检测获取到的季节参数是否正常
- $area_params = array(); //地域的参数数组
- if(in_array($season_sort,array('all','spring','summer','autumn','winter'))){
- $area_params['season'] = $season_sort; //若季节正常,将季节参数放入地域筛选的 url 中
- }
- //检测获取到的地域参数是否正常
- $season_params = array(); //季节的参数数组
- if(in_array($area_sort,array('all','center','east','west','south'))){
- $season_params['area'] = $area_sort; //若地域正常,将地域参数放入季节筛选的 url 中
- }
- $selected = 'class="selected"';
- ?>
- <div class="group clearfix">
- <div class="group_title"> 位置:</div>
- <div class="list clearfix">
- <?php
- //将地域数组的地域设置为 all
- $area_params['area'] = 'all';
- ?>
- <a <?php if($area_sort=='all') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $area_params, $base ) ); ?>"> 全境</a>
- <?php
- //将地域数组的地域设置为 center
- $area_params['area'] = 'center';
- ?>
- <a <?php if($area_sort=='center') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $area_params, $base ) ); ?>"> 城区周边</a>
- <?php $area_params['area'] = 'west'; ?>
- <a <?php if($area_sort=='west') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $area_params, $base ) ); ?>"> 西片</a>
- <?php $area_params['area'] = 'south'; ?>
- <a <?php if($area_sort=='south') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $area_params, $base ) ); ?>"> 南片</a>
- <?php $area_params['area'] = 'east'; ?>
- <a <?php if($area_sort=='east') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $area_params, $base) ); ?>"> 东片</a>
- </div>
- </div>
- <div class="group clearfix">
- <div class="group_title"> 季节:</div>
- <div class="list clearfix">
- <?php $season_params['season'] = 'all';?>
- <a <?php if($season_sort=='all') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $season_params, $base ) ); ?>"> 全部</a>
- <?php $season_params['season'] = 'spring';?>
- <a <?php if($season_sort=='spring') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $season_params, $base ) ); ?>"> 春季</a>
- <?php $season_params['season'] = 'summer';?>
- <a <?php if($season_sort=='summer') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $season_params, $base ) ); ?>"> 夏季</a>
- <?php $season_params['season'] = 'autumn';?>
- <a <?php if($season_sort=='autumn') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $season_params, $base ) ); ?>"> 秋季</a>
- <?php $season_params['season'] = 'winter';?>
- <a <?php if($season_sort=='winter') echo $selected; ?> href="<?php echo esc_url( add_query_arg( $season_params, $base ) ); ?>"> 冬季</a>
- </div>
- </div>
三、增加可查询变量
前台输出地址和等下后台都要用到从 url 中获取参数,都使用了 get_query_var 这个函数,不过这个函数获取参数还需要将你要查询的变量加入到 「公共可查询变量中」,这个我也不知道怎么翻译。
使用如下代码使得 area 和 season 两个参数可用 (在 functions.php 文件中加入如下代码) 。
- function ashu_query_vars($public_query_vars) {
- $public_query_vars[] = 'area';
- $public_query_vars[] = 'season';
- return $public_query_vars;
- }
- add_action('query_vars', 'ashu_query_vars');
当然,你也可以使用 $_GET 方法来获取变量。
四、按条件输出文章
有了前面三步,至少在前台显示的 url 是可以正常工作。
第四步也就是最后一步,让前台的文章输出我们想要的。
要点:1. 使用 pre_get_posts 钩子来改变文章查询的参数 2. 如何使用自定义字段查询文章。
(在 functions.php 文件中加入如下代码)
- add_action('pre_get_posts','ashuwp_custom_posts_per_page'); //使用 pre_get_posts 钩子来改变查询文章的参数
- function ashuwp_custom_posts_per_page($query){
- //范例中的页面是 destination 的归档页面,所以使用 is_post_type_archive 来判断页面
- if(is_post_type_archive('destination') && $query->is_main_query() && !is_admin()){
- $relation = 0; //用来计数有几个参数
- $area_sort = get_query_var('area'); //获取地域参数
- $season_sort = get_query_var('season'); //获取季节参数
- $meta_query = array(
- 'relation' => 'OR',
- );
- //判断季节是否合法,此处就不需要 all 了,因为 all 就是所有
- if(in_array($season_sort,array('spring','summer','autumn','winter'))){
- $meta_query[] = array(
- 'key'=>'destination_season', //自定义字段的名称
- 'value'=> $season_sort,
- 'compare'=>'LIKE', //因为自定义字段值可能保存为数组,所以按字段查询文章时使用 LIKE
- );
- $relation++;
- }
- //判断地域是否合法
- if(in_array($area_sort,array('center','east','west','south','center'))){
- $meta_query[] = array(
- 'key'=>'destination_location',
- 'value'=> $area_sort,
- 'compare'=>'LIKE',
- );
- $relation++;
- }
- //如果有两个参数,relation 要设置为 AND,即两个条件都要满足
- if($relation){
- if($relation==2){
- $meta_query['relation'] = 'AND';
- }
- $query->set('meta_query',$meta_query);
- }
- }
- }
END 。