在WordPress中將分類按照階層排列

目標

假設現在有一篇文章的分類包含以下多項,且彼此之間有階層關係。

  • 關東
    • 東京
      • 代官山
      • 澀谷
    • 神奈川
      • 橫濱

所以我們想要將這些分類,依照原本的階層順序顯示為:關東、東京、代官山、澀谷、神奈川、橫濱。在Wordpress中預設以name排序:代官山、東京、橫濱、澀谷、神奈川、關東,而其他比較有意義的排序法大概也就是按文章數量countquery查詢工具),但也並非想要的排列。

有些Plugin可以自訂分類排序,例如:

  • WP Term Order
  • Category Order and Taxonomy Terms Order
  • Custom Taxonomy Order

但是能夠改的排序,限為同層分類的排序,例如你可以把自訂把「澀谷」擺到「代官山」前面,或者讓「神奈川」整個群組都比「東京」先出現,依然不是我們要的功能。

只好來實做看看。

取得所有分類

首先要取得某篇文章的所選分類,可以用get_the_category來取得一個包含所有分類項目Object的Array,再利用array_map把這些分類的名稱單獨挑出來。

$object_id = get_the_ID();
$categories = get_the_category( $object_id );

$terms = implode( '、', array_map(function($item) { return $item->name; }, $categories ));
echo $terms; // 代官山、東京、橫濱、澀谷、神奈川、關東

或者,也可以使用wp_get_object_terms來取得任意自訂分類。

$object_id = get_the_ID();
$taxonomies = 'category'; // 這邊我們就選擇預設分類
$args = array( 'fields' => 'all' ); // options arguments
$categories = wp_get_object_terms( $object_id, $taxonomies, $args );

$terms = implode( '、', array_map(function($item) { return $item->name; }, $categories ));
echo $terms; // 代官山、東京、橫濱、澀谷、神奈川、關東

我們發現:欸?階層不見了,最上層的「關東」表示憤怒竟然排在最後!!!先不要管為什麼,但接下來我們就要利用分類項目中的parent屬性,來為每個項目進行認親的動作,以達到優先以階層排序的目的。

為分類找階層排序

懶得看文章的話程式碼在這裡,使用方法就是把wp_get_object_terms改成get_object_terms_hierarchical就可以惹。

<?php
// 點兩下這裡看原始碼
/**
  * Make terms retrieved by wp_get_object_terms() organized hierarchically.
  *
  * Use this function instead of wp_get_object_terms() to get a hierarchically
  * structured array or term data.
  *
  * This function takes the terms returned by wp_get_object_terms() and organizes
  * them into a hierarchical array with the parent's children (and grandchildren)
  * stored in nested arrays (within the 'children' item).
  *
  * @see wp_get_object_terms() for parameters.
  *
  * @return array $terms Hierarchilized $terms array.
  */
function get_object_terms_hierarchical( $object_ids, $taxonomies, $args = array() ) {
  $return_flat = true;
  $tree  = array();
  $terms = wp_get_object_terms( $object_ids, $taxonomies, $args );
  $ids = array_map(function($item) { return $item->term_id; }, $terms);
  if ( ! empty( $terms ) ) {
    foreach ( $terms as $term ) {
      if ( $term->parent == 0 || !in_array($term->parent, $ids) ) {
        if ( $return_flat ) {
          array_push($tree, $term);
          get_child_terms( $term->term_id, $terms, $tree );
        } else {
          $tree[ $term->term_id ] = $term;
          $tree[ $term->term_id ]->children = get_child_terms( $term->term_id, $terms );
        }
      }
    }
  }
      
  return $tree;
}
  
/**
 * Organizes the child terms.
  *
  * This is a recursive function.
  *
  * @param interval $parent_id The parent ID to retrieve the children terms of.
  * @param array  $terms The term data.
  *
  * @return array Returns nested child terms.
  */
function get_child_terms( $parent_id, $terms, &$order_terms = null ) {
  $children = array();
  foreach ( $terms as $term ) {
    if ( $term->parent == $parent_id ) {
      if ( $order_terms ) {
        array_push($order_terms, $term );
        get_child_terms( $term->term_id, $terms, $order_terms );
      } else {
        $children[ $term->term_id ] = $term;
        $children[ $term->term_id ]->children = get_child_terms( $term->term_id, $terms );
      }
    }
  }
  return $children;
}

第18行的$return_flat設定輸出為單層Array或者維持階層,設定為false的話子項目會存在children這個key裡。

測試看看。

