プラグインなしでカテゴリの親子階層をアコーディオンで出力

カテゴリーのアコーディオン

ブログで記事が増えてくると、カテゴリーもそれに比例して深くなりがちで、それらを全て表示するとかなりの長さになってしまいます。

以前、以下の記事でそんなカテゴリの表示カスタマイズをjQueryで行いました。

アコーディオンのイラスト jQueryを使ってWordPressの子カテゴリーをアコーディオンで表示させるスニペット

打って変わってこの記事のスニペットは、同じ内容をネイティブなJavaScriptで置き換えて、かつ無理くりにリンクを打ち消す処理をしない自然な記述内容でオススメです。

「カテゴリが増えてしまい整理したい」「アコーディオンでカテゴリをスッキリさせたい」方は、この記事を参考にしてみてください。

アコーディオンで展開するカテゴリ一覧のサンプル

早速、カテゴリ一覧をアコーディオンで展開するサンプルです。サンプルは2種で、上から順に「記事数付き」と「記事数なし」の2種類です。

どちらも、「子カテゴリがある親カテゴリはアコーディオン」。それ以外のカテゴリは、aタグのリンクになっています。

記事数付のアコーディオン

記事数なしのアコーディオン

実装の手順と方法

手順と方法

それでは、実装の手順と方法についてです。言語は、PHP・CSS・JavaScriptの3種で、5つの手順です。

これらを順に説明していきます。

PHPのファイルを使えるよう、準備

記事ページにPHPのコードをそのまま記述をしても、表示されません。

その為、PHPをショートコードで好きな場所で使用できるように準備しておく必要があるので、以下の記事を参考に準備しておきましょう。

phpのショートコードのイラスト プラグインなしでページ内にPHPを読み込む方法
かかかず
かかかず

これでウィジェットや記事内など、好きな場所にPHPを設置する事ができます。

PHPを記述

次に、表示させたい場所。もしくはショートコードで読み込みさせるPHPのファイルにコードを記述します。

以下のPHPのコードは、「記事数付き」「記事数なし」の2種類です。後述するCSSやJavaScriptのコードは共通なので、どちらを使っても大丈夫です。

記事数付きのPHPコード

コードを表示する

PHP

<ul class="accordionCat">
<?php
$args = array(
    'taxonomy'   => 'category',
    'orderby'    => 'menu_order',
    'pad_counts' => true,
);
$categories = get_categories($args);
?>
<?php foreach( $categories as $category ) :?>
<?php
$childcatnum = count(get_term_children($category->cat_ID,'category'));
?>
<?php if($childcatnum > 0) : //アコーディオンの親 ?>
<?php
$catchildargs = array('parent'=>$category->cat_ID);
$catchilds = get_categories($catchildargs);
?>
<li>
<div class="accordion cat-item-<?php echo $category->cat_ID; ?>">
<?php echo $category->name ;?><span class="postCount"><?php echo $category->count;?></span>
</div>
<ul class="children">
<?php
foreach($catchilds as $catchild):?>
<?php $cat_link = get_category_link($catchild ->cat_ID);?>
<li>
<a href="<?php echo $cat_link ;?>">
<?php echo $catchild->name ;?><span class="postCount"><?php echo $catchild->count;?></span>
</a>
</li>
<?php endforeach ;?>
</ul>
<?php elseif ($childcatnum == 0 && $category->category_parent == 0) : //親のみの場合 ?>

<li class="catparent cat-item-<?php echo $category->cat_ID; ?>">
<a href="<?php echo get_category_link( $category->term_id ) ;?>">
	<?php echo $category->name ;?><span class="postCount"><?php echo $category->count;?></span>
</a>
</li>
<?php endif ;?>
</li>
<?php endforeach ;?>
</ul>

記事数なしのPHPコード

コードを表示する

PHP

<ul class="accordionCat">
<?php
$args = array(
    'orderby' => 'menu_order',
    'parent' => 0,
);
$categories = get_categories($args);
?>
<?php foreach( $categories as $category ) :?>
<?php
$childcatnum = count(get_term_children($category->cat_ID,'category'));
?>
<?php if($childcatnum > 0) : //アコーディオンの親 ?>
<?php
$catchildargs = array('parent'=>$category->cat_ID);
$catchilds = get_categories($catchildargs);
?>
<li>
<div class="accordion cat-item-<?php echo $category->cat_ID; ?>">
<?php echo $category->name ;?>
</div>
<ul class="children">
<?php
foreach($catchilds as $catchild):?>
<?php $cat_link = get_category_link($catchild ->cat_ID);?>
<li>
<a href="<?php echo $cat_link ;?>">
<?php echo $catchild->name ;?>
</a>
</li>
<?php endforeach ;?>
</ul>
<?php elseif ($childcatnum == 0) : //親のみの場合 ?>
<li class="catparent cat-item-<?php echo $category->cat_ID; ?>">
<a href="<?php echo get_category_link( $category->term_id ) ;?>">
	<?php echo $category->name ;?>
