WordPressの月別アーカイブを年単位で開閉させる

長くなりすぎた月別アーカイブリンクを、年ごとにjQueryでアコーディオン開閉させたいなと思って書きました。いろんなやり方あるとは思うのですが、ひとつの方法としてシェアします。
ご注意
テーマを変更したので現在このブログでは実装しておりません。
月別アーカイブ長すぎ問題
このブログはPCとスマホで別テーマを作ってあります。PC版のアーカイブは、Compact Archivesというプラグインを使って
フッターにこんな感じで表示してました。
で、スマホ版は数年前にこのあたりの記事で書いたように、
<ul><?php wp_get_archives('show_post_count=1'); ?></ul>
こんなふうによくある形で書いてすっかり放置してしまい、先日なんとなくスマホのメニューを見ていて
なんとなくタップしてみたら
ウワァァァァァアァアアアァァ!!! (>’A`)>
あんまりひどかったので何とかしたいと思って書きました。勢いでPHPまで書いて、できたできたー! って喜んだものの、それから調べてみたら同じような結果になるプラグインや方法を提示している記事もたくさんありまして、今更感なのですが…。
でもせっかく書いたし、コードは人それぞれだし! と思って記事にしておきます。
結果
現在の月からさかのぼって、一番古い投稿のある月までのアーカイブリンクを出力します。最初の年はデフォルトで開き、それより前の年はたたまれます。他の年を開くと、連動して開いていたところが閉じます。
スマホ向けで作ったのでアイコンやリストマークはCSSで出来ています。PCはモダンブラウザ推奨ということで。
実装
目指すHTML
こういう形のHTMLを出力するためのPHPを書きます。
<ul class="accordion"> <li> <p><span class="acv_open"></span>今年 (n)</p> <ul> <li><a href="http://sample.com/YYYY/MM">今年今月</a> (n)</li> <li><a href="http://sample.com/YYYY/MM">YYYY年MM月</a> (n)</li> <!-- 略 --> <li><a href="http://sample.com/YYYY/MM">YYYY年1月</a> (n)</li> </ul> </li> <li> <p><span></span>YYYY年 (n)</p> <ul class="hide"> <li><a href="http://sample.com/YYYY/MM">YYYY年12月</a> (n)</li> <li><a href="http://sample.com/YYYY/MM">YYYY年MM月</a> (n)</li> <li><a href="http://sample.com/YYYY/MM">YYYY年MM月</a> (n)</li> <!-- 略 --> <li><a href="http://sample.com/YYYY/MM">YYYY年1月</a> (n)</li> </ul> </li> <!-- 一番古い投稿日まで続く --> </ul>
span部分がプラスのアイコンになるところです。最初の年は開いておくので、3行目にacv_openというクラスをつけて、アイコンを変えたりjQueryで開く処理に使います。
次の年からは閉じておくためにulにhideというクラスをつけて、あとは一番古い投稿日がある年まで続きます。
functions.php
それではここから実際に書くコード。
指定した年の投稿数、指定した年月の投稿数、それと一番古い記事の投稿年を取得する関数を書きます。
// 指定年の投稿数を取得
function get_year_archives_num( $year ) {
global $wpdb;
$cnt = $wpdb->get_var(
"SELECT count(*) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type = 'post' AND DATE_FORMAT(post_date, '%Y') = '".$year."';"
);
return $cnt;
}
// 指定年月の投稿数を取得
function get_month_archives_num( $year, $month ) {
global $wpdb;
$cnt = $wpdb->get_var(
"SELECT count(*) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type = 'post' AND DATE_FORMAT(post_date, '%Y%m') = '".$year.str_pad($month, 2, 0, STR_PAD_LEFT)."';"
);
return $cnt;
}
// 一番古い記事の年を取得
function get_oldest_year() {
global $wpdb;
$oldest_date = $wpdb->get_var(
"SELECT post_date FROM $wpdb->posts WHERE post_status = 'publish' AND post_type = 'post' ORDER BY post_date ASC LIMIT 1;"
);
return idate('Y', strtotime($oldest_date) ); //投稿日の年だけ数値で取得
}
WPのデータベースにSQLを投げて投稿数とかをもらってきます。
このへんは、昔自分で書いた記事が役に立ちました。まとめとくもんだと思った!
任意のテンプレートファイル
上で書いた関数を使って、アーカイブリストを出したい場所に以下を書きます。
<ul class="accordion">
<?php
$y_flg = true; //年の切替フラグ
$f_flg = true; //初回フラグ
$year = idate('Y'); //本日の年
$month = idate('m'); //本日の月
$oldest_year = get_oldest_year(); //一番古い投稿日の年
while ( $year >= $oldest_year ) { //一番古い投稿年を指定年が下回るまでループ
//年見出し出力
if ( $y_flg == true ){ //年切替フラグが立っていたら
$year_archives_num = get_year_archives_num( $year ); //指定年の投稿数を取得
if ( $year_archives_num > 0 ){ //指定年の投稿があったら閉じた年見出しを出力
if ( $f_flg == true ){ //初回は閉じタグ不要&開いておく
?>
<li>
<p><span class="acv_open"></span><?php echo $year; ?>年 (<?php echo $year_archives_num; ?>)</p>
<ul>
<?php
$f_flg = false; //1度通ったらフラグを倒しておく
} else { //2回目以降は閉じタグ必要&閉めておく
?>
</ul>
</li>
<li>
<p><span></span><?php echo $year; ?>年 (<?php echo $year_archives_num; ?>)</p>
<ul class="hide">
<?php
}
$y_flg = false; //年見出しが出力されたら年切替フラグを倒しておく
} else { //該当の年に投稿がなかった場合
$year--; //1年前へ
$month = 12; //12月へ
}
}
//月アーカイブ出力
if ( $y_flg == false ){ //年切替フラグが倒れていたら
$month_archives_num = get_month_archives_num($year, $month); //指定年月の投稿数を取得
if ( $month_archives_num > 0 ) { //指定年月の投稿があったらアーカイブリンクを出力
?>
<li><a href="<?php echo home_url('/').$year."/".str_pad($month, 2, 0, STR_PAD_LEFT); ?>"><?php echo $year."年".$month."月"; ?></a> (<?php echo $month_archives_num; ?>)</li>
<?php
}
$month--; //1月前へ
if ( $month < 1 ){ //0月になってしまったら
$year--; //1年前へ
$month = 12; //12月へ
$y_flg = true; //年切替フラグを立てる
}
}
}
?>
</ul>
</li>
</ul>
16行と25行が「YYYY年 (n)」を出力しているところで、40行が「YYYY年MM月 (n)」のリンクを出力しているところなので、表記を変えたい方はここを変更してください。
CSS
ul.accordion ul{ /* アコーディオン部 */
margin: 5px 0 30px 15px;
}
ul.accordion ul.hide{ /* アコーディオン非表示 */
display: none;
}
ul.accordion li{ /* リセット */
list-style: none;
background: none;
padding: 0;
}
ul.accordion li p{ /* リセット */
margin: 0;
}
ul.accordion li p span{ /* アイコン背景 */
display: inline-block;
width: 15px;
height: 15px;
position: relative;
background: #09c;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
margin-right: 5px;
vertical-align: -2px;
}
ul.accordion li p span:before{ /* アイコン横棒 */
content:'';
height: 1px;
width: 9px;
display: block;
background: #fff;
position: absolute;
top: 7px;
left: 3px;
}
ul.accordion li p span:after{ /* アイコン縦棒(閉じてるとき) */
content: '';
height: 9px;
width: 1px;
display: block;
background: #fff;
position: absolute;
top: 3px;
left: 7px;
}
ul.accordion li p span.acv_open:after{ /* アイコン縦棒なし(開いてるとき) */
height: 0;
width: 0;
}
ul.accordion ul li{ /* アーカイブリスト */
margin-left: 15px;
position: relative;
}
ul.accordion ul li::after{ /* アーカイブリストマーク */
display: block;
content: '';
position: absolute;
top: .2em;
left: -1em;
width: 6px;
height: 6px;
border-right: 1px solid #666;
border-bottom: 1px solid #666;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
色を変えたい場合はハイライト部を変更してください。
リセット部分とか、いろんなところのpx数なんかは環境によって異なると思いますので適宜調整してください。
CSSはこちらを参考にさせていただいてます。Naoyaさんいつもありがとうございますー!
jQuery
<script type="text/javascript">
jQuery(function($) {
$('.accordion p').click(function(){
if($(this).next('ul').is(':visible')) { //既に開いている場所なら
$(this).next('ul').slideUp(300); //閉じる
$(this).children('span').removeClass('acv_open'); //.acv_openを削除
} else { //閉じている場所なら
$('.accordion ul').slideUp(); //全部閉じる
$('.accordion').find('span').removeClass('acv_open'); //.acv_open全削除
$(this).next('ul').slideDown(300); //開く
$(this).children('span').addClass('acv_open'); //.acv_open付加
}
});
});
</script>
動きは、こんな感じ。jQueryの読み込みは別途行ってくださいね。
関連記事&参考はこちらです! かちびとさんには何度お世話になっていることか!
あとがき
と、いう感じで実装しました。もっと早く気づけばよかったと反省です。このPHPを書いてるうちに、あっこれPCテーマの月別アーカイブもプラグイン外して自分で書けちゃうなと思って、ついでにそれもやっちゃったので、次はそのことについても書こうかなと思ってます。
書きました!





4件のコメント
ありがとうございます。
これで迷っておりました。
カスタムフィールドの日付でも同じことが可能なのでしょうか?
よっしーさん、コメントありがとうございます。
カスタム投稿タイプの公開日を使って、ということなら可能だとは思いますが、関数のSELECT文や出力のリンクURLをカスタム投稿に適応したものに書き換えなきゃいけないですね。カスタム投稿タイプの月別アーカイブページを作るのにもテコ入れが必要っぽいので、この記事の内容とは別の書き方になりそうです。
随分過去の記事でしたが、とても参考になりました。
カテゴリーで指定してこちらのアーカイブを絞り込む事は可能ですか?
ワードプレスの投稿でカテゴリー分け(お知らせとブログ)をして、レイアウトも変えているのですがブログの方だけ月間のアーカイブを付けています。こちらの方法では、すべての投稿の記事アーカイブが含まれてしまうのでカテゴリーで絞りこんだ記事アーカイブを表示できればと思いました。
ひなさん、コメントありがとうございます。
調べてみたら実装できそうだったので、新しい記事として書いてみました。ご参照ください。
コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)
YouTubeでQ&Aコンテンツを企画しています
運営しているYouTubeチャンネルで、ご相談やご質問を募集しています。動画のコメントやお問い合わせページからお気軽にご相談をお寄せください。