どもです。
WordPressにはカテゴリ一覧を出力するタグがあります。年別や月別のアーカイブを出力するタグもあります。
が、カテゴリ&月別アーカイブを出力するタグがありません。
この難題を解決してくれたのが、こちらのサイト様。
d-wood.com [wp get archives にないカテゴリ毎の月次アーカイブに対応する]
色々試してみましたが、個人的にこちらのサイト様の解答が一番使い易かった。
しかしこちらのソースをそのままfunctionsに貼り付けるだけだと、致命的な問題がありました。
子孫カテゴリが反映されないという、サイトのパターンによってはかなり致命的な問題が。
ので、子孫カテゴリ込み込み型を作ってみました。
add_filter('getarchives_where', 'custom_archives_where', 10, 2);
add_filter('getarchives_join', 'custom_archives_join', 10, 2);
function custom_archives_join($x, $r) {
global $wpdb;
$cat_ID = $r['cat'];
if (isset($cat_ID)) { return $x . " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";
} else {
return $x;
}
}
function custom_archives_where($x, $r) {
global $wpdb;
$cat_ID = $r['cat'];
if (isset($cat_ID)) {
return $x . " AND $wpdb->term_taxonomy.taxonomy = 'category' AND $wpdb->term_taxonomy.term_id IN ($cat_ID)";
} else {
$x;
}
}
function wp_get_cat_archives($opts, $cat) {
$child_cats = get_term_children($cat, 'category');
$child_cats[] = $cat;
$cat_id = implode(',', $child_cats);
$args = wp_parse_args($opts, array('echo' => '1')); // default echo is 1.
$echo = $args['echo'] != '0'; // remember the original echo flag.
$args['echo'] = 0;
$args['cat'] = $cat_id;
$tag = ($args['format'] === 'option') ? 'option' : 'li';
$archives = wp_get_archives(build_query($args));
$archs = explode('</'.$tag.'>', $archives);
$links = array();
foreach ($archs as $archive) {
$link = preg_replace("/='([^']+)'/", "='$1?cat={$cat}'", $archive);
array_push($links, $link);
}
$result = implode('</'.$tag.'>', $links);
if ($echo) {
echo $result;
} else {
return $result;
}
}
オリジナリティがあるのはハイライトの部分だけなんですねこれが。
出力タグについては、ソース元のサイト様と同じで、
wp_get_cat_archives('type=monthly&format=option&show_post_count=1',$parent_id);
でおk。
$parent_idのところに最上位カテゴリIDです。
ちなみに最上位カテゴリの取得方法は以前の記事に書きました通り。
functions.php 版なら↓で。
カスタム投稿は含まず、return される $cat_parent はカテゴリ情報一式の配列です。
function get_top_level_category(){
$cat_parent = "";
if(is_single()||is_category()){
if(is_single()){
$cat = get_the_category();
$cat = $cat[0];
$cat_id = $cat->cat_ID;
}
if(is_category()){
$cat_id = get_query_var('cat');
if( !$cat_id ){
$cat_now = get_the_category();
$cat_now = $cat_now[0];
$cat_id = $cat_now->cat_ID;
}
}
$cat_parent = get_category($cat_id);
for($i = 1; $i <= 100; $i++){ if($cat_parent -> category_parent == 0){
break;
}
$cat_parent = $cat_parent -> category_parent;
$cat_parent = get_category($cat_parent);
}
}
return $cat_parent;
}
そして一応、ハイライト部分で何やってるかの解説ですが、
- get_term_children($cat,'category') で $parent_id の子孫カテゴリIDを配列で回収(wp_get_cat_archives に入った時点で $parent_id は $cat に名前が変わります。)
- 配列に $parent_id を追加(これで子孫+最上位になる)
- implode(',', $child_cats) で配列をカンマ区切りに形状変更
これだけです。
元々、複数カテゴリに対応していてくれていたっぽいので、複数カテゴリを指定してやった感じです。
2015.10追記
通常のwp_get_archivesと併用する際、wp_get_archivesの方で記事数の取得(記事のあるなしの判断)について不具合が発生することが確認されました。
wp_get_archivesと併用する際は、wp_get_cat_archivesを作る関数をfunctions.phpに記載せず、wp_get_cat_archivesを使う直前に関数の宣言等を行うことが推奨されます。
当然ですが、直接テンプレートに記載すると冗長になるのでget_template_partなどを使って別テンプレートに書移動させた関数を読み込む推奨です。