WordPress Logo WordPress パーマリンク リライトルール

パーマリンクやリライトルールの基本的なことやリライトルールを追加する関数 add_rewrite_rule() やリライトルール関連のフィルターなどの使い方についての覚え書きです。

更新日:2023年03月11日

作成日:2019年07月22日

リライトルール

パーマリンク(URL)がデフォルトの「基本」以外に設定されている Pretty パーマリンクの場合、WordPress は内部で URL 文字列のドメイン以降の部分をクエリ変数を使ったパラメータに変換してそれらに基づいて表示するページを決定しています。

例えば、ブラウザのアドレスバーに以下の URL が入力された場合、

http://example.com/contact

WordPress の内部ではリライト処理が行われ、例えば以下のような URL として認識されます。

http://example.com/index.php?pagename=contact

言い換えると、

http://example.com/contact でアクセスされたら

http://example.com/index.php?pagename=contact を表示するようになっています。

リライトルールとは上記のようにリクエストされたページの URL を必要に応じてパラメータに変換するための規則です。

WordPress は内部ではリライトルールに基いて URL をパラメータに変換してページを表示しています。

また、リライトルールを管理するためのクラスは WP_Rewrite になります。

Codex 日本語版:WP_Rewrite クラス

リライトルールは、WP_Rewrite で定義され、そのインスタンス $wp_rewrite に登録されているので、header.php などのテーマのファイルに以下を記述して参照することができます。

<pre><?php var_dump( $wp_rewrite ); ?></pre>

以下は出力例の一部抜粋です(リライトルール以外は改行を削除しています)。

