【カスタムリライトルール】WordPressでパーマリンクを変更したい
この記事ではリライトルールの変更やパーマリンクの変更方法を紹介します。
- 「パーマリンクの設定」からでは対応不可能な変更をしたい
- 既存のリライト方法に加えて新しいURLを使用したい
こんな感じで検索している方には参考になると思います。
目次
- 既存のリライトルールの確認
- リライトの仕組み
- 独自のリライトルールを設定する
- WordPressから出力されるリンクを変更する
- オリジナルのリライトタグを使用したい場合
既存のリライトルールの確認
リライトルールを追加したくてもリライトルールの仕組みについて理解していないと追加することができません。
また、既存のリライトルールに被せようとしている場合も要チェックです。
そこで、一度現在設定されているリライトルールについて確認してみたいと思います。
パーマリンクを「基本」に設定している場合は出てこないと思います。
方法は二つです。
- WP-CLIから確認
- var_dump等で出力
WP-CLIから確認する方法
WP-CLIで確認する方が圧倒的に速いです。
(「Local」等ローカル開発環境で開発している場合はサイト名の右クリック「open site shell」でコマンド画面を起動できます。)
wp rewrite list
このコマンドを叩いてあげると現在設定されているリライトルールが一覧で画面に出力されます。
左列:マッチパターン(正規表現)
中列:エントリURL
右列:該当のタクソノミー、投稿タイプ
※右列は正しくない表記がされている可能性もあります。
var_dump等で出力
こちらは黒い画面を見たくない人向けです。
フックに引っ掛けてリライトルールを確認できます。
引っ掛けるフックは「rewrite_rules_array」です。
add_filter( 'rewrite_rules_array', function( $rules ) {var_dump( $rules );} );
連想配列で返されて、
key:マッチパターン(正規表現)
value:エントリURL
のようになっています。
リライトの仕組み
そもそもリライトの仕組みってどんな感じという人もいると思います。
上記でリライトルール確認したけど「index.php?name=$matches[1]」とかって言われても良くわからないという人ですね。
そんな人のために例を交えてみていきましょう。
「パーマリンク設定:投稿名」「投稿 スラッグ:hello」の場合
https://eample.com/hello
で投稿が表示されます。
この時の内部での動きは
- リクエストされたURLからリライトルールを確認する
- リライトルールがあった場合エントリURLからクエリパラメータを取得(?name=hello)
- SQL実行用の配列にパラメーターをセット
- 取得用のSQL実行
- 取得したデータをもとに表示
という感じになっています。
「リクエストされたURLからリライトルールを確認する」は上記例で見てみると、リライトルールの中にあった
([^/]+)(?:/([0-9]+))?/?$
というマッチパターンに引っかかっています。
そのためリライトルールから「index.php?name=hello&page=」というクエリーだとわかります。
nameだから「投稿」スラッグは「hello」、「page」は指定なしね
と解釈されて投稿が表示されるわけです。
リライトルールもおおよそ理解できたところで、リライトの設定方法を見ていきましょう。
独自のリライトルールを設定する
独自のリライトルールの設定は「rewrite_rules_array」をフックします。
先程確認のところでも使用したフックです。
引数の「$rules」は配列で、
key:マッチパターン(正規表現)
value:エントリURL
となっています。
それでは例として
固定ページは
https://example.com/kotei/sample1
のようにスラッグの前に「kotei」を入れます。
投稿は
https://example.com/toukou/sample2
のようにスラッグの前に「toukou」を入れます。
パーマリンク設定は投稿名です。
add_filter( 'rewrite_rules_array', function custom_rewrite_rules( $rules ) {$new = [];// 投稿ページ変更$new['toukou/([^/]+)(?:/([0-9]+))?/?$'] = 'index.php?name=$matches[1]&page=$matches[2]';// 固定ページ変更$new['kotei/(.?.+?)(?:/([0-9]+))?/?$'] = 'index.php?pagename=$matches[1]&page=$matches[2]';// デフォルトの投稿設定削除unset( $rules['([^/]+)(?:/([0-9]+))?/?$'] );// デフォルトの固定ページ設定削除unset( $rules['(.?.+?)(?:/([0-9]+))?/?$'] );// 設定ルールが先に適応される$new_rules = array_merge( $new, $rules );return $new_rules;} );
このような形になります。
※他にも投稿・固定ページ用のリライトがありますのでそれらも変更する必要があります。今回は例なので、メインのリライト設定のみ変更しています。
コード説明
$new['toukou/([^/]+)(?:/([0-9]+))?/?$'] = 'index.php?name=$matches[1]&page=$matches[2]';
新しくつくった配列にkey「’toukou/([^/]+)(?:/([0-9]+))?/?$’」、value「’index.php?name=$matches[1]&page=$matches[2]’」を当てはめています。
投稿の標準形のマッチパターンは「([^/]+)(?:/([0-9]+))?/?$」です。
なのでその前に「toukou/」を入れているだけです。
valueは投稿の標準形そのまま利用しています。
$new['kotei/(.?.+?)(?:/([0-9]+))?/?$'] = 'index.php?pagename=$matches[1]&page=$matches[2]';
新しくつくった配列にkey「’kotei/(.?.+?)(?:/([0-9]+))?/?$’」、value「’index.php?pagename=$matches[1]&page=$matches[2]’」を当てはめています。
固定ページの標準形のマッチパターンは「(.?.+?)(?:/([0-9]+))?/?$」です。
なので投稿同様に「kotei/」を入れているだけです。
valueは固定ページの標準形そのまま利用しています。
unset( $rules['([^/]+)(?:/([0-9]+))?/?$'] );unset( $rules['(.?.+?)(?:/([0-9]+))?/?$'] );
この記述は通常の投稿・固定ページのリライトルールを削除しています。
https://example.com/sample1
https://example.com/sample2
で表示できなくするための記述です。
$new_rules = array_merge( $new, $rules );
最後に新しいリライトルールと既存リライトルールを結合しています。
この場合新しいほうのルールが配列の先頭になります。
リライトは先頭のルールから検証されます。
今回はあまり問題ないですが、通常の投稿のような幅広いマッチをするルールは後ろから結合した方が良いです。
これで実際に入力URLで
「https://example.com/kotei/sample1」
と入力するとsample1の固定ページが表示されます。
また、
「https://example.com/sample1」
と入力した場合は404が返ってくるはずです。
投稿の方も同様に試してみてください。
ところで、
パーマリンク設定が投稿名の場合、固定ページと投稿はともに「https://example.com/slug」ですよね。
同じだけれどリライトルールを確認すると、
- 投稿:([^/]+)(?:/([0-9]+))?/?$
- 固定ページ:(.?.+?)(?:/([0-9]+))?/?$
となぜリライトルールが異なるのでしょうか。
これは階層型投稿タイプかどうかという違いになっています。
階層無し投稿タイプの場合は「投稿」のリライトルール、階層ありの場合は「固定ページ」のリライトルールになります。
カスタム投稿のリライトを行う場合は参考にして下さい。
そしてもう一つ、
固定ページと投稿が同じスラッグの場合どうなるでしょうか。
パーマリンクも一緒の場合表示されるのは固定ページになります。
なぜか、
それは、固定ページのリライトルールが配列の先にあり、マッチするからです。
同じ形式のパーマリンクを予定している場合はお気をつけて。。。
WordPressから出力されるリンクを変更する
リライトルール変更してURLはしっかり対応できるようになりました。
しかし、投稿の編集画面や、phpの関数で表示されるリンクはリライトルール変更前のリンクのはず。
これでは、ページが繋がらずいろいろと支障をきたします。
リライトはできるけどパーマリンクが変更されていないという状態です。
そこで、先ほどの例でパーマリンクの変更も行ってみます。
使用するのは投稿は「post_link」フィルターフック、固定ページは「page_link」フィルターフックです。
投稿
add_filter( 'post_link', function change_post_link( $permalink, $post, $leavename ) {return home_url( '/toukou/' . $post->post_name . '/' );}, 10, 3 );
固定ページ
add_filter( 'page_link', function change_post_link( $link, $post_id, $sample ) {$post = get_post( $post_id );return home_url( '/toukou/' . $post->post_name . '/' );}, 10, 3 );
書き方は好きなように変更して使用してください。
使用方法は単純で新しいパーマリンクを返してあげるだけです。
これで変更されたリライトルールに応じてパーマリンクも対応するようになりました。
※投稿タイプは「pre_post_link」でも変更できます。
オリジナルのリライトタグを使用したい場合
パーマリンク設定でカスタム構造に「%postname%」というのありますよね。
あれを独自で設定することも可能です。
「add_rewrite_tag」を使用します。
add_action( 'init', function() {add_rewrite_tag( '%custom_tag%', '([^&]+)', 'p=' );} );
このような感じで使用します。
第一引数: タグ文字列
第二引数: リライトルールのマッチパターン
第三引数: queryで使用できる形(※「=」で終わること)
上の例で
https://example.com/%custom_tag%
とカスタム構造を設定した場合。
ドメイン名後に投稿IDを入力するとその投稿が表示されるようになります。
初期設定で「https://example.com/1/」とすれば投稿ID 1 の「Hello World」が表示されます。
これはかなり楽なパターンですね。
デフォルトで「%post_id%」も用意されているので正直不要です。
実際はカスタム投稿タイプやカスタムタクソノミー、カスタムフィールドで使いたい場合が多いのでしょう。
そこで、カスタムフィールドでも例を作成してみようと思います。
add_action( 'init', function() {add_rewrite_tag( '%department%', '([^&]+)', 'department=' );} );
第一引数と第三引数が上のように同じなら省いても構いません。
add_rewrite_tagで追加したタグはデフォルトではないので自動で変更がされません。
そのため変更するための処理を追加してあげます。
add_filter( 'post_link', function( $permalink, $post, $levelname ) {if ( strpos( $permalink, '%department%' ) !== false ) {$post_meta = get_post_meta( $post->ID, 'department', true );$post_meta = $post_meta ? $post_meta : 'no-department';return str_replace( '%department%', $post_meta, $permalink );}return $permalink;}, 10, 3 );
先程も利用した「post_link」で追加したタグがあったら置換してあげる処理です。
これで例えば、
https://example.com/%department%/%post_name%/
とカスタム構造のパーマリンク設定にしたとします。
https://example.com/development/php/
と指定された場合、投稿のスラッグは「php」カスタムフィールド:departmentは「development」の投稿が表示されます。
URLのエイリアスを作る際にも上記を使用することができます。
先程のフックを少し変更しましょう。
add_action( 'init', function() {add_rewrite_tag( '%department%', '([^&]+)', 'department=' );add_rewrite_rule( 'programming/([^/]+)/([^/]+)/?', 'index.php?department=$matches[1]&name=$matches[2]', 'top' );} );
先ほどリライトルールの追加は配列で行いましたが、「add_rewrite_rules」は個別に追加できる関数です。
第三引数でリライトルール配列の先頭か一番後ろか選べます。
着目は「index.php?department=$matches[1]&name=$matches[2]」の部分です。
「add_rewrite_tag」に第三引数で指定した値を「add_rewrite_rurle」のqueryで使用していますね。
こうすることで、
先程の投稿は以下のどちらでも表示されるようになります。
(スラッグは「php」カスタムフィールド:departmentは「development」)
https://example.com/development/php
https://example.com/programming/development/php
実際エイリアスで使用することはないと思いますが、「add_rewrite_tag」「add_rewrite_rules」「設定したタグの置換」を使用したリンク設定で役に立つと思います。
まとめ
リンク設定は少しややこしい気もしますね。
以下、注意して変更しましょう。
- リンクを変更する場合は慎重に行いましょう。
- 本番環境でいきなり設定しないようにしましょう。
- ローカル環境でリライトルール確認しながら重複等なくしましょう。
本番環境のを変更する場合、seo評価の引継ぎのためのリダイレクト設定も併せて行うと良いと思います。