フロントエンドエンジニア兼ゲーマーがモノやサービスをレビュー

カスタムタクソノミーのパーマリンクで絶望的な404から抜け出した方法

カスタムタクソノミーのパーマリンクで絶望的な404から抜け出した方法

2015.04.24 一部文章を訂正しました。
2014.07.07 コードの変更と追記をしました。

※修正していない部分に関しても記事を書いた時期が古いため現在の状況と異なる部分が多々あると思われます。ご注意ください。

このブログは技術系のブログではないので、あまり小難しいことは書きません。
ですが、最近のWordpress案件でカスタム投稿タイプとカスタムタクソノミーを使って市区町村別のページを投稿していくようカスタマイズしたときにズブズブとハマッたパーマリンクの404 not found(ページが見つかりませんでした)から抜け出した設定を備忘録として残しておこうと思います。
それと、”カスタムタクソノミー”というのは長いので、ここから先は”カスタム分類”で統一して表記しますね!

スポンサーリンク

本日のメニュー

さて、今回カスタム投稿タイプで作る部分のページ構成はこのようになっています。

サイトマップ

カスタム投稿名:area
カスタム分類名:area_cat
ターム:tokyo, kanagawa, chiba, saitama, …
カスタム投稿記事スラッグ:chuo, minato, shinjuku, …

目指すパーマリンク構造

  • カスタム投稿アーカイブ:
    http://example.com/area/
  • カスタム分類アーカイブ:
    例)http://example.com/area/tokyo/
  • 個別記事ページ:
    例)http://example.com/area/tokyo/chuo/

デフォルトの状態

  • カスタム投稿アーカイブ:
    http://example.com/area/
  • カスタム分類アーカイブ:
    例)http://example.com/area_cat/tokyo/
  • 個別記事ページ:
    例)http://example.com/area/chuo/

カスタム投稿タイプを定義する

まずはカスタム投稿が使えるようにするためにfunctions.phpにコードを追加しましょう。
いきなりであれですが、最終的に404が出なかった完成形の設定コードを書いてしまいます。

add_action( 'init', 'create_post_type' );
function create_post_type() {
	register_post_type('area',
		array(
			'label' => 'エリア別',
			'description' => '',
			'public' => true,
			'show_ui' => true,
			'show_in_menu' => true,
			'capability_type' => 'post',
			'hierarchical' => false,
			'rewrite' => true,
			'query_var' => false,
			'has_archive' => true,
			'exclude_from_search' => false,
			'menu_position' => 20,
			'supports' => array(
				'title',
				'editor',
				'revisions',
				'page-attributes'
			),
			'taxonomies' => array('area_cat'),
			'labels' => array (
				'name' => 'エリア別',
				'all_items' => 'エリア別一覧'
			)
		)
	);
	
	register_taxonomy(
		'area_cat',
		'area',
		array(
			'hierarchical' => true,
			'label' => '都道府県',
			'show_ui' => true,
			'query_var' => true,
			'rewrite' => array('slug' => 'area'),
			'singular_label' => '都道府県'
		)
	);
}

[2014.07.07追記] register_taxonomyの ‘rewrite’ => true を ‘rewrite’ => array(‘slug’ => ‘area’)に変更しました。

こうなっていると404が出てしまうスイッチ

flush_rewrite_rules( false ); を書くと404が出てしまった。

これをregister_post_typeを追加した後に書いておくと404が直るといくつかのブログで見つけることができ、実際に以前別件で404が出ていたときにこれで直ったので書いてあったコードです。

ただ、この部分がおこなっているのはリライトルールを更新するぐらいなので、functions.phpを更新したら自分の手で管理画面の「設定」→「パーマリンク設定」を開き、「変更を更新」ボタンで空更新すればいいだけの話です。取ってしまいましょう。

‘rewrite’ の ‘with_front’ を false にするとダメだった。

これもいくつかのブログで解決法として提示されていました。

[2015.04.24追記] WP 4.1.2とCustom Post Type Permalinks 1.0.3の組み合わせでは、この件について’with_front’ を falseにしても問題は起きなくなりました。※functions.phpを更新したらパーマリンクの空更新を忘れずに!

rewriteは配列でいくつかのパラメータを設定することができます。

/* 例えばこんな感じ (register_post_type) */
'rewrite' => array(
	'slug' => 'bar', // 個別記事ページのスラッグベースをbarに変更
	'with_front' => false, // falseにすると投稿のパーマリンクで設定した文字列が付かない。初期値はtrue
	'feeds' => false, // falseにするとfeedを出力しない。初期値は'has_archive'の値
	'pages' => true // アーカイブページは作るけどページングはいらない場合はfalse。初期値はtrue
),

参考:Function Reference/register post type « WordPress Codex

カスタム投稿の個別記事パーマリンクは先に書いたようにデフォルトで http://サイトのアドレス/投稿タイプ名/投稿名/ のようになります。
しかし、通常の投稿のパーマリンクで /archive/%postname%/ のように文字列を入れて設定している場合は、 /archive/ がカスタム投稿の個別記事にもついて http://サイトのアドレス/archive/投稿タイプ名/投稿名/ となります。(これが’with_front’の初期値:true)

‘with_front’ を false にして解決した方々はきっと投稿のパーマリンクに文字列を入れていたのかもしれません。実際、他のサイトでパーマリンクを /news/%postname%/ と設定しているサイトでは、’with_front’=>false でキレイに /news が取れて404も出ませんでした。
今回取り組んでいるサイトの場合は /%category%/%postname%/ という設定をしていたのでダメだったんですかね?うーん。

今回の場合はそのまま ‘rewrite’ => true (投稿タイプ名 /area/ をスラッグとして使う設定)としました。

