文章篩選功能以前寫過一個教程 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 。