</a>
</li>
<?php endif ;?>
</li>
<?php endforeach ;?>
</ul>

かかかず
かかかず

50記事以上など、ある程度記事数があるなら「記事数付き」の方がハマると思います。

JavaScriptのコードを記述

PHPを記述したら、JavaScriptのコードを記述してアコーディオンにします。

以下のコードを、<body>〜</body> のクロージングタグ前に記述すればOKです。

JavaScript

var acc = document.getElementsByClassName('accordion');
var i;
for ( i = 0; i < acc.length; i++ ){
    acc[i].onclick = function() {
    this.classList.toggle('active');
    var panel = this.nextElementSibling;
    if ( panel.style.maxHeight ){
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + 'px';
    }
  }
}

CSSを記述

最後に、見た目を整える為にCSSをコピペします。

CSS

ul.accordionCat {
    list-style: none;
    padding: 0;
    border: none;
    margin: 0;
}
ul.accordionCat li {
    margin: 0;
    padding: 0;
    line-height: 42px;
}
ul.accordionCat li div.accordion {
    padding-left: 10px;
}
ul.accordionCat li a {
    display: block;
    color: #626262;
    padding-left: 10px;
}
div.accordion {
    display: block;
    border: none;
    cursor: pointer;
    transition: 0.1s ease-in;
    position: relative;
    margin: 0;
    background: #FFF;
}
div.accordion, li.catparent {
    font-weight: 600;
    color: #626262;
}
.accordion.active {
    margin-bottom: 0;
}
.entry-content ul.children {
    max-height: 0;
    overflow: hidden;
    transition: 0.3s ease-out;
    padding: 0;
}
div.accordion:hover, ul.accordionCat li a:hover{
  background-color: #efefef;
  text-decoration: none;
}
div.accordion:after {
    color: #6bb6ff;
    position: absolute;
    right: 15px;
    top: 50%;
    transform: translateY(-53%);
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    font-size: 1em;
    content: "\f055";
}
div.accordion.active:after {
    content: "\f056";
}

span.postCount {
    background: #ebfcfe;
    color: #005fa0;
    display: inline-block;
    overflow: hidden;
    min-width: 24px;
    height: 24px;
    margin-left: 7px;
    border-radius: 3px;
    font-size: 12px;
    font-weight: normal;
    text-align: center;
    vertical-align: -5px;
    line-height: 24px;
}
ul.children li a:before {
    color: silver;
    content: "\f105";
    padding-left: 5px;
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    font-size: 0.95em;
    padding-right: 5px;
}
ul.accordionCat li ul.children li a {
    font-size: 0.95rem;
}

CSSのコードは当サイトに合わせて作っていますので、使うサイトに応じてカスタマイズしてお使いください。

かかかず
かかかず

このCSSを使う場合、Fontawesomeも使っているので一緒に使うようにしてください。

きちんと動くかチェック

最後に、作ったカテゴリ一覧がきちんと表示されるかチェックしましょう。

これできちんと表示されていれば完了です。

コピペ用コード一式

上記の「手順と方法」で紹介した同じコードです。

「詳しい説明等は不要でコピペして使いたい」方は、こちらのコードをそれぞれまるっとコピペすれば完了です。

記事数付のアコーディオンのコード一式

コードを表示する

PHP

<ul class="accordionCat">
<?php
$args = array(
    'taxonomy'   => 'category',
    'orderby'    => 'menu_order',
    'pad_counts' => true,
);
$categories = get_categories($args);
?>
<?php foreach( $categories as $category ) :?>
<?php
$childcatnum = count(get_term_children($category->cat_ID,'category'));
?>
<?php if($childcatnum > 0) : //アコーディオンの親 ?>
<?php
$catchildargs = array('parent'=>$category->cat_ID);
$catchilds = get_categories($catchildargs);
?>
<li>
<div class="accordion cat-item-<?php echo $category->cat_ID; ?>">
<?php echo $category->name ;?><span class="postCount"><?php echo $category->count;?></span>
</div>
<ul class="children">
<?php
foreach($catchilds as $catchild):?>
<?php $cat_link = get_category_link($catchild ->cat_ID);?>
<li>
<a href="<?php echo $cat_link ;?>">
<?php echo $catchild->name ;?><span class="postCount"><?php echo $catchild->count;?></span>
</a>
</li>
<?php endforeach ;?>
</ul>
<?php elseif ($childcatnum == 0 && $category->category_parent == 0) : //親のみの場合 ?>

