【WordPress】現在見ているカテゴリ以外を非表示にするウィジェットのカスタマイズ

現在のカテゴリー以外を非表示にする

ここではWordPressのウィジェットでサイドバーにカテゴリーを表示し、Windowsエクスプローラーの様な閉じたツリー表示にする方法を解説します。

カテゴリーが多くなるとサイドバーが長くなる問題

WordPressのウィジェットでサイドバーにカテゴリーを表示している方は多いですよね。

しかしカテゴリーが多くなってくると、縦に長くなりすぎて見にくいことがあります。

カテゴリーの表示が長い

そこで、表示している記事と関係のないカテゴリーを非表示にすることを考えます。

Windowsエクスプローラーがフォルダの階層をツリー表示するように、現在表示しているカテゴリー以外を非表示にするのが目標です。

現在のカテゴリー以外を非表示にしたい(実現したいこと)

カテゴリーを階層化し、現在見ているカテゴリー以外を隠す(非表示にする)ことで見やすくしたいと思います。

カテゴリーを見やすくする

具体的には上の画像のように表示するのが目標です。

「コードレス掃除機」というカテゴリーを見ているか、もしくは「コードレス掃除機に属する個別記事」を見ているときのイメージです。

「掃除機」の1階層下のカテゴリーが全て表示され、「掃除機」と同じ階層で「家電」カテゴリーに属するカテゴリーが全て表示されています。

現在のカテゴリー以外を非表示にするには?(実装の方針)

まずウィジェットのカテゴリーがどのようなHTMLになっているのか確認します。

その準備として、WordPressのウィジェットを階層表示させます。

「外観->ウィジェット」を表示し、サイドバーのカテゴリーで「階層を表示」にチェックを入れます。

階層を表示

これでカテゴリーが階層を表示されます。

カテゴリーを階層表示にすると以下の様なHTMLが出力されます。

HTML
<li class="cat-item cat-item-1">親カテゴリー1
<ul class="children">
	<li class="cat-item cat-item-2">子カテゴリー1
	<ul class="children">
		<li class="cat-item cat-item-3">孫カテゴリー1</li>
		<li class="cat-item cat-item-4">孫カテゴリー2</li>
		<li class="cat-item cat-item-5">孫カテゴリー3</li>
	</ul>
	</li>
	<li class="cat-item cat-item-6">子カテゴリー2</li>
	<li class="cat-item cat-item-7">子カテゴリー3</li>
</ul>
</li>
<li class="cat-item cat-item-8">親カテゴリー2
<ul class="children">
	<li class="cat-item cat-item-9">子カテゴリー4</li>
	<li class="cat-item cat-item-10">子カテゴリー5</li>
	<li class="cat-item cat-item-11">子カテゴリー6</li>
</ul>
</li>

子孫となるカテゴリーはクラスがchildrenの<ul>で囲まれます。

<li>にはWordPressにより「cat-item-○」というようなクラスが付加されています。

○の部分はカテゴリーのIDです。例えば、ID=15のカテゴリーに対しては「cat-item-15」というクラスが付加されています。

子孫カテゴリーを非表示にする

子孫カテゴリーを非表示にするには、クラスがchildrenのulタグ非表示にすることでできます。

CSSで以下のようにすると子孫カテゴリーを非表示にできます。

CSS
.children{
	display:none;
}

しかしこれだと全ての子孫カテゴリーが非表示になり、表示させたいカテゴリーまで隠れてしまいます。

現在見ているカテゴリーを表示するには?

現在見ているカテゴリーを表示するにはどうしたら良いでしょうか?

表示したいカテゴリー以外を非表示にすれば良いので、CSSの否定擬似クラス(:not)を使えばできそうです。

まず、表示したいカテゴリーにselectedというクラスを付加します。

HTML
<li class="cat-item cat-item-1">親カテゴリー1
<ul class="children selected">
	<li class="cat-item cat-item-2">子カテゴリー1
	<ul class="children selected">
		<li class="cat-item cat-item-3 selected">孫カテゴリー1</li> <!--ここを表示中-->
		<li class="cat-item cat-item-4">孫カテゴリー2</li>
		<li class="cat-item cat-item-5">孫カテゴリー3</li>
	</ul>
	</li>
	<li class="cat-item cat-item-6">子カテゴリー2</li>
	<li class="cat-item cat-item-7">子カテゴリー3</li>
</ul>
</li>
<li class="cat-item cat-item-8">親カテゴリー2
<ul class="children">
	<li class="cat-item cat-item-9">子カテゴリー4</li>
	<li class="cat-item cat-item-10">子カテゴリー5</li>
	<li class="cat-item cat-item-11">子カテゴリー6</li>
