【wordpress】カスタム投稿タイプの月別アーカイブを出す

2015.1.17 Wordpress

カスタム投稿タイプで更新した記事も、月別のアーカイブを表示したい時があると思います。

これが簡単なようで意外とハマリました。ちなみに、「『アーカイブページ』内の記事」の表示のことではありません。今回は2通りの方法をご紹介いたします。

function.phpに追記する方法

だいたいこれにぶち当たると思います。

至極簡単で、functions.phpに以下のコードを追記します。

//投稿タイプ保管用
$my_archives_post_type = 'post';

//Where書き換え
add_filter( 'getarchives_where', 'my_getarchives_where', 10, 2 );
function my_getarchives_where( $where, $r ) {
global $my_archives_post_type;
if ( !array_key_exists( 'post_type', $r ) ) {
return $where;
}

$target = $r['post_type'];
$new_where = str_replace( "'post'", "'{$target}'", $where );
$my_archives_post_type = $target;
return $new_where;
}

//出力URL書き換え(末尾にpost_typeくっつけるだけ)
add_filter( 'get_archives_link', 'my_get_archives_link' );
function my_get_archives_link( $link_html ) {
global $my_archives_post_type;
if ( '' != $my_archives_post_type ) {
$link_html = preg_replace( "/\<a\shref\=\'([^\"]+)\'\>/", "<a href='$1&post_type={$my_archives_post_type}'>", $link_html );
}
return $link_html;
}

 なにをやっているか?

add_filter(‘getarchives_where’ , ” );

関数リファレンス/add filter – WordPress Codex 日本語版

フィルターは、様々な種類のテキストがデータベースまたはブラウザ画面に送信される前に WordPress が変更を行うフックです。プラグインは、フィルター API を利用して、指定したテキストをその時点で変更する PHP 関数を実行できます。フィルターフックの一覧は プラグイン_API/フィルターフック一覧 を参照してください。

add_filter( 'getarchives_where', 'my_getarchives_where', 10, 2 );

wp_get_archivesなどでアーカイブを取得するために、内部的に日付の検索を行う(という解釈でいいのか…)のですが、このフィルターを利用することで、アーカイブの取得条件を変更できます。

ここで実行される関数my_getarchives_where()は、「$where」と「$r」を受け取っていますが、これはgetarchives_whereをフックするときに渡される変数で、「$r」には、wp_get_archives()が実行されるときのパラメータが展開されたものが入っています。

キーワード 省略時の値 意味
type ‘monthly’ アーカイブ種別を指定(’daily’、’weekly’、’monthly’、’yearly’、’postbypost’、’alpha’など)
limit 表示件数(正数)
format ‘html’ 表示形式を指定(’html’、’link’、’option’など)
before リンク名の前に連結する文字列
after リンク名の後に連結する文字列
show_post_count false 投稿件数を表示する場合はtrue、表示しない場合はfalse
echo 1 表示する場合は1、文字列として取得する場合は0

「$where」には、デフォルトで「WHERE post_type = ‘post’ AND post_status = ‘publish’」が格納されています。これはデータベースの抽出条件ですね。

wp_get_archives:WordPress私的マニュアル

!array_key_exists()

bool array_key_exists ( mixed $key , array $array )

$keyが、その後の引数である$arrayに含まれているかどうかを判断しています。

今回の場合はifの中で直前に「!」がついているので、含まれていない場合に{}内の処理をするわけですが、これはつまり、渡ってきた「$r」のパラメータの中に「post_type」が無ければ、 $whereをデフォルトのまま返して終わるということです。

PHP: array_key_exists – Manual

str_replace( “‘post'”, “‘{$target}'”, $where );

その下で、変数「$target」に、そのpost_typeを代入しています。

直後、str_replace()で$whereの中の’post’を「$target」に置換して「$new_where」に保存して、返しています。

mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )

 PHP: str_replace – Manual

add_filter(‘get_archives_link’ , ” );

リンクテキストを返す直前にget_archives_linkフィルターが実行される。$link_htmlには、生成されたリンクテキストの内容が格納されている。

リンクを出力するタイミングで、書き換え用の関数「my_get_archives_link()」を実行します。ここで受け取る値は上記のとおり、生成されたリンクテキスト。つまり「アーカイブリンク」です。

外で定義した$my_archives_post_typeをglobal変数として定義します。
それが空でなければif(){~}内の処理を実行します。

preg_replace( “/\<a\shref\=\'([^\”]+)\’\>/”, ~ );

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

$subjectを$replacementで入れ替えるために$patternで検索します。

今回の場合は$link_htmlから、「\<a\shref\=\'([^\”]+)\’\>」という条件で検索します。
ようするに「<a href=””>」のことなのですが、「[^\”]+」がキモです。これは「『”』以外の文字が1個以上続いている」箇所を表しています。

[^\”]+」に該当した箇所は「<a href=’$1&post_type={$my_archives_post_type}’>」の中の「$1」に挿入されます。

これで置換完了です。直後、$link_htmlを返します。

「wp_get_archive()」でpost_typeを指定する

本来そのような指定の仕方では何の意味もないのですが、上記のようにコードを書くことで「post_type」が機能します。

wp_get_archives('type=monthly&post_type=カスタム投稿名');

 テンプレートタグ/wp get archives – WordPress Codex 日本語版

これで、通常はデフォルトの投稿しか出力しない「wp_get_archive」でカスタム投稿タイプを出力できるようになりました!

月ごとのアーカイブへのURLが以下のように出力されます。

http://ドメイン/?m=201501&post_type=post //(通常)
http://ドメイン/?m=201501&post_type=カスタム投稿タイプ名 //(カスタム投稿)

…ですが、注意事項として

  • 以降のwp_get_archivesは全て書き換わってしまう
  • 「パーマリンク設定」が「デフォルト」以外だと機能しない。

と、すこし不便です…

「Custom Post Type Permalinks」を使う

「Custom Post Type Permalinks」ダウンロード

これをインストールして有効にすることで、上記のように「post_type」の指定が機能します。
こちらを使ったほうが圧倒的に良い印象です。

[設定]>[パーマリンク設定]から、カスタム投稿ごとに細かいパラメータの付き方も指定できるようになります。

customposttypepermalink

パーマリンク設定で「投稿名」を指定している状態です。

今までと同様に記事単体のページのURLですので、「/%postname%/」を消したURLがアーカイブページとなります。

あとは「archive-投稿タイプ名.php」でテンプレートファイルを作って、おなじみの

if(have_posts()){
 while(have_posts()){
  the_post();

~~~ループで表示したい項目の処理
 }
}

で問題ないかと思います。

 

以上、2通りのやり方をご紹介いたしました。

ここは「Custom Post Type Permalinks」に軍配が上がったのではないでしょうか?

 

でわ!

Profile

東京でWebデザイナー・コーダーとして、フロントエンド的なことからデザイン思考的なことを考えたりして、ごにょごにょと活動中。(ポートフォリオ)Webクリエイターでは珍しい(?) HIPHOP, R&B好き。休日はよくカフェや漫画喫茶に出向いたりパン屋に行ったりコーヒ豆買いに行ったり、主に散歩しています。。デザインのトレンドやデザイン思考、HTML、CSSからSASS、Javascript、Wordpress構築などコーディングのTIPSなどをブログにアップしていきます。その他のことはtwitter( @satohmsys )まで。コーヒー友達募集中。