年ベースの月別アーカイブの表示と取得をするコードを作った
現在受けている案件で、月別アーカイブの上に年を表示する必要があった。
要は以下のような形で、WordPressで年ベースの月別アーカイブのタグを表示・取得をしなければならないといったこと。
2018 →2018.01 →2018.02 2017 →2017.01 →2017.02
コピペコードも探してみたが、なかなかそういったものでピンとくるものはなかった。
そこで、どうせだし自分の使いやすいようにやっちまおうということで、作ってみた。
作成したコード
今回は、getarchives_whereのフィルターフックに対して年での範囲指定を任意に行わなければならないためクラスを使用して作成。
functions.phpに組み込んでもいいけど、手続き式とオブジェクト指向の混在を避けるため、できれば別ファイルに分けたほうがいいかも。
Class YearlyBase_Monthly_Archives { private $_year; function __construct() { $this->_year = ''; } public function monthly_on_year( $_args = false, $_year = '' ) { if ( ! $_args || ! is_array( $_args ) ) $_args = array( 'type' => 'monthly', 'echo' => 1, ); $_args['type'] = 'monthly'; if ( ! isset( $_args['echo'] ) ) $_args['echo'] = 1; if ( '' == $_year ) $_year = '<li><a href="#">1970</a></li>'; $_year = $this->convert_wp_get_archives_year( $_year ); $this->set_year( $_year ); add_filter( 'getarchives_where', array( $this, 'durationize' ), 10, 2 ); $_monthly = wp_get_archives( $_args ); remove_filter( 'getarchives_where', array( $this, 'durationize' ) ); if ( 0 === $_args['echo'] ) return $_monthly; } public function monthly_on_year_with_title( $_args = false, $_year = '' ) { $_echo = 1; if ( ! $_args || ! is_array( $_args ) ) $_args = array( 'type' => 'monthly', 'echo' => 0, ); if ( ! isset( $_args['echo'] ) ) $_args['echo'] = 1; $_echo = $_args['echo']; $_args['type'] = 'monthly'; $_args['echo'] = 0; $_year = $this->convert_wp_get_archives_year( $_year ); $this->set_year( $_year ); add_filter( 'getarchives_where', array( $this, 'durationize' ), 10, 2 ); $_yearly = wp_get_archives( array_merge( $_args, array( 'type' => 'yearly' ) ) ); $_yearly = preg_replace( '~<li>|<li.+?>|</li>~', '', $_yearly ); remove_filter( 'getarchives_where', array( $this, 'durationize' ) ); $_monthly = '<ul>' . $this->monthly_on_year( $_args, $_year ) . '</ul>'; if ( 0 == $_echo ) return '<ul><li>' . $_yearly . $_monthly . '</li></ul>'; elseif ( 1 == $_echo ) echo '<ul><li>' . $_yearly . $_monthly . '</li></ul>'; } public function explode_of_year( $_args = false ) { if ( ! $_args || ! is_array( $_args ) ) $_args = array(); $_args['type'] = 'yearly'; $_args['echo'] = 0; $_yearly = wp_get_archives( $_args ); $_yearly = preg_replace( '~\r|\n|\r\n|\t~', '', $_yearly ); $_yearly = str_replace( '<li', '~<li', $_yearly ); $_yearly = array_values( array_filter( explode( '~', $_yearly ) ) ); return $_yearly; } private function set_year( $_year = '' ) { $this->_year = $_year; } private function convert_wp_get_archives_year( $_year = '' ) { return intval( preg_replace( '~<.+?>~', '', $_year ) ); } public function durationize( $_where, $_r ) { $_where .= ' AND post_date >= \'' . esc_sql( $this->_year ) . '-01-01 00:00:00\' AND post_date <= \'' . esc_sql( $this->_year ) . '-12-31 23:59:59\''; return $_where; } }
その後、以下のような形でアーカイブを表示したいところにコードを記載する。
$archives_class = new YearlyBase_Monthly_Archives(); $yearlies = $archives_class->explode_of_year( apply_filters( 'widget_archives_args', null, $instance ) ); foreach ( $yearlies as $yearly ) { // 表示 $archives_class->monthly_on_year_with_title( array( 'echo' => 1 ), $yearly ); // 取得 $monthly_on_year_with_title = $archives_class->monthly_on_year_with_title( array(), $yearly ); }
ある年の月別アーカイブを出したい場合は、このような形で記載。以下の例では2018年の月別アーカイブを出してくる。
$archives_class = new YearlyBase_Monthly_Archives(); // 年のアーカイブのタイトル付き $archives_class->monthly_on_year_with_title( array( 'echo' => 1 ), 2018 ); // 月別アーカイブのみ $archives_class->monthly_on_year( array( 'echo' => 1 ), 2018 );
アーカイブウィジェットに適用させたい場合は、WP_Widget_Archivesを継承して適当にクラスを作成、大本のWP_Widget_Archivesクラスのwidgetメソッドをコピペ。
そして、widgetメソッドでwp_get_archives()を呼んでいるあたりをこんな感じで書き換える。
//wp_get_archives( apply_filters( 'widget_archives_args', array( // 'type' => 'monthly', // 'show_post_count' => $c //), $instance ) ); $archives_class = new YearlyBase_Monthly_Archives(); $yearlies = $archives_class->explode_of_year( apply_filters( 'widget_archives_args', array( 'show_post_count' => $c, ), $instance ) ); foreach ( $yearlies as $yearly ) { $archives_class->monthly_on_year_with_title( apply_filters( 'widget_archives_args', array( 'show_post_count' => $c, ), $instance ), $yearly ); }
コードの使用方法としてはこんなところかな。
で、コードを読んでみると分かる通り、クラス中のメソッドにある$_argsの部分はアーカイブを表示・取得するテンプレート関数のwp_get_archives()の引数をおおよそ持ってきている。
‘type’については用途が決まっているため、各メソッドごとで固定化している。別に問題はないはず。
YearlyBase_Monthly_Archivesクラスとして作成したこのコードの、各メソッドの説明は以下のような感じ。
monthly_on_yearメソッド
年内の月別アーカイブ全てを表示するメソッド。
第二引数に年(例:2018等)を指定することで任意の年の月別アーカイブを表示可能。
publicメソッドなのでオブジェクトインスタンスから直接参照できるよ!
monthly_on_year_with_titleメソッド
年内の月別アーカイブ全てを表示するメソッド。
monthly_on_yearメソッドとの違いは年別アーカイブをリストヘッドとして出してくること。
同じくpublicメソッドなのでオブジェクトインスタンスから直接参照可。
explode_of_yearメソッド
年別アーカイブのリストタグを分解するためのメソッド。
年別アーカイブ毎のリストタグをひと年ごとに配列にして返す。
privateメソッドなのでオブジェクトインスタンスからの直接参照は不可。
(publicに書き換えて使用することもできんこともあらへんけど非推奨。)
set_yearメソッド
getarchives_whereのフィルターフックで期間指定を動的に行えるようにするためのメソッド。
クラス内のprivate変数の$_yearを書き換えるために使用。
privateメソッドなので(略)
convert_wp_get_archives_yearメソッド
ひと年ごとの年別アーカイブのタグを年を表す数字に変換するメソッド。
テンプレート関数であるwp_get_archives()で「’type’=>’yearly’を指定した際に、年の数字しかリストタグ内に表示しない」という仕様だかバグだかをわからんけどその穴を突っついて、数値型の年に変換する。
privateメソッド。
durationizeメソッド
年の期間指定用、つまりgetarchives_whereのフィルターフック実行用のメソッド。
本当はprivateでやりたかったけど、メソッドをフィルターフックする場合はpublicにしておかなければならないため、やむなくこの形に(´・ω・`)
たったこれだけのことをするのと、コードの公開をするためにえらい手間をかけた気がする。
まぁ、仕組みがぱっと思いついて、すぐにそれを形にできるところ、やっぱりWordPressの中身のコードって良い意味でも悪い意味でもすごいと思う。