カスタム投稿タイプのタクソノミーの一覧ページが 404 になる:URL が添付ファイルのリライトルールとぶつかる

広告WordPress・PHP を学べる本

Amazonのアソシエイトとして、WordPress functions.phpは適格販売により収入を得ています。

タクソノミーの一覧ページだけが 404 になった

このブログで、目的から処理を探せる「逆引き」のカスタム投稿を作っていたときのことです。投稿タイプとタクソノミーを登録し、投稿タイプの URL を /my-reference/、タクソノミーの一覧ページの URL を /my-reference/cat/php/ のように、投稿タイプの下に置く形にしました。ところが、タクソノミーの一覧ページを開くと 404 になりました。

そこで、WordPress がこの URL をどのリライトルールで読んでいるかを調べました。記事の中の名前は例の名前(投稿タイプは my_reference、タクソノミーは my_reference_cat)にしています。

はじめに書いたコード

タクソノミーの rewrite の slug に、投稿タイプの URL の下になる my-reference/cat を入れていました。

はじめの形(タクソノミーの一覧ページが 404 になる)
function my_reference_register() {
    register_post_type(
        'my_reference',
        array(
            'public'       => true,
            'has_archive'  => true,
            'hierarchical' => false,
            'rewrite'      => array( 'slug' => 'my-reference', 'with_front' => false ),
        )
    );
    register_taxonomy(
        'my_reference_cat',
        'my_reference',
        array(
            'public'       => true,
            'hierarchical' => true,
            'rewrite'      => array( 'slug' => 'my-reference/cat', 'with_front' => false ),
        )
    );
}
add_action( 'init', 'my_reference_register' );

原因:添付ファイルのリライトルールに先に当たる

WordPress は、URL をリライトルール(URL の正規表現の一覧)に上から順に当てて、最初に当たったもので中身を決めます。階層のない投稿タイプを登録すると、その一覧には 1 件ずつのページのルールのほかに、/my-reference/{投稿}/{添付ファイル}/ の形の、添付ファイルのページのルールも入ります。

タクソノミーのリライトルールは、投稿タイプのリライトルールのあとに並ぶので、/my-reference/cat/php/ はタクソノミーのリライトルールより先に、添付ファイルのリライトルールに当たります。その結果、「cat という投稿の、php という添付ファイル」として読まれ、そんな添付ファイルはないので 404 になっていました。

リライトルールの順番を確かめる

作業環境の WordPress を読み込む検証用スクリプトを作り、例の名前の投稿タイプとタクソノミーをメモリの中だけで登録してから、$wp_rewrite->rewrite_rules() でリライトルールの一覧を作りました。rewrite_rules() は作るだけで DB には保存しないので、作業環境のパーマリンクの設定は変わりません。そのうえで、WordPress が URL を読むときと同じように、ルールの正規表現に URL を上から順に当てて、最初に当たったものを出しています。

検証用スクリプト(当てるところだけ)
global $wp_rewrite;
$rules = $wp_rewrite->rewrite_rules(); // 作るだけで、DB には保存しない

$path = 'my-reference/cat/php';
$i    = 0;
foreach ( $rules as $match => $query ) {
    $i++;
    if ( preg_match( "#^$match#", $path ) ) {
        echo $i . ' ' . $match . ' => ' . $query . PHP_EOL;
        break;
    }
}
書き方 役目
$wp_rewrite->rewrite_rules() いま登録されている投稿タイプやタクソノミーから、リライトルールの一覧を作る
preg_match( "#^$match#", $path ) WordPress が URL を読むときと同じ形で、ルールの正規表現に当てる
break 最初に当たったところで止める(WordPress も最初に当たったものを使う)

作業環境で出た結果は、次のとおりです。番号はリライトルールの一覧の中の順番です。

タクソノミーの slug 開いた URL 最初に当たったルール 読まれ方
my-reference/cat /my-reference/cat/php/ 121 番 my-reference/[^/]+/([^/]+)/?$ attachment=php(添付ファイル)
my-reference-cat /my-reference-cat/php/ 131 番 my-reference-cat/([^/]+)/?$ my_reference_cat=php(タクソノミーの一覧ページ)
どちらでも /my-reference/some-post/ 120 番 my-reference/([^/]+)(?:/([0-9]+))?/?$ my_reference=some-post(1 件のページ)

はじめの形では、タクソノミーのリライトルール(127〜131 番)は一覧の後ろのほうにあり、その前の 121 番の添付ファイルのリライトルールに先に当たっていることが分かりました。試したあと、DB に保存されているルールが変わっていないことも、スクリプトの中で前後を比べて確かめています。

直し方:タクソノミーの URL を分ける

直し方はいくつかありますが、今回はタクソノミーの slug を my-reference-cat にして、投稿タイプの URL の下から出しました。タクソノミーの一覧ページは /my-reference-cat/php/ になり、添付ファイルのリライトルールとは形がぶつからなくなります。

やり方 よいところ 気をつけること
タクソノミーの URL を分ける(今回のやり方) slug を 1 つ変えるだけで、リライトルールの順番を気にしなくてよい URL が投稿タイプの下に並ばない
タクソノミーを先に登録する /my-reference/cat/php/ の形のままにできる 登録の順番に頼るので、あとでコードを並べ替えたときに 404 に戻りやすい
add_rewrite_rule() でルールを上に足す URL の形を自由に決められる ルールを自分で書いて持ち続けることになる

