[WordPress Core] Rewrite API を利用してカテゴリ毎の年次アーカイブのインデックスページを作成する

WordPress が用意していない独自の URL にアクセスしたときに、必要なアーカイブインデックスを表示するように設定します。

WordPress のリクエスト処理の流れ

リクエストパラメータに基づいて処理を行い、その結果を返します。

  • http://vccw.local/index.php?p=123 のようにリクエストパラメータをクエリ文字列として受け取る。
  • リクエストパラメータは $wp->query_vars に格納される($wp はグローバル変数)。

URLのリライトとルールの追加

設定>パーマリンク設定 でリライト機能を有効にすると、http://vccw.local/2017/12/04/sample-post/ のようにURLからリクエストパラメータを取得することができます。
また add_rewrite_rule() を利用すると、追加でリライトルールを指定できます。

リライトルールは、下記のプラグインなどで確認する事ができます。

Rewrite API については、こちらが大変参考になりました。

下準備

Twenty-Seventeen の子テーマを用意します。
細かい手順は省略します。

/wp-content/themes/twentyseventeen-child
├── functions.php
└── style.css

リライトルールの追加

WP_Query を参考にリクエストパラメータを組み立てます。
yearcategory_name にそれぞれの値を渡します。

さらにページネーション用にルールを追加します。
paged を渡します。

functions.php
<?php
namespace Foo\Theme;
if ( WP_DEBUG ) {
    add_action( 'init', 'flush_rewrite_rules' );
}
const CAT_BACKNUMS = 'feature|media|news';
/**
 * /<category_name>/backnumber/<year> というリクエストがあった時に、
 * 該当するカテゴリー&年別のアーカイブを表示する
 */
function add_back_number_rewrite_rule() {
    $regex_1 = '^(' . CAT_BACKNUMS . ')/backnumber/([0-9]{4})$/?';
    add_rewrite_rule(
        $regex_1,
        'index.php?year=$matches[2]&category_name=$matches[1]',
        'top'
    );
    $regex_2 = '^(' . CAT_BACKNUMS . ')/backnumber/([0-9]{4})/page/([0-9]{1,})/?';
    add_rewrite_rule(
        $regex_2,
        'index.php?year=$matches[2]&category_name=$matches[1]&paged=$matches[3]',
        'top'
    );
}
add_action( 'init', 'Foo\Theme\add_back_number_rewrite_rule' );

リライトルールは、先に書いた定義が優先されます。
またリライトルールの変更は、設定>パーマリンク設定>変更を保存 を実行することで反映されます。

補足

namespace

debug mode で開発しているときのみ flush_rewrite_rules を利用して、リライトルールの変更を自動で反映させます。

add_action('init', 'flush_rewrite_rules');

memo.

タイトルの調整

カテゴリー&年別のアーカイブのタイトルを整えます。

但し wp_title は使われていないので、Hook を document_title_parts に変更します。

functions.php
/**
 * カテゴリー&年別のアーカイブのタイトルを整える
 */
function extend_year_wp_title( $title ) {
    if ( is_year() && ! empty( get_query_var( 'category_name' ) ) ) {
        $cat_year       = get_query_var( 'year' );
        $title['title'] = $title['title'] . ' : ' . $cat_year;
    }
    return $title;
}
add_filter( 'document_title_parts', 'Foo\Theme\extend_year_wp_title', 100, 1 );

その他

その他、関連するトピックス。

変数を追加する

&cat_slug=$matches[1] などで渡された変数を追加する場合、下記のように query_vars へ登録する。

functions.php
/**
 * $wp_query->query_vars にパラメータを追加する
 */
function add_back_number_to_qvar( $vars ) {
    array_push( $vars, 'cat_slug' );
    return $vars;
}
add_filter( 'query_vars', 'Foo\Theme\add_back_number_to_qvar' );

メインクエリを変更する

テンプレートを用意して new WP_Query するのではなく、pre_get_posts を利用する。

functions.php
/**
 * メインクエリの内容を変更する
 */
function modify_main_query( $query ) {
    /* 管理画面 or メインクエリでない場合は何もしない */
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    /* 年別アーカイブページの場合 */
    if ( $query->is_year() ) {
        // 前述の通り、本来このようにする必要はない
        $cat_slug = $query->query_vars['cat_slug'];
        $query->set( 'category_name', $cat_slug );
        return;
    }
    /* ホームページの場合 */
    if ( $query->is_home() ) {
        $query->set( 'posts_per_page', '3' );
        return;
    }
}
add_action( 'pre_get_posts', 'Foo\Theme\modify_main_query' );

補遺