同じリライトルールで投稿もカテゴリーも表示させる

同じリライトルール(パーマリンク構造)で投稿もカテゴリ―も表示させる方法を紹介します。
WordPressで「投稿名」をパーマリンク設定で設定しているとします。
その場合
- 『投稿』・・・https://kumatech-lab.com/post-name
- 『カテゴリ―』・・・https://kumatech-lab.com/category/php
のようにパーマリンクが決定します。
今回紹介する方法は、
と同様のパーマリンク形式で表示しつつもそれぞれの内容は「投稿」「カテゴリ―」となるような方法です。
通常のブログでの利用機会は少ないと思いますが、企業のサイトなどカスタムカテゴリ―・カスタムタクソノミーを使用する場合には覚えておくと便利です。
もちろん同様の形式にする以上、投稿のスラッグとカテゴリーのスラッグで同一のものを使用した場合優先度の高いほうが優先されますので運用上の回避が必要になります。
同じリライトルールで投稿もカテゴリ―も表示させる
まずは、同一リライトルールを投稿とカテゴリ―に適応させる必要があります。
変更方法は以下記事を参考にしてください。
https://kumatech-lab.com/wordpress-permalink-rewrite/
上記でリライトルールの設定が終わったら、一度表示を確かめてみましょう。
リライトルール配列の先に設定した方は意図した動きをすると思います。(カテゴリ―を投稿と同じリライトルールに変更してカテゴリ―の方が優先度が高い場合、投稿と同じリライトルールでカテゴリ―が表示される。)
ただし、もう片方は404など意図していない表示がされると思います。 (カテゴリ―を投稿と同じリライトルールに変更してカテゴリ―の方が優先度が高い場合、正常に表示されていた投稿が表示されなくなる。)
ここからが本題です。
投稿、カテゴリ―が正常に表示されるように調整していきましょう。
リクエストを変更する
リライトルールが適用された後はその内容に応じて適切にリクエストが生成されます。
そのリクエストに少し手を加えることで、同一パーマリンクを実現させることができるようになります。
リクエストに手を加えるには「request」フィルターフックを活用します。
apply_filters( 'request', array $query_vars )
引数はリクエストの配列です。
中身の例を見てみます。パーマリンクが「投稿名」でデフォルトの場合です。
リライトルールで「index.php?category_name=$matches[1]」が適用された場合(cat1というカテゴリ―にアクセス)
Array([category_name] => cat1)
リライトルールで「index.php?name=$matches[1]&page=$matches[2]」が適用された場合(testという投稿にアクセス)
Array([page] =>[name] => test)
上の例を見てわかると思いますが、キーとスラッグの形になっています。
なので、カテゴリ―のスラッグでカテゴリーが存在するか確認、存在すればそのまま、存在しなければキーを変更し、投稿の形に変更してあげます。
早速変更適用例を見てみましょう。
add_filter( 'request', function ( $vars ) {foreach ( $vars as $key => $value ) {if ( 'category_name' === $key ) {if ( ! get_term_by( 'slug', $value, 'category' ) ) {$vars['name'] = $value;unset( $vars[$key] );break;}} elseif ( 'name' === $key ) {$query = new WP_Query( 'name' => $value );if ( ! $query->have_posts() ) {$vars['category_name'] = $value;unset( $vars[$key] );break;}}}return $vars;} );
リクエストの連想配列をforeachでまわします。
if ( 'category_name' === $key ) {if ( ! get_term_by( 'slug', $value, 'category' ) ) {$vars['name'] = $value;unset( $vars[$key] );break;}}
「category_name」の場合、カテゴリ―の存在確認をして、なければ投稿の形式に変換しています。
elseif ( 'name' === $key ) {$query = new WP_Query( 'name' => $value );if ( ! $query->have_posts() ) {$vars['category_name'] = $value;unset( $vars[$key] );break;}}
同様に「name」の場合は、投稿の存在を確認、なければカテゴリ―の形式に変換しています。
以上をfunctions.phpなどに記述することで序盤に紹介した
- 『投稿』・・・https://kumatech-lab.com/post-name
- 『カテゴリ―』・・・https://kumatech-lab.com/php
がどちらも正常に表示されて内容も投稿とカテゴリ―が問題ありません。
まとめ
投稿スラッグは「name」、カテゴリ―スラッグは「category_name」と紹介しましたが、他のがわからない場合はログとして出力して確認しましょう。
WP_Queryと似たなので、WordPressの公式ページから確認するのも良いかもしれません。
また、今回紹介でpage、pagedについては考慮していません。実際に使用する場合は考慮して変換する、または、投稿ページは分割しないなど運用上回避を行ってください。