タクソノミーを先に登録するやり方も、検証用スクリプトで登録の順番を入れ替えてみたところ、タクソノミーのリライトルールが添付ファイルのリライトルールより上に並び、/my-reference/cat/php/ がタクソノミーの一覧ページとして読まれました。ただ、このやり方は登録の順番に頼っているうえ、cat という slug の投稿を作ると、その下の URL がタクソノミーのリライトルールに取られてしまいます。そのため今回は、いちばん簡単な、URL を分けるやり方にしました。

/wp-content/themes/(テーマのフォルダ)/functions/reference.php(直したあと・短くしたもの)
<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

define( 'MY_REFERENCE_REWRITE_VERSION', '2' );

function my_reference_register() {
    register_post_type(
        'my_reference',
        array(
            'labels'       => array( 'name' => '逆引き' ),
            'public'       => true,
            'show_in_rest' => true,
            'has_archive'  => true,
            'hierarchical' => false,
            'rewrite'      => array( 'slug' => 'my-reference', 'with_front' => false ),
            'supports'     => array( 'title', 'editor', 'excerpt', 'revisions' ),
        )
    );
    register_taxonomy(
        'my_reference_cat',
        'my_reference',
        array(
            'labels'            => array( 'name' => '逆引きの分類' ),
            'public'            => true,
            'hierarchical'      => true,
            'show_in_rest'      => true,
            'show_admin_column' => true,
            // my-reference/cat にすると、1 件のページの下の添付ファイルの決まりとぶつかる
            'rewrite'           => array( 'slug' => 'my-reference-cat', 'with_front' => false ),
        )
    );
}
add_action( 'init', 'my_reference_register' );

// 決まりを変えたときだけ、パーマリンクを作り直す
function my_reference_maybe_flush() {
    if ( get_option( 'my_reference_rewrite_version' ) === MY_REFERENCE_REWRITE_VERSION ) {
        return;
    }
    flush_rewrite_rules( false );
    update_option( 'my_reference_rewrite_version', MY_REFERENCE_REWRITE_VERSION, false );
}
add_action( 'init', 'my_reference_maybe_flush', 20 );
書き方 役目
'slug' => 'my-reference-cat' タクソノミーの一覧ページの URL を、投稿タイプの URL の下から出す
'with_front' => false パーマリンクの設定の前の部分(/archives/ など)を付けない
MY_REFERENCE_REWRITE_VERSION リライトルールのバージョンの番号。slug を変えたら数を上げる
get_option( … ) === … 保存してある番号と同じなら、何もしないで戻る
flush_rewrite_rules( false ) ルールを作り直して DB に保存する。false で .htaccess は書き換えない
add_action( 'init', …, 20 ) 投稿タイプとタクソノミーの登録(優先度 10)が終わってから作り直す

パーマリンクの作り直しは、変えたときに 1 回だけ

投稿タイプやタクソノミーの URL を変えたときは、リライトルールを作り直さないと、新しい URL が 404 のままです。とはいえ flush_rewrite_rules() は重い処理で、ルールを DB に書き込むので、init で毎回呼ぶとページを開くたびに作り直すことになります。

そこで、option にバージョンの番号を入れておき、コードの番号と違うときだけ作り直して、番号を保存するようにしました。slug を変えたときは番号を 1 つ上げておけば、本番に入れたあとの最初の 1 回だけ作り直されます。作業環境で試すだけなら、管理画面の「設定 → パーマリンク」を開いて「変更を保存」を押すだけでも、ルールが作り直されます。

気をつけること

  • 投稿タイプの URL の下に別の URL を置くと、1 件のページや添付ファイルのリライトルールとぶつかることがあります。URL の形を決めるときに、リライトルールの順番もあわせて確かめておきます
  • slug を変えると、前の URL は 404 になります。公開したあとで変えるときは、前の URL からの転送も考えておきます
  • パーマリンクを作り直しても 404 が直らないときは、リライトルールの順番を検証用スクリプトで出してみると、どこに当たっているかが分かります

まとめ

  • 階層のない投稿タイプのリライトルールには、/{slug}/{投稿}/{添付ファイル}/ の形の添付ファイルのリライトルールが入る
  • タクソノミーの URL を投稿タイプの下に置くと、タクソノミーのリライトルールより先に添付ファイルのリライトルールに当たり、404 になることがある
  • タクソノミーの slug を分ける(my-reference-cat)のが、いちばん簡単な直し方
  • flush_rewrite_rules() は毎回呼ばず、option にバージョンの番号を入れて、変わったときに 1 回だけ呼ぶ

参考

関連機能

  1. WordPress SiteGuard プラグインにて入力を間違えて管理者アカウントがログインロック状態になった場合の解除方法

  2. 対応手順解説「サイトに重大なエラーがありました」

  3. WordPress 記事の新規作成時に公開状態の初期値を非公開にする

サイドバー

よく使うカスタマイズ

最近の記事

Profile

PAGE TOP