📋
WordPress のセレクトボックス(プルダウン)で階層構造を表現する
TL;DR
標準の WordPress 関数ではセレクトボックスの階層構造を表現出来ない
再帰関数を利用するのでちょっと複雑
ちょっとコードは雑だけど一応動いたので共有
実装例
出力はこんな感じです。
<option value="https://example.com/info">お知らせ</option>
<option value="https://example.com/case">査定事例</option>
<option value="https://example.com/case/aichi">  愛知県</option>
<option value="https://example.com/case/aichi/toyohashi">    豊橋市</option>
<option value="https://example.com/case/aichi/nagoya">    名古屋市</option>
実装コード
/**
* カテゴリー一覧をプルダウンで出力:階層構造に対応
*
*/
function show_select_box_category_ancester(string $taxName ='category')
{
$args = array(
'orderby' => 'term_order',
'hide_empty' => false
);
$termsData = get_terms($taxName, $args);
return taxonomyTreeOptions($termsData, $taxName);
}
/**
* 現在のslugを返す
*
*/
function currentTermSlug(string $taxName)
{
if($taxName === 'category'){
return get_query_var('category_name');
}
return get_query_var('term');
}
/**
* 親カテゴリーをベースにした再帰関数によって階層構造を持ったタクソノミーリストを作成
*/
function taxonomyTreeOptions(array $getTermsArray, string $taxName )
{
$categoryHierarchy = [];
sort_terms_hierarchically($getTermsArray, $categoryHierarchy);
return recursiveSelectBox($categoryHierarchy, $taxName);
}
/**
* Recursively sort an array of taxonomy terms hierarchically. Child categories will be
* placed under a 'children' member of their parent term.
* https://wordpress.stackexchange.com/questions/14652/how-to-show-a-hierarchical-terms-list
* @param Array $cats taxonomy term objects to sort
* @param Array $into result array to put them in
* @param integer $parentId the current parent ID to put them in
*/
function sort_terms_hierarchically(array &$cats, array &$into, $parentId = 0)
{
foreach ($cats as $i => $cat) {
if ($cat->parent == $parentId) {
$into[$cat->term_id] = $cat;
unset($cats[$i]);
}
}
foreach ($into as $topCat) {
$topCat->children = array();
sort_terms_hierarchically($cats, $topCat->children, $topCat->term_id);
}
}
/**
* 再帰的にselectboxを作成
* $term->children に配列が設定されていたら再帰取得する
*/
function recursiveSelectBox(array $categoryHierarchy, string $taxName, int $count = 0, string $output = '')
{
foreach($categoryHierarchy as $term){
$output .= outputSelectBox($term, $taxName, $count);
if (is_array($term->children) && !empty($term->children)) {
$output = recursiveSelectBox($term->children, $taxName, ++$count, $output);
}
}
return $output;
}
/**
* option出力
*
*/
function outputSelectBox(WP_Term $term, string $taxName, $count)
{
$prefix = '';
//再帰関数のせいか、$countが1になってしまうのを是正
if($term->parent === 0) $count = 0;
for($i = 0; $i<$count; ++$i){
$prefix .= '  ';
}
$selected = currentTermSlug($taxName) === $term->slug ? ' selected' : '';
return '<option value="'.esc_url(link_by_term($term, $taxName)).'"'.$selected.'>'.$prefix.esc_attr($term->name).'</option>';
}
呼び出し側
<select class="select-category">
<option value="">ALL</option>
<?php echo show_select_box_category_ancester();?>
</select>
注目はこちらの再帰関数ですね。コメントでもリンクしていますが、以下 StackExchange のコードを利用させて頂きました。
get_terms で取得した terms オブジェクトに対して、$term->children を入れ子にした階層構造を作成してくれます。
Discussion