WordPressでRewriteを書きまくる話

どうもこのところ立て続けにWordPressの仕事をしているので,どうしてもそれ絡みのネタが多くなってしまう.(;・∀・) 今回はURLの書き換えに関して.

WordPressにはデフォルトで実装されているURL生成の仕組みがあって,基本的にはそれに従って欲しいんだけど,クライアントの要望でWordPressのデフォルトのURLでは全然ダメなケースがこのところ頻発.

仕方ないので,functions.php に add_rewrite_rule を書きまくって対応しているんだけど,どう書けば良いのか迷った件が幾つかあったので,メモしておこうかと.(長いです)

カスタムポストタイプとカテゴリの組み合わせ

例えばカスタムポストタイプとして magazine をセットし,ここに追加でTaxonomyを作ってTermで分類したいといったケース. magazine専用のカテゴリ(例えば magcategory)を作って,Red, Blue, Yellow という3つから選択させたい.

さらに各カテゴリ毎に年での一覧表示ページ,さらに投稿n件毎にページネーションさせたい・・・ということでこれを検討していきます.

まずはURLを考えるところから

上に簡単に書いた仕様を実現するために,まずはURLを考える必要がありまして,今回のケースでは次の8種類にしました.

  1. /magazine/ ・・・マガジンのトップページ
  2. /magazine/page/2/・・・そのページネーション
  3. /magazine/2018/ ・・・年毎の一覧
  4. /magazine/2018/page/2/ ・・・そのページネーション
  5. /magazine/red/ ・・・ 各カテゴリのトップページ
  6. /magazine/red/page/2/ ・・・そのページネーション
  7. /magazine/red/2017/ ・・・カテゴリ別年毎の一覧
  8. /magazine/red/2017/page/2/ ・・・そのページネーション

URLのうち,”page”はページネーション専用の固定の文字列,またカテゴリ名は任意とはいえ URLをご覧頂けば判る通り,”page”と4桁の数字はカテゴリスラグとしては使用不可ではあります.(使っても良いんだけど,思い通りにはならない)

URLに合わせてrewrite_ruleを考える

1のマガジンのトップページとそのページネーションはWordPressのデフォルトのrewriteルールでカバーされますので,特にプログラム側で対応する必要はありません.

3の年別一覧と4の年別一覧のページネーションは次のようなルールをfunctions.phpに書きました.

5〜8の各カテゴリ別のURLでは,まずそのカテゴリ名(redとかblueとか)を表す引数をWordPressに伝えてやる必要があるので,その引数名を決めて(例えば term)設定します.

そのうえで,5〜8は次のように書きました.

これ,functions.phpに書く順番もとても重要です.

というのも,2階層目の年とpageとカテゴリスラッグが重なるので,先に年,次にpageの方を書いておかないと,例えば/magazine/2018/というURLの時に,2018をカテゴリスラッグとみなしてしまうのです. なので二回層目の条件として[0-9]{4}の方を先に指定しておき,次にpage/固定,最後に[^/]+とすることで,4桁の数字なら年,page/ならトップのページネーション,それ以外ならカテゴリスラッグという順番で処理させています.

rewrite_ruleによって渡されてくる引数を元に記事を抽出する

上で検討した8つのURLは全てmagazineの一覧表示用のテンプレート(archive-magazine.php)で受け取る事になるので,あとは引数をテンプレートのプログラムで受け取ってWP_Queryを使って投稿を引っ張り出せばOKです.

実際のプログラムからの抜粋であくまでもサンプルなので,こちらのソースそのものでの動作検証は行なっていませんが雰囲気は伝わると思います.

ここから先は通常のWordPressのテンプレートと同じようにループを回して記事を取り出せば良いわけです. 多少面倒なのはページネーションのリンクを作るところくらいですが,上述の通り既にURLは決めているので,引数に従ってURL文字列を生成して上げればOKです.

個別の記事表示URLにもご要望が

さらにそれぞれの記事のURLは記事に付与されたカテゴリ(例えばred)の下になるようにしたい. つまり,記事URLは /magazine/red/{記事タイトル}/ としたいとのご要望.

本来仕組みとして複数選択できるカテゴリをURLに埋め込むのはSEO的にはNGなはず(複数カテゴリを選択できると,複数のURLで全く同一の内容のページが生成されうるため)なんだけど運用でカテゴリは必ず一つ選択にするからこのURLで作ってくれ,と. そうなるとこれもrewriteを書く必要があります.

ごらんの通りで,二階層目のカテゴリの文字列は読み捨てて,3階層目の記事タイトルをそのままカスタムポストタイプに渡しています.

固定ページの子ページでカスタムポストタイプの一覧を表示したい

例えばですが,会社の履歴みたいな情報をhistoryというポストタイプを作ってそこで管理したい場合,履歴の一覧は通常のURLであれば /history/ になります.

ところが,これは会社の履歴なので,URLとしては /about/history/にしたいとのことでこれも rewrite_rule の出番です.(たぶん)

実はどうやるのがスマートなのかよく判らなかったので,historyポストタイプ専用のテンプレートを適当な名前で作り,template nameをセットしておきます.

こうしておいて,固定ページのaboutの下にhistoryという固定ページをつくり,テンプレートとして上のAbout Historyテンプレートを選択しておきます. これで/about/history/にアクセスしてきた時にこのテンプレートがアサインされるので,後はWP_Queryを使ってカスタムポストタイプを引っ張り出せばOKです.

ここまでは良かったんですが,このhistoryにはタグをつけられる様にして,そのタグ別の一覧を表示することになりました. URLとしては /about/history/{tagの名前}/ になります.

固定ページを呼び出すのなら,index.php?pagename={固定ページのslug}で良いはずなので,index.php?pagename=historyと書いたのですがこれだと動きませんでした. どうもおかしいと思って検索したところ,こちらのページがヒットしました.

https://wordpress.stackexchange.com/questions/50773/add-rewrite-rule-not-playing-nice-with-child-pages

わかってしまえば単純な話でpagename=about/historyと渡せということでした. で,結局タグ別一覧のURLは次のように記述しました.(タグのslugを渡したいのでadd_rewrite_tagも書いています)

あとはabout/historyのテンプレートの中で渡されてくるtag_nameを評価して絞り込むなりなんなりの処理を追加すれば良いわけです.


Rewriteのデバグとしてまたとないツール

で,こんな感じでfunctions.phpにadd_rewrute_ruleを書きまくっていると,果たしてこれちゃんと動いてるのかな?っていうのを確認する必要があるわけで,そんな時のデバグで役立つのがこちら.

このプラグインのおかげでrewrite_ruleのデバグが素晴らしく楽でした. インストールして有効化するとツールメニューの中に「Rewrite Rules」というサブメニューが現れるので,このページで確認したいURLを叩いてやると適用されるルールが順番に表示されるので,自分の期待通りか否かが一目瞭然なのでした.

数年前まではここまでrewrite_ruleを書くことは無かったのですが,ここ1年くらいは逆にrewrite_ruleを書かないで済む事は無い感じで,月に数回はrewriteに頭を悩ませているこのごろです.