$object_id = get_the_ID();
$taxonomies = 'category'; // here we use the default
$args = array( 'fields' => 'all' ); // options arguments

$categories = wp_get_object_terms( $object_id, $taxonomies, $args );
$terms = implode( '、', array_map(function($item) { return $item->name; }, $categories ));
echo $terms; // 關東、東京、代官山、澀谷、神奈川、橫濱

關東終於拿下他該有的位置了,很好!我們搞定。

解釋一下

事實上在後台設定了分類間的階層關係,也只會在Wordpress資料庫中新增一個parent欄位描述某個分類的上層id,所以資料本身是沒有分層的,我們必須再自己重新配對好它們的從屬關係才行。

事實上,Wordpress自己則是用了一個叫Walker類的方法,也一樣可以取得正確的階層分布,其基本原理也是會去「走」遍所有分類去做認親。

$object_id = get_the_ID();
$categories = get_the_category( $object_id );
$cat_ids = array_map( function($item) { return $item->term_id; },  $categories );
$args = array(
    'include' => $cat_ids,// 我們只取文章有使用到的分類 id 們
    'hierarchical' => true,
    'title_li' => '',   // 移除第一個大項目寫「分類」
    'style' => '',      // 設定成 list 以外的字串以避免輸出 ul>li
    'separator' => '、' // 將預設的 <br /> 改為中文頓號 
);
$terms = wp_list_categories( $args );
echo $terms; // 代官山、東京、橫濱、澀谷、神奈川、關東

成功!那你說我用wp_list_categories就好啦?不行。

假如今天沒有選用任何最上層分類的話,這裡就會出現bug。我們考慮同樣的分類階層,例如有一篇文章沒有勾選「關東」,只選用了其中的

  • 神奈川
    • 橫濱

這時候用Wordpress的內建函式wp_list_categories會得到

echo $terms; // 橫濱、神奈川

那欸阿餒?改用get_object_terms_hierarchical看看。

echo $terms; // 神奈川、橫濱

成功啦!

參考資料

  1. EricBusch/get_object_terms_hierarchical
  2. WordPress/get_the_category
  3. WordPress/wp_get_object_terms
  4. WordPress/wp_list_categories

ひより/Hiyori/日和

前言

台灣人出國旅遊最熱門的國家,就是日本。無論在任何季節,都有著許多特色景點的國家,春天賞櫻、夏天新綠、秋天紅葉、以及冬天白雪。櫻花的粉紅,象徵一個旅遊部落格的開始,以此開始逐漸成長茁壯,與一般遊記式的景點介紹不同,著重在更多資訊的分享,以景點的特色風情為主、以個人的旅遊經驗為輔,並且透過精心拍攝及挑選的照片,希望傳遞給讀者最真實的感動。

簡介

偶爾會有的食記,除了名店以外也會介紹特色的小店,每一篇文章底下的資訊欄,都可以幫助讀者更快速的找到所需要的相關情報,讓人無須迷失在其他類似的遊記中。

首頁的三篇焦點文章,是作者為自己最近生活的最佳註解,亦提供最合時宜的當季精選。有需要的人則可以立即透過首頁的行動按鈕,傳送信息聯絡作者,洽詢相關的合作機會。

Hiyori在日文裡是晴天的意思,希望每一趟旅程,都成為美好的回憶、心情也放晴:)

Computer Vision Research Center

視覺:方。

  • 由方形的監視螢幕來監控
  • 由方塊構成的電腦分析
  • 以方格來辨識其中模糊的資訊
  • 將格子像素變小亦即代表解析度的提升。

色調:調整過的紅藍綠

  • 紅藍綠三原色乃光的三原色,無論是視覺或是螢幕顯示都可以由三原色來解析,是最符合電腦視覺的三個顏色,微調後使之成為網站設計時的基本顏色。
  • 暗藍色暗喻未知的背景,並利用輔色的紅色框框來顯示掃描、偵測的功能。
  • 亮藍色代表已知的事物,代表研發中心所發展的技術以及內容,都爐火純青且公開透明,歡迎各廠商來洽談。

整體網站編排

  • 將導覽列設計在下方,有如在操作 Windows 作業系統,左邊的直欄就是開始工作列。
  • 整個中心網站,就像是一部電腦。從研發中心開始,將為您帶來最先進的科技之意。
  • 另外,在版面安排的時候,會考量各區塊的重量配置,希望儘量達到視覺上的平衡,並且期望在各螢幕大小上都有最佳的瀏覽體驗。