年アーカイブで、月ごとにセクションを出力する【WordPress】

WordPressには日付アーカイブのテンプレート、date.phpがあります。
パーマリンクによって、現在表示されているのが年アーカイブか月アーカイブかを判断し、
年アーカイブであればその年の記事をあらかじめ$wp_queryに入れてくれます。
ですが、年アーカイブで「月ごとにタイトルのリストを作りたい」ということがありました。
下記のようなものです。
一見簡単にできそうなのですが、ちょっと工夫が必要でした。
HTML
HTMLは月ごとに<section>で囲む形になります。(classなどは省いています)
<div>
<section>
<h3>5月</h3>
<ul>
<li><a href=""><time datetime="2021-05-13">13日</time>日記</a></li>
<li><a href=""><time datetime="2021-05-14">14日</time>夏野菜苗の支え</a></li>
<li><a href=""><time datetime="2021-05-14">14日</time>物置の整理</a></li>
<li><a href=""><time datetime="2021-05-15">15日</time>5月の夏野菜</a></li>
</ul>
</section>
<section>
<h3>6月</h3>
〜同様
</section>
</div>月初めの記事の時は、<section>タグと<ul>タグが必要で、月終わりの記事はそれぞれの閉じタグを出力するような分岐を作って
ループでHTMLをつなげていき、最終的に出力するHTMLの文字列を作るという方法もあります。
…が、なんとなくそれではHTMLを気軽にさわりづらくなるので、別の方法を考えました。
年アーカイブを配列で取得するテンプレートタグがない
WordPressが用意しているテンプレートタグでよく使われるのが、wp_get_archives()です。
typeの値にyearly monthlyなどの値を渡すと、それに応じた日付ベースのアーカイブを作成します。
しかし、出力形態がhtmlなので、カスタマイズに限界があります。
配列で取得することができれば、foreachで回してその中でサブループを使って一月一月出力ができるのですが、
調べた結果、「投稿のある年月を配列で取得する」というテンプレートタグが、ありそうでないという結論に達しました。
…というわけで、wp_get_archives()を使って無理やり配列を作ることにしました。
コード
<?php
// 年月のHTMLを生成
$mStr = wp_get_archives('type=monthly&echo=0&order=ASC');
// HTMLの「2021年5月」の部分を文字列操作で月の部分だけ取り出して配列にする
$splitArr = explode('月',$mStr);
$arr = array_map(function($val) use($year){
if(strpos($val,(String)$year) !== false){
$s = explode('年', $val);
return $s[1];
}
},$splitArr);
$mArr = array_filter($arr);
?>
<h2><?= $year ?>年の記事一覧</h2>
<?php foreach($mArr as $m): ?>
<section>
<h3><?= $m ?>月</h3>
<ul>
<?php
$args = array(
'year' => $year,
'monthnum' => $m,
'posts_per_page' => -1,
'order' => 'ASC'
);
$query = new WP_Query($args);
if ($query->have_posts()):while ($query->have_posts()):$query->the_post();
?>
<li><a href="<?php the_permalink($post);?>"><time datetime="<?php the_time('Y-m-d');?>"><?php the_time('j日');?></time> <?php the_title();?></a></li>
<?php endwhile; endif; wp_reset_postdata(); ?>
</ul>
</section>
<?php endforeach; ?>1、wp_get_archives()で、月のHTMLリストを取得する
typeはmonthly、echoは0にして出力ではなく取得にし、orderで順序を昇順にしています。
ここで取得し$mStrに格納されたのは、
<li><a href="">2020年5月</a></li>
<li><a href="">2020年6月</a></li>
〜のようなHTMLの文字列です。(classなどいろいろ省略しています↑)
2、この文字列を使って、月の部分をとりだし配列にする。(ただし該当の年のものだけ)
explodeやarray_mapを使い、この文字列を分割して、月だけの配列にします。
wp_get_archives()では全ての年の月を取得しています。つまり、2021年のアーカイブページでも、2020年の記事があれば2020年の<li></li>も取得してきています。
そのため、該当の年に絞るために、if(strpos($val,(String)$year) !== false){ }をいれています。
3、配列をforeachでまわし、その中でサブループを作る
サブループでyearとmonthnumを指定し、<li>のループを作ります。
まとめと課題(?)
この方法だと、テンプレートの見通しがよくなり、あとからHTMLを編集しやすく簡潔であることが利点です。
ただ、12月分のクエリを作成するので、年アーカイブのメインクエリを使用し投稿記事によってhtmlを出し分ける(月の初めはsectionタグを出すなど)方法と比べると、
処理コストの面ではどうかな…という気がしなくもないです。
実際検証したわけではないので、どれほどの差があるのかはわからないですが…。
































