📋

WordPress のセレクトボックス(プルダウン)で階層構造を表現する

2022/10/27に公開

TL;DR

標準の WordPress 関数ではセレクトボックスの階層構造を表現出来ない
再帰関数を利用するのでちょっと複雑
ちょっとコードは雑だけど一応動いたので共有

実装例

出力はこんな感じです。

<option value="https://example.com/info">お知らせ</option>
<option value="https://example.com/case">査定事例</option>
<option value="https://example.com/case/aichi">&#160;&#160;愛知県</option>
<option value="https://example.com/case/aichi/toyohashi">&#160;&#160;&#160;&#160;豊橋市</option>
<option value="https://example.com/case/aichi/nagoya">&#160;&#160;&#160;&#160;名古屋市</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 .= '&#160;&#160;';
	}
	$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 のコードを利用させて頂きました。
https://wordpress.stackexchange.com/questions/14652/how-to-show-a-hierarchical-terms-list#answer-99516
get_terms で取得した terms オブジェクトに対して、$term->children を入れ子にした階層構造を作成してくれます。

Discussion