<li class="catparent cat-item-<?php echo $category->cat_ID; ?>">
<a href="<?php echo get_category_link( $category->term_id ) ;?>">
	<?php echo $category->name ;?><span class="postCount"><?php echo $category->count;?></span>
</a>
</li>
<?php endif ;?>
</li>
<?php endforeach ;?>
</ul>

CSS

ul.accordionCat {
    list-style: none;
    padding: 0;
    border: none;
    margin: 0;
}
ul.accordionCat li {
    margin: 0;
    padding: 0;
    line-height: 42px;
}
ul.accordionCat li div.accordion {
    padding-left: 10px;
}
ul.accordionCat li a {
    display: block;
    color: #626262;
    padding-left: 10px;
}
div.accordion {
    display: block;
    border: none;
    cursor: pointer;
    transition: 0.1s ease-in;
    position: relative;
    margin: 0;
    background: #FFF;
}
div.accordion, li.catparent {
    font-weight: 600;
    color: #626262;
}
.accordion.active {
    margin-bottom: 0;
}
.entry-content ul.children {
    max-height: 0;
    overflow: hidden;
    transition: 0.3s ease-out;
    padding: 0;
}
div.accordion:hover, ul.accordionCat li a:hover{
  background-color: #efefef;
  text-decoration: none;
}
div.accordion:after {
    color: #6bb6ff;
    position: absolute;
    right: 15px;
    top: 50%;
    transform: translateY(-53%);
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    font-size: 1em;
    content: "\f055";
}
div.accordion.active:after {
    content: "\f056";
}

span.postCount {
    background: #ebfcfe;
    color: #005fa0;
    display: inline-block;
    overflow: hidden;
    min-width: 24px;
    height: 24px;
    margin-left: 7px;
    border-radius: 3px;
    font-size: 12px;
    font-weight: normal;
    text-align: center;
    vertical-align: -5px;
    line-height: 24px;
}
ul.children li a:before {
    color: silver;
    content: "\f105";
    padding-left: 5px;
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    font-size: 0.95em;
    padding-right: 5px;
}
ul.accordionCat li ul.children li a {
    font-size: 0.95rem;
}

JavaScript

var acc = document.getElementsByClassName('accordion');
var i;
for ( i = 0; i < acc.length; i++ ){
    acc[i].onclick = function() {
    this.classList.toggle('active');
    var panel = this.nextElementSibling;
    if ( panel.style.maxHeight ){
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + 'px';
    }
  }
}

記事数なしのアコーディオンのコード一式

コードを表示する

PHP

<ul class="accordionCat">
<?php
$args = array(
    'orderby' => 'menu_order',
    'parent' => 0,
);
$categories = get_categories($args);
?>
<?php foreach( $categories as $category ) :?>
<?php
$childcatnum = count(get_term_children($category->cat_ID,'category'));
?>
<?php if($childcatnum > 0) : //アコーディオンの親 ?>
<?php
$catchildargs = array('parent'=>$category->cat_ID);
$catchilds = get_categories($catchildargs);
?>
<li>
<div class="accordion cat-item-<?php echo $category->cat_ID; ?>">
<?php echo $category->name ;?>
</div>
<ul class="children">
<?php
foreach($catchilds as $catchild):?>
<?php $cat_link = get_category_link($catchild ->cat_ID);?>
<li>
<a href="<?php echo $cat_link ;?>">
<?php echo $catchild->name ;?>
</a>
</li>
<?php endforeach ;?>
</ul>
<?php elseif ($childcatnum == 0) : //親のみの場合 ?>
<li class="catparent cat-item-<?php echo $category->cat_ID; ?>">
<a href="<?php echo get_category_link( $category->term_id ) ;?>">
	<?php echo $category->name ;?>
</a>
</li>
<?php endif ;?>
</li>
<?php endforeach ;?>
</ul>

CSS

