wordpressでカスタム投稿タイプとタクソノミーを作った時のURL設計
Qiita WordPress Advent Calendar 2017の記事です。
公開がすごく遅くなって申し訳ない。
wordpressってイマイチURL設計に自由度がないのよね〜などと言われた時に「そんなことないもん」って言い返したいための、カスタム投稿タイプとカスタムタクソノミーを混ぜたURL設計のやり方です。
実際、カスタム投稿タイプやカスタムタクソノミーなどを作成した時に「あれ、このパーマリンクどうやって実現するんだっけ」ってなることがおおいにあることでしょう。
たとえば
カスタム投稿タイプ:animals
カスタム投稿タイプanimalのカスタムタクソノミー:animal-families
を作成したとしてお話を進めていきますよ。
カスタム投稿タイプとタクソノミーを作る
functions.phpに以下のように記載し、カスタム投稿タイプとカスタムタクソノミーを作成します。
register_post_type(
'animals',
array(
'label' => 'どうぶつ',
'description' => '',
'public' => true,
'hierarchical' => false,
'rewrite' => true,
'query_var' => true,
'has_archive' => true,
'menu_position' => 5,
'supports' => array(
'title',
'editor',
'custom-fields'
),
'labels' => array(
'name' => 'どうぶつ',
'all_items' =>'項目一覧',
'add_new' => '新しいどうぶつ',
'add_new_item' => '新しいどうぶつを追加',
'edit' => '編集',
'edit_item' => 'どうぶつを編集',
'new_item' => '新しいどうぶつ',
'view' => '表示',
'view_item' => 'どうぶつを表示',
'search_items' => 'どうぶつを検索',
'not_found' => '見つかりませんでした。',
'not_found_in_trash' => 'ゴミ箱内に見つかりませんでした。'
)
)
);
register_taxonomy(
'animal_families', //タクソノミー名
'animals', //投稿タイプ
array(
'hierarchical' => true,
'label' => 'どうぶつの種類',
'query_var' => true,
'rewrite' => array('slug' => 'animals/family'),
'labels' => array(
'name' => 'どうぶつの種類',
'singular_name' => 'どうぶつの種類',
'search_items' => 'どうぶつの種類を検索',
'all_items' => 'すべてのどうぶつの種類',
'edit_item' => 'どうぶつの種類を編集',
'update_item' => 'どうぶつの種類を更新',
'add_new_item' => 'どうぶつの種類を追加',
'new_item_name' => '新しいどうぶつの種類'
)
)
);
animal-familiesは以下のようになっているとしよう。
- felidae(ネコ科)
- panthera(ヒョウ属)
- felis(ネコ属)
- canidae(イヌ科)
- vulpes(キツネ属)
- nyctereutes(タヌキ属)
(亜目とかのことはわすれてください)
期待するURL
カスタム投稿タイプanimalの記事は
/animals/%postname%
カスタム投稿タイプanimalsに紐づくカスタムタクソノミーanimal-familiesのアーカイブは
/animals/family/%term%
(なので、taxonomyのrewriteではslugにanimals/familyと記載)
このままではアクセスできない!
しかしこのままではanimal-familiesのアーカイブにアクセスはできないのです。
/animals/以下はカスタム投稿タイプの記事を探されてしまうから。
add_rewrite_ruleを追記して解決しよう
ここでfunctions.phpに以下の通り追記します。
function myUrlRewrite(){
add_rewrite_rule('animals/family/([^/]+)/?$', 'index.php?animal_families=$matches[1]', 'top');
}
add_action( 'init', 'myUrlRewrite' );
add_rewrite_rule
を追記した後のお約束
add_rewrite_rule
を追記した後はこちらの関数を呼ぶ必要があります。
やり方としては2通り。
1. functions.php内でflush_rulesを実行する
2. 「設定」の「パーマリンク設定」で何も変更せずに「保存」をクリックする(内部でflush_rules
が呼ばれている)
1番は
global $wp_rewrite;
$wp_rewrite->flush_rules(true);
みたいな使い方をします。しかし、flush_rulesは結構負担が大きい処理なので、前出の例ではinitという毎回呼ばれているfunctionに記載するのはやだなーということで今回は2番で書き換えしてます。
えっ、じゃあそもそもadd_rewrite_ruleってinitに書く必要あるの?いいえ、ないです。
本来はこんな感じで書くといいですね。前出は検証ってことでinitに書いちゃったっていうだけです。
function myUrlRewrite($rules){
$myRule = array();
$myRule['animals/family/([^/]+)/?$'] = 'index.php?animal_families=$matches[1]';
return array_merge( $myRule, $rules );
}
add_action('rewrite_rules_array', 'myUrlRewrite' );
flush後、アクセスして確認。
なんということでしょう。期待した通りのURLでアクセスできるではありませんか。
カスタムタクソノミーをURLに入れ込みたい
この例の場合、キツネ属のアカギツネだからURLも
/animals/family/vulpes(%term%)/red_fox(%postname%)/
みたいな感じにしたいな〜という要望もあるかもしれない。
これらは、まあ実現できないこともないのです。
まずはrewrite_rule
をちょこっと追記します。
function myUrlRewrite($rules){
$myRule = array();
$myRule['animals/family/([^/]+)/?$'] = 'index.php?animal_families=$matches[1]';
$myRule['animals/family/([^/]+)/([^/]+)?$'] = 'index.php?animals=$matches[2]';
return array_merge( $myRule, $rules );
}
add_action('rewrite_rules_array', 'myUrlRewrite' );
これで/animals/family/vulpes/red_fox
にアクセスされた際のルーティングはOK
お次にリンク生成部分の処理に手を加えるべく、post_type_link
とpost_link
に以下の処理をadd_filter
します。
function myPostTypeLink($link, $post ) {
if ( $post->post_type == 'animals' ) {
if ( $cats = get_the_terms( $post->ID, 'animal_families' ) ) {
$link = str_replace( '%animal_families%', current( $cats )->slug, $link );
}
}
return $link;
}
add_filter('post_type_link', 'myPostTypeLink', 10, 2 );
add_filter('post_link', 'myPostTypeLink', 10, 2 );
これで/animals/family/vulpes/
のアーカイブページにアクセスした際、ちゃんと期待したURLがリンクとして生成されています。
/animals/family/vulpes/red_fox/
にアクセスすると
/animals/family/%term%/%postname%/
このように実現します。
もし複数のtermが紐づいていたら・・・とか考えると、あんまり実装するべきではないのかなー、と思いますが。