</ul>
</li>

上のコードは「親カテゴリー1 > 子カテゴリー1 > 孫カテゴリー1」を表示しているときの状態です。

次に、CSSでnotを使いselected以外を非表示にします。

CSS
.children:not(.selected){
	display:none;
}

これで「親カテゴリー2」の下層にあるカテゴリーは非表示になります。

実装方法

表示したいカテゴリーにselectedクラスを付加する方法を考えます。

ぱっと思いつくのはjQueryを使う方法です。

他にはWordPressのWalkerクラスを継承したクラスを作成する方法があります。

jQueryの方が簡単に作れそうなので、今回はjQueryを使って実装していきます。

処理の流れ

jQueryを使って、表示したいカテゴリーや<ul>にselectedクラスを付加します。

個別の記事を表示しているときと、カテゴリーアーカイブを表示しているときで処理が異なります。

カテゴリーアーカイブを表示しているとき
  1. 「そのカテゴリーに属する1つ下の階層」のカテゴリーをすべて表示する。
  2. 「そのカテゴリーと同じ階層」かつ「親カテゴリーに属する」カテゴリーを表示する。
  3. その1階層上について2.と同じ処理を繰り返す。
個別記事(エントリー)を表示しているとき
  1. 「その記事が属するカテゴリーと同じ階層」かつ「親カテゴリーに属する」カテゴリーを表示する。
  2. その1階層上について1.と同じ処理を繰り返す。

jQueryの記述場所

jQueryを記述するのは子テーマのfunctions.phpが良いでしょう。

テンプレートに直接記述すると、テンプレートをバージョンアップしたときに上書きされて消えてしまいます。

子テーマに記述しておけばバージョンアップしても上書きされてきえてしまうことはありません。

functions.php
function my_load_widget_scripts() {
	//ここにjavascriptを記述する
}
add_action('wp_footer', 'my_load_widget_scripts');

こうしておけばfooter部分にjavascriptが出力されます。

CSSの記述場所

CSSもjQueryと同様に子テーマのstyles.cssに記述しておくと、バージョンアップにより上書きされることはありません。

コーディングする

functions.phpに以下のように追記します。

functions.php
function my_load_widget_scripts() {
	if( is_category() ) //カテゴリーアーカイブのとき
	{
		$cat_id = get_query_var('cat');
		$cur_class = '.cat-item-' . $cat_id;
		
		$str = '<script type="text/javascript">
			jQuery(function(){
				jQuery("'.$cur_class.'").parents(".children").addClass("selected");
				jQuery("'.$cur_class.'").children(".children").addClass("selected");
			});
		</script>';
		echo $str;
	}
	else if( !is_front_page() && !is_home() ) //トップページ以外
	{
		$cat = get_the_category();
		$cur_class = '.cat-item-' . $cat[0]->term_id;
		
		$str = '<script type="text/javascript">
			jQuery(function(){
				jQuery("'.$cur_class.'").addClass("selected");
				jQuery("'.$cur_class.'").parents(".children").addClass("selected");
			});
		</script>';
		echo $str;
	}
}
add_action('wp_footer', 'my_load_widget_scripts');
注意
通常は「jQuery」の部分は「$」で記述していますが、コンフリクトしたので「jQuery」としています。

CSSには以下のように追記します。

style.css
.widget_categories .children:not(.selected){
	display:none;
}

ウィジェットにあるchildrenクラスのみを非表示にするために、widget_categoriesクラスを指定しました。

これがないとウィジェット以外にあるchildrenクラスも非表示になってしまいます。

widget_categoriesクラスを指定しておけば記事本文などでchildrenというクラスを使っていても消えてしまうことはありません。

以上の実装をしたところ、下の画像のような結果になりました。

不要なカテゴリーを非表示にしたもの

カテゴリーアーカイブの表示結果

カテゴリーアーカイブを表示

「動物」カテゴリーを表示したときは上の画像のようになります。

「動物」カテゴリーの子カテゴリーが全て表示されています。

個別記事の表示結果

個別記事を表示

「動物 > 犬 > 柴犬」カテゴリーにある個別記事を表示したときは上の画像のようになります。

「柴犬」と同じ階層にあるカテゴリーで「犬」の1階層下のものが全て表示されています。

「犬」と同じ階層にあるカテゴリーで「動物」の1階層下のものが全て表示されています。

まとめ

以上で希望通りの結果が得られました。

個別記事とカテゴリーアーカイブでしか試してないので、それ以外のアーカイブを表示したときは希望通りの動作にならないかもしれません。