ul.accordionCat {
    list-style: none;
    padding: 0;
    border: none;
    margin: 0;
}
ul.accordionCat li {
    margin: 0;
    padding: 0;
    line-height: 42px;
}
ul.accordionCat li div.accordion {
    padding-left: 10px;
}
ul.accordionCat li a {
    display: block;
    color: #626262;
    padding-left: 10px;
}
div.accordion {
    display: block;
    border: none;
    cursor: pointer;
    transition: 0.1s ease-in;
    position: relative;
    margin: 0;
    background: #FFF;
}
div.accordion, li.catparent {
    font-weight: 600;
    color: #626262;
}
.accordion.active {
    margin-bottom: 0;
}
.entry-content ul.children {
    max-height: 0;
    overflow: hidden;
    transition: 0.3s ease-out;
    padding: 0;
}
div.accordion:hover, ul.accordionCat li a:hover{
  background-color: #efefef;
  text-decoration: none;
}
div.accordion:after {
    color: #6bb6ff;
    position: absolute;
    right: 15px;
    top: 50%;
    transform: translateY(-53%);
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    font-size: 1em;
    content: "\f055";
}
div.accordion.active:after {
    content: "\f056";
}

span.postCount {
    background: #ebfcfe;
    color: #005fa0;
    display: inline-block;
    overflow: hidden;
    min-width: 24px;
    height: 24px;
    margin-left: 7px;
    border-radius: 3px;
    font-size: 12px;
    font-weight: normal;
    text-align: center;
    vertical-align: -5px;
    line-height: 24px;
}
ul.children li a:before {
    color: silver;
    content: "\f105";
    padding-left: 5px;
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    font-size: 0.95em;
    padding-right: 5px;
}
ul.accordionCat li ul.children li a {
    font-size: 0.95rem;
}

JavaScript

var acc = document.getElementsByClassName('accordion');
var i;
for ( i = 0; i < acc.length; i++ ){
    acc[i].onclick = function() {
    this.classList.toggle('active');
    var panel = this.nextElementSibling;
    if ( panel.style.maxHeight ){
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + 'px';
    }
  }
}

ざっくりとしたコードの解説

先生

ざっくりながらコードの解説です。CSSは、当サイトに合わせて作っているので割愛します。

PHP:$childcatnum で条件分岐

PHPでは、条件分岐で出力内容を分けています。

この条件分岐を行う為に、まず$childcatnum = count(get_term_children($category->cat_ID,'category')); で、記事数をカウントする変数を作ります。そして、作った $childcatnum で「子カテゴリが0個の場合」と「子カテゴリが1個以上」の2つで、条件分岐をかけています。

PHP

<?php if($childcatnum > 0) : //アコーディオンの親 ?>
<!-- 子カテゴリがある親とその子の出力内容 -->
<?php elseif ($childcatnum == 0 && $category->category_parent == 0) : //親のみの場合 ?>
<!-- 親だけだった場合の出力内容 -->
<?php endif ;?>
<!-- ここまで条件分岐 -->

この条件分岐で、「子カテゴリがある場合、その親はdivタグでアコーディオン」「子カテゴリがない場合、その親はaタグでリンク」と出力内容を変えています。

かかかず
かかかず

これ以外にも、いろんな変数を作っていますがここの条件分岐が仕組みの大きなところです。

JavaScript:.classList.toggle() でアコーディオン

アコーディオンは、JavaScriptの.classList.toggle() を使っています。

詳細は以下の記事にまとめていますが、この.classList.toggle()は、タグが持つclassをON・OFFで切り替える個人的にもよく使うメソッドで、色々応用がきくので覚えておくと便利です。

Q&A JavaScriptの.classList.toggle()でよくある質問のアコーディオン
かかかず
かかかず

この.classList.toggle()は、非常に便利なメソッドなので参考にしてみてください。

さいごに

意外に苦戦したのは、get_categories() に入れる引数のところで、なかなか以下を入れてもハマらずに四苦八苦しました。

  • pad_counts ... 子カテゴリーを含めて、リンクまたは投稿の数を計算するパラメータ
  • parent ... カテゴリー ID で指定されたカテゴリーの直接の子カテゴリーのみを取得するパラメータ

結局のところ、'pad_counts''parent' の併用は、コンフリクトが起きるので両方同時に使えないことが分かり、今回のような「記事数あり・なし」で冒頭箇所の記述内容が多少違う内容になっています。

かかかず
かかかず

記事数が取得できない・・・。と、苦戦しました。

公式カテゴリのデータを取得するパラメータは種類がたくさんあるので、使いこなせるように公式の関数リファレンスを読むのがオススメです。

是非、参考にしてみてください。

参考サイト

参考関数リファレンス/get categoriesWordPress Codex 日本語版
カテゴリーのイラスト

同じカテゴリの記事一覧

ボタンの影