技術情報

WordPressのアーカイブをカテゴリを指定して表示する方法

2016.07.19


WordPressでコーポレートサイトを作っていると、任意カテゴリ以下の記事のみの
アーカイブリンクを表示したくなります。
アーカイブリンクというのは、wp_get_archivs() で表示される、年毎、もしくは月事のリンクです。

例えば以下のような感じでカテゴリ分けをした場合、「ブログ」以下のアーカイブを表示したくなるとおもいます。

  • ブログ
    • 社長日記
    • スタッフ日記
  • お知らせ

実は表示に関しては、何年何月の任意のカテゴリーの一覧を表示、というのは公式にサポートされているようで、例えば 2016年7月の カテゴリーID 5の一覧を表示したい場合、

http://example.com/?m=201607&cat=5

等と指定するとその通りに表示れます。パーマリンクを表示するようにしている場合には、

http://example.com/2016/07/?cat=5

となります。 カテゴリの部分がID番号なのが気になりますが、これはこれで良いとして
サイドバーに各月もしくは年のリンクを表示したいですよね。

以前はこんな時は、

WordPress plugin Archives for a category

というプラグインをつかっていました。ただしこのプラグインですが、もうメンテナンスしてないので、使わない方がよいとこのページの冒頭に注意があります。ほかの解決方法として、post_typeで分けるという手もあります。上記の場合にはブログは通常の投稿(post)タイプにして、別途 ニュースをpost_typeとして定義すれば解決します。

今回は年度毎と月事を合わせた、以下のような変則的な表示をしたいので、ちょっと自作する事にしました。

  • 20016年
    • 5月(1)
    • 6月(2)
  • 20015年
    • 7月(5)

以下をfunctions.phpに入れて、 wp_archive_year_month_by_category(カテゴリーID); でサイドバーのテンプレートで呼び出せばOKです。

function wp_archive_year_month_by_category($cat_id) {
    global $wpdb;
    $colums_ids_arr = get_term_children($cat_id, 'category');
    $colums_ids_arr[] = $cat_id;
    $column_terms = implode( ',', $colums_ids_arr);

    $results_arr2 = $wpdb->get_results("SELECT DISTINCT ID 
    FROM $wpdb->posts INNER JOIN wp_term_relationships 
    ON (wp_posts.ID = wp_term_relationships.object_id) 
    WHERE post_status = 'publish' and post_date <= now()
    AND post_type = 'post' AND ( wp_term_relationships.term_taxonomy_id IN ($column_terms))
    ORDER BY post_date DESC");
    $pids = implode( ',', array_map( function($post) { return intval($post->ID); }, 
                        $results_arr2));
    $year_prev = null;
    $months = $wpdb->get_results("SELECT DISTINCT MONTH( post_date ) AS month ,
                                    YEAR( post_date ) AS year,
                                    COUNT( id ) as post_count FROM $wpdb->posts WHERE post_status = 'publish' and post_date <= now()
                                    AND post_type = 'post' AND ( wp_posts.ID IN ($pids) )
                                    GROUP BY month , year
                                    ORDER BY post_date DESC");
    foreach($months as $month) :
        $year_current = $month->year;
    if ($year_current != $year_prev){
        if ($year_prev != null){?>
            </ul>
        <?php } ?>
        <li><span><?php echo $month->year; ?>年</span>
    <ul>
    <?php } ?>
    <li>
    <a href="<?php bloginfo('url') ?>/<?php echo $month->year; ?>/<?php echo date("m", mktime(0, 0, 0, $month->month, 1, $month->year)) ?>?cat=<?php echo $cat_id; ?>">
     <?php echo date("n", mktime(0, 0, 0, $month->month, 1, $month->year)) ?>月(<?php echo $month->post_count; ?>)
        </a>
    </li>
    <?php $year_prev = $year_current;
    endforeach; ?>
</li>
<?php
}