同じく ‘rewrite’ の ‘hierarchical’ を true にしてもダメだった。

これは以下のサイトで解決法として書かれていました。
参考:taxonomy.phpを読み込まずに404が出てしまう件の解決方法
WP 3.1から加わったらしいパラメータですが、今回の場合はこれも書いてあるとダメなようで最終的に取りました。

register_taxonomy の ‘query_var’ が false だとダメだった。

「’query_var’ => true」に設定すると、「http://ブログのアドレス/?カスタム分類名=個々の分類のスラッグ」のアドレスで、そのカスタム分類のアーカイブページを開くことができるようになります。
また、「’query_var’ => 文字列」とすると、「http://ブログのアドレス/?文字列=個々の分類のスラッグ」のアドレスで、そのカスタム分類のアーカイブページを開くことができるようになります。register_taxonomy関数の書き方 – The blog of H.Fujimoto

これは404になってしまうのではなく、カスタム分類アーカイブがURLは希望通りに出力されるのですが、サイトトップページが表示されてしまうという状況になってしまいました。trueにするか省略するかにしておきます。

他、直接僕には関係がなかった例として、カスタム分類名にハイフンが入っていたり、投稿の方のカテゴリー名や固定ページのスラッグと被っていたりした事例がありました。

カスタム投稿とカスタム分類のパーマリンクを思い通りに設定する

カスタム投稿アーカイブ

カスタム投稿アーカイブに関してはデフォルトで
http://サイトのアドレス/カスタム投稿名/
となるので今回はこのまま希望通りです。次に行きましょう。

個別記事ページのパーマリンク

今回の案件では通常投稿のパーマリンクは管理画面のカスタム構造で
http://サイトのアドレス/%category%/%postname%/
としてあります。

このときカスタム投稿タイプの個別記事は、
http://サイトのアドレス/投稿タイプ名/投稿名/ となり、
http://example.com/area/chuo/ です。

これを、
http://example.com/area/tokyo/chuo/ としたいので、
http://サイトのアドレス/投稿タイプ名/ターム/投稿名/ となるようにします。

実現するためにCustom Post Type Permalinksプラグインを使いますが、0.7.9.1の時点で既知の不具合として、

  1. ‘hierarchical’ => trueなカスタム投稿タイプと、’hierarchical’ => trueなカスタム分類を関連づけている
  2. その投稿タイプパーマリンクにカスタム分類を設定している
  3. 記事が親カテゴリを持つカテゴリ(ターム)に所属している

という3つの条件を満たすと404が出てしまう問題があるので気をつけてください。

プラグインを有効にしたら、管理画面の「設定」→「パーマリンク設定」を開き、 /area/%area_cat%/%postname%/ となるように設定して更新(%area_cat%の箇所は自分でつけたカスタム分類名に置き換えてください)。これでOKです。

[2014.07.07追記] プラグインのバージョン0.9.5.4で同ページの下部にある「カスタム分類のアーカイブのパーマリンクを変更する。」のチェックはオフにしてください。

カスタム分類アーカイブ

カスタム分類アーカイブはデフォルトだと
http://サイトのアドレス/カスタム分類名/ターム/
http://example.com/area_cat/tokyo/ です。

Custom Post Type Permalinksを使うと
http://サイトのアドレス/投稿タイプ名/カスタム分類名/ターム/ とすることができます。
あとはここから「カスタム分類名」を取ることが出来れば完成ですね。

register_taxonomy の ‘rewrite’ を array( ‘slug’ => ” ) と空にすることでカスタム分類アーカイブのカスタム分類名(今回の例だとarea_cat)が消え、思い通りのURLになります。
ですが、僕の環境だと通常投稿の個別記事と月別アーカイブのページが404になってしまったので、ここは単なるtrueにし、functions.phpに以下のように書きました。これで完成です。

//カスタム投稿パーマリンク「/taxonomy/」削除
function my_custom_post_type_permalinks_set($termlink, $term, $taxonomy){
	return str_replace('/'.$taxonomy.'/', '/', $termlink);
}
add_filter('term_link', 'my_custom_post_type_permalinks_set',11,3);

参考:カスタム投稿とカスタム分類 / かりんと~く 【 夢猫工房 】

[2014.07.07追記] プラグインバージョン0.9.5.4現在、上のコードだとうまくいかないので使いません。今回の用途であればここまでの設定で目標のURL構造で表示されているはずです。
ただし、ページング(2ページ目、3ページ目…)を必要とする場合、2ページ目以降が404になってしまうようで、functions.phpにリライトルールを追加します。

// カスタム分類アーカイブ用のリライトルールを追加する
add_rewrite_rule('area/([^/]+)/page/([0-9]+)/?$', 'index.php?area_cat=$matches[1]&paged=$matches[2]', 'top'); //2ページ目以降用 

参考:新?パーマリンクからタクソノミーを消す方法

おまけ:同じカスタム分類を通常投稿(post)でも使いたい

カスタム分類を複数の投稿タイプに使うには、register_taxonomyの第二引数を配列で書けば大丈夫なのですが、postとかを先に書いてしまうとCustom Post Type Permalinksを使っている影響でカスタム分類アーカイブのURLがおかしくなります。
そんなときは以下のように、先にカスタム投稿タイプ名を書いてあげると大丈夫です。

register_taxonomy('area_cat', array( 'area', 'post' ), $args);

カスタム投稿、カスタム分類まわりは色々な原因で404が出てしまう部分で、ちょっと検索してみても様々な事例を見ることができます。
例えば、今回はページングができる必要がありませんでしたが、ここで不具合が出ている人も多いようでした。
404と闘っているエンジニアの方々に僕の場合の解決策も参考になればと思います。