object(WP_Rewrite)#526 (25) {
  ["permalink_structure"]=>string(23) "/%category%/%postname%/"  //パーマリンク設定
  ["use_trailing_slashes"]=>bool(true)
  ["author_base"]=>string(6) "author"
  ["page_structure"]=>string(10) "%pagename%"
  ["search_base"]=>string(6) "search"
  ["comments_base"]=>string(8) "comments"
  ["pagination_base"]=>string(4) "page"
  ["comments_pagination_base"]=>string(12) "comment-page"
  ["feed_base"]=>string(4) "feed"
  ["front"]=>string(1) "/"
  ["root"]=>string(0) ""
  ["index"]=>string(9) "index.php"
  ["matches"]=>string(0) ""
  ["rules"]=>  //★リライトルールの配列
  array(170) {
    ["^wp-json/?$"]=> //キー(正規表現)
    string(22) "index.php?rest_route=/"  //値(変換後のパラメータの形式)
    ["^wp-json/(.*)?"]=>
    string(33) "index.php?rest_route=/$matches[1]"
    ["^index.php/wp-json/?$"]=>
    string(22) "index.php?rest_route=/"
    ["^index.php/wp-json/(.*)?"]=>
    string(33) "index.php?rest_route=/$matches[1]"
    ["rental/?$"]=>
    string(26) "index.php?post_type=rental"
    ["category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$"]=>
    string(52) "index.php?category_name=$matches[1]&feed=$matches[2]"
    ["category/(.+?)/(feed|rdf|rss|rss2|atom)/?$"]=>
    string(52) "index.php?category_name=$matches[1]&feed=$matches[2]"
    ["category/(.+?)/embed/?$"]=>
    string(46) "index.php?category_name=$matches[1]&embed=true"
    ["category/(.+?)/page/?([0-9]{1,})/?$"]=>
    string(53) "index.php?category_name=$matches[1]&paged=$matches[2]"
    ["category/(.+?)/?$"]=>
    string(35) "index.php?category_name=$matches[1]"
    ["tag/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$"]=>
    string(42) "index.php?tag=$matches[1]&feed=$matches[2]"
    ["tag/([^/]+)/(feed|rdf|rss|rss2|atom)/?$"]=>
    string(42) "index.php?tag=$matches[1]&feed=$matches[2]"

    ・・・中略・・・

  ["extra_permastructs"]=>  //パーマリンク構造
  array(9) {
    ["category"]=>
    array(8) {
      ["with_front"]=>bool(true)
      ["ep_mask"]=>int(512)
      ["paged"]=>bool(true)
      ["feed"]=>bool(true)
      ["forcomments"]=>bool(false)
      ["walk_dirs"]=>bool(true)
      ["endpoints"]=>bool(true)
      ["struct"]=>string(20) "/category/%category%"
    }
    ["post_tag"]=>
    array(8) {
      ["with_front"]=>bool(true)
      ["ep_mask"]=>int(1024)
      ["paged"]=>bool(true)
      ["feed"]=>bool(true)
      ["forcomments"]=>bool(false)
      ["walk_dirs"]=>bool(true)
      ["endpoints"]=>bool(true)
      ["struct"]=>string(15) "/tag/%post_tag%"
    }
    ["post_format"]=>
    array(8) {
      ["with_front"]=>bool(true)
      ["ep_mask"]=>int(0)
      ["paged"]=>bool(true)
      ["feed"]=>bool(true)
      ["forcomments"]=>bool(false)
      ["walk_dirs"]=>bool(true)
      ["endpoints"]=>bool(true)
      ["struct"]=>string(19) "/type/%post_format%"
    }

    ・・・中略・・・

  ["rewritecode"]=>  //リライトタグ(構造タグ)
  array(21) {
    [0]=>string(6) "%year%"
    [1]=>string(10) "%monthnum%"
    [2]=>string(5) "%day%"
    [3]=>string(6) "%hour%"
    [4]=>string(8) "%minute%"
    [5]=>string(8) "%second%"
    [6]=>string(10) "%postname%"
    [7]=>string(9) "%post_id%"
    [8]=>string(8) "%author%"
    [9]=>string(10) "%pagename%"
    [10]=>string(8) "%search%"
    [11]=>string(10) "%category%"
    [12]=>string(10) "%post_tag%"
    [13]=>string(13) "%post_format%"
    ・・・中略・・・
  }
  ["rewritereplace"]=>  //リライトタグ(構造タグ)を置き換える正規表現
  array(21) {
    [0]=>string(10) "([0-9]{4})"
    [1]=>string(12) "([0-9]{1,2})"
    [2]=>string(12) "([0-9]{1,2})"
    [3]=>string(12) "([0-9]{1,2})"
    [4]=>string(12) "([0-9]{1,2})"
    [5]=>string(12) "([0-9]{1,2})"
    [6]=>string(7) "([^/]+)"
    [7]=>string(8) "([0-9]+)"
    [8]=>string(7) "([^/]+)"
    [9]=>string(8) "([^/]+?)"
    [10]=>string(4) "(.+)"
    [11]=>string(5) "(.+?)"
    [12]=>string(7) "([^/]+)"
    [13]=>string(7) "([^/]+)"
    ・・・中略・・・
  }
  ["queryreplace"]=>  //置換後に追加するクエリパラメータ
  array(21) {
    [0]=>string(5) "year="
    [1]=>string(9) "monthnum="
    [2]=>string(4) "day="
    [3]=>string(5) "hour="
    [4]=>string(7) "minute="
    [5]=>string(7) "second="
    [6]=>string(5) "name="
    [7]=>string(2) "p="
    [8]=>string(12) "author_name="
    [9]=>string(9) "pagename="
    [10]=>string(2) "s="
    [11]=>string(14) "category_name="
    [12]=>string(4) "tag="
    [13]=>string(12) "post_format="
    ・・・中略・・・
  }
・・・以下省略・・・

リライトルールは上記のように正規表現をキー、変換するパラメータの形式を値とした連想配列で構成されています。

リライトルール(連想配列 rules)の構成要素
  • キー:URL の正規表現パターン(例:([0-9]{4})/?$)
  • 値:変換後のパラメータの形式(例:index.php?year=$matches[1])

例:rules["([0-9]{4})/?$"]=>"index.php?year=$matches[1]"

リライト処理の際は、リライトルールの連想配列を先頭から URL と照合し、最初にマッチしたルールを適用します。

このため、リライトルールの中にマッチするルールが複数あった場合、より先頭に近いルールが適用されることになります。

また、リライトルールだけを出力するには以下のように記述することができます。

<pre><?php var_dump( $wp_rewrite->rules ); ?></pre>

または、リライトルールはデータベースの options テーブルに rewrite_rules という名前で保存されているので、get_option() を使って以下のように記述するとリライトルールだけを出力することができます。

<pre><?php var_dump( get_option('rewrite_rules') ); ?></pre>

以下は出力例の一部抜粋です。Version 5.2.2 のデフォルトの場合、以下のように92個のルールがあります。カスタム投稿やカスタム分類を設定している場合は、それらのルールも追加されるのでルールはその分増えます。

array(92) {  //92個の配列(リライトルール)
  ["^wp-json/?$"]=>  //キーは正規表現
  string(22) "index.php?rest_route=/"  //値は変換後のパラメータの形式
  ["^wp-json/(.*)?"]=>
  string(33) "index.php?rest_route=/$matches[1]"
  ["^index.php/wp-json/?$"]=>
  string(22) "index.php?rest_route=/"
  ["^index.php/wp-json/(.*)?"]=>
  string(33) "index.php?rest_route=/$matches[1]"
  ["category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$"]=>
  string(52) "index.php?category_name=$matches[1]&feed=$matches[2]"
  ["category/(.+?)/(feed|rdf|rss|rss2|atom)/?$"]=>
  string(52) "index.php?category_name=$matches[1]&feed=$matches[2]"
  ["category/(.+?)/embed/?$"]=>
  string(46) "index.php?category_name=$matches[1]&embed=true"
  ["category/(.+?)/page/?([0-9]{1,})/?$"]=>
  string(53) "index.php?category_name=$matches[1]&paged=$matches[2]"
  ["category/(.+?)/?$"]=>
  string(35) "index.php?category_name=$matches[1]"
  ["tag/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$"]=>
  string(42) "index.php?tag=$matches[1]&feed=$matches[2]"
  ["tag/([^/]+)/(feed|rdf|rss|rss2|atom)/?$"]=>
  string(42) "index.php?tag=$matches[1]&feed=$matches[2]"
  ["tag/([^/]+)/embed/?$"]=>
  string(36) "index.php?tag=$matches[1]&embed=true"
  ["tag/([^/]+)/page/?([0-9]{1,})/?$"]=>
  string(43) "index.php?tag=$matches[1]&paged=$matches[2]"
  ["tag/([^/]+)/?$"]=>
  string(25) "index.php?tag=$matches[1]"
  ["type/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$"]=>
  string(50) "index.php?post_format=$matches[1]&feed=$matches[2]"
  ["type/([^/]+)/(feed|rdf|rss|rss2|atom)/?$"]=>
  string(50) "index.php?post_format=$matches[1]&feed=$matches[2]"
  ・・・中略・・・
  //例:4桁の数字/page/1桁以上のページ送りの数(例 /2019/06/page/2/)
  ["([0-9]{4})/page/?([0-9]{1,})/?$"]=>
  //index.php?year=マッチした4桁の数字&paged=ページ送り数(例 index.php?year=2019&paged=2)
  string(44) "index.php?year=$matches[1]&paged=$matches[2]"
  ["([0-9]{4})/?$"]=>
  string(26) "index.php?year=$matches[1]"
  [".?.+?/attachment/([^/]+)/?$"]=>
  string(32) "index.php?attachment=$matches[1]"
  ・・・中略・・・
  ["(.?.+?)/page/?([0-9]{1,})/?$"]=>
  string(48) "index.php?pagename=$matches[1]&paged=$matches[2]"
  ["(.?.+?)/comment-page-([0-9]{1,})/?$"]=>
  string(48) "index.php?pagename=$matches[1]&cpage=$matches[2]"
  ["(.?.+?)(?:/([0-9]+))?/?$"]=>
  string(47) "index.php?pagename=$matches[1]&page=$matches[2]"
  [".+?/[^/]+/attachment/([^/]+)/?$"]=>
  string(32) "index.php?attachment=$matches[1]"
 ・・・中略・・・
  ["(.+?)/([^/]+)/page/?([0-9]{1,})/?$"]=>
  string(70) "index.php?category_name=$matches[1]&name=$matches[2]&paged=$matches[3]"
  ["(.+?)/([^/]+)/comment-page-([0-9]{1,})/?$"]=>
  string(70) "index.php?category_name=$matches[1]&name=$matches[2]&cpage=$matches[3]"
  ["(.+?)/([^/]+)(?:/([0-9]+))?/?$"]=>
  string(69) "index.php?category_name=$matches[1]&name=$matches[2]&page=$matches[3]"
  ・・・中略・・・
  ["(.+?)/embed/?$"]=>
  string(46) "index.php?category_name=$matches[1]&embed=true"
  ["(.+?)/page/?([0-9]{1,})/?$"]=>
  string(53) "index.php?category_name=$matches[1]&paged=$matches[2]"
  ["(.+?)/comment-page-([0-9]{1,})/?$"]=>
  string(53) "index.php?category_name=$matches[1]&cpage=$matches[2]"
  ["(.+?)/?$"]=>
  string(35) "index.php?category_name=$matches[1]"
}

「パーマリンク設定」が「基本」の場合

「パーマリンク設定」でデフォルトの「基本」が選択されている場合は、リライトルールは作成されないので以下のようになります。

<pre><?php var_dump( $wp_rewrite->rules ); ?></pre>

<!--「パーマリンク設定」が「基本」の場合 -->
string(0) ""

Debug Bar

Debug Bar と言うプラグインを使うと、リライトルールによる変換を簡単に確認することができます。(Debug Bar は2019年7月の時点で検証済み最新バージョン:4.9.10 ですが、リライトルールの変換は確認することができます)

以下は投稿の個別ページ(ページのスラッグ: query-test)にアクセスした際のスクリーンショットです。

プラグイン Debug Bar の実行結果のスクリーンショット

リクエストされた URL が news/query-test で、
リライトルールのパターン (.+?)/([^/]+)(?:/([0-9]+))?/?$ がマッチしたため、以下のパラメータに変換されたことが確認できます。

category_name=news&name=query-test&page=(一致したリライト・クエリー)

この例でマッチしたパターン (.+?)/([^/]+)(?:/([0-9]+))?/?$ は前述の出力例57行目にあります。

このため以下の出力例58行目の変換後のパラメータの形式が適用されています。

index.php?category_name=$matches[1]&name=$matches[2]&page=$matches[3]

  • $matches[1]:news → (.+?)にマッチ。改行を除く文字列
  • $matches[2]:query-test → ([^/]+)にマッチ。/ 以外の文字列
  • $matches[3]:該当なし → ([0-9]+) 4番目の括弧。3番目の括弧は ?: があるので参照対象外

参考サイト:WordPress の表示ロジックを理解する – Reloaded –