Rewrite APIその1 「Rewriteとパーマリンク」(WordPressプラグイン開発のバイブルのボツ原稿から)

WordPressプラグイン開発のバイブルという本がありまして、大絶賛大好評販売中なのですが、ボツ原稿を載せていきたいと思います。

ご購入はこちらから。

WordPressにたくさんあるAPIのうち、Rewrite APIを取り上げます。ここは、大幅に簡略化したところでして、ものすごく長いのでシリーズ物にしたいと思います。Rewrite APIはWordPressをアプリケーション・プラットフォームとして利用する際にとても便利なものですので、WordPressを使ってアプリを作るぞ!みたいな方々のお役に立てると思います。

第一弾はRewrite APIの前提となる「Rewriteとパーマリンク」の関係についてです。それでは、以下、ボツ原稿です(校正をするまえにボツになったので間違いも含むかもしれません。一応チェックはしました)。

次回は、デフォルトの状態のリライトを拡張して、WordPressをアプリとして動かすための便利関数について紹介します。

Rewriteとパーマリンク

管理画面の設定->パーマリンク設定へ進むと、URLの構造を変更することができます。

パーマリンク設定
管理画面のパーマリンク設定

デフォルトの状態は、“Ugly”と呼ばれていて、以下のようなURLでページが表示されます。

IDがNの投稿
http://example.com/?p=N

IDがNのカテゴリーアーカイブページ
http://example.com/?cat=N

IDがNの固定ページ
http://example.com/?page_id=N

どのようなサーバ環境でも動くように、新規インストール時のデフォルトはこうなっていますが、あまりかっこよくありません。

ウェブサーバーが

  • mod_rewriteモジュールが入っているApache
  • lighttpd
  • nginx

などであれば、“Pretty Permalinks”と呼ばれる、ディレクトリ構成を持つ静的なウェブサイトに似せたURLの構造を持たせることができます。構造の持ち方は、さまざまな設定が可能で、以下のタグを組み合わせてURLの構造を作ることができます。

タグ 内容
%year% 投稿された年を4桁で取得します。例えば、2004です。
%monthnum% 投稿された月を取得します。例えば、05です。
%day% 投稿された日を取得します。例えば、28です。
%hour% 投稿された時(時間)を取得します。例えば、15です。
%minute% 投稿された分を取得します。例えば、43です。
%second% 投稿された秒を取得します。例えば、33です。
%post_id% 投稿の固有IDを取得します。例えば、423です。
%postname% 投稿の投稿名を取得します。
%category% 投稿のカテゴリーを取得します。サブカテゴリーは入れ子にされたディレクトリとして取得されます。
%author% 投稿の作成者を取得します。

たとえば、/%year%/%monthnum%/%day%/%postname%-%post_id%を入力すると、投稿のURLは http://example.com/2014/12/24/crhistmas–345`となります。

この時に動作しているのがRewrite APIです。

.htaccessやnginx.confでのリライトの設定

WordPressのリライトがきちんと働くためにはサーバーでの設定が必要です。

Apacheの場合には、WordPressがインストールされているディレクトリに.htaccessを設置し、次の記述が必要になります。(たいていの場合、リライトルールを更新した際に自動的に生成されます)

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

上記の設定は、以下のような内容を示しています。

設定 内容
RewriteRule ^index.php$ – [L] リクエストがすでにindex.phpの場合には、以降の-fのチェックに進まない。
RewriteCond %{REQUEST_FILENAME} !-f リクエストされたファイルが存在しないならば次へ、
RewriteCond %{REQUEST_FILENAME} !-d リクエストされたディレクトリ存在しないならば次へ、
RewriteRule . /index.php [L] index.phpへリダイレクトし、以後他のリライトを行わない

つまり、サーバーはまずURLによってリクエストされた場所、たとえば、http://example.com/dir/nameにnameというファイル、あるいはnameというディレクトリがあるかどうかを確認して、ファイル/ディレクトリがあれば通常通りにレスポンスし、もし無ければWordPressルートのindex.phpにリライトを行います。

リクエストされたパスにディレクトリもパスもない場合には、WordPressがリクエストを受け取り、リライトルールに従って要求されたデータ、HTMLを応答する、ということです。
(リライトはリダイレクトのようにユーザ(ブラウザ)を実際に転送させるわけではありません。リクエストがindex.phpに渡される感じです)

この設定はウェブサーバーがnginxの場合でも必要で、WordPressのパーマリンク設定などの設定は、WordPressのリライトルールとウェブサーバーのURLリライト機能が組み合わさって実現されています。

WordPressによるURLの処理

パーマリンクがデフォルト以外に設定されている場合、WordPressは、URLを解析して訪問者が求めているページを判別します。

WordPressがインストールされているディレクトリにあるindex.phpは、wp-blog-header.phpファイルを読み込んでおり、wp-blog-header.phpでは、wp-load.phpというwp-config.phpを読み込むためのファイルを呼び出します。wp-config.phpが読み込むwp-setting.phpの中に、WordPressによるURLの解釈、リライトのために重要な2つのオブジェクト、$wp_queryと$wp_rewriteが初期化されます。

この時点では、多くの機能が利用可能な状態になっていますが、どのページが表示されるべきなのか、まだ分かっていません。wp-blog-header.phpで、次にコールされているのが、WPオブジェクトのparse_queryメソッドを呼び出す、wp()関数です。

この関数が実行されることで、WordPressがURLから必要なページを判断できるようになるのです。

大曲仁さんによるブログ記事より、WordPressの実行フローを視覚化した図。 http://www.warna.info/archives/279/
大曲仁さんによるブログ記事より、WordPressの実行フローを視覚化した図。 http://www.warna.info/archives/279/

たとえば、リクエストURLhttp://example.com/category/book/page/2は、実際にはhttp://example.com/index.php?category_name=book&paged=2を意味しており、カテゴリーアーカイブの2ページ目を表示する、という具合です。

以下は、wp-blog-header.phpファイルのメインの部分です。

require_once( dirname(__FILE__) . '/wp-load.php' );

wp();

require_once( ABSPATH . WPINC . '/template-loader.php' );

はじめにwp-load.phpが読み込まれて、WordPressの機能が使えるように準備が行われます。次に、wp()によってURLの解釈が行われて、最後のtemplate-loader.phpでは、テーマのテンプレートファイルの選択が行われるようになります。

ルートのindex.phpからwp-blog-header.php、wp-load.php、wp-settings.phpまでの流れ、ここまででテーマの利用の直前までに必要な大部分が実行可能な状態になっています、さらに、URLが解釈されるwp()の概要、最後に解釈にしたがってテーマテンプレートが選ばれるに至るtemplate-loader.phpについては、WordPressの基本的な動き方を知る上でとても重要なので、一度目を通してみるとよいと思います。

リライトルール

wp()関数が実行されると、WordPressに登録されたリライトルールが参照されます。リライトルールは、$wp_rewriteオブジェクトに登録されており、テーマ内に以下の記述をすることで参照することができます。

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

結果の一部を抜粋すると、以下のようになっています。

object(WP_Rewrite) (24) {
  ["permalink_structure"]=>
  string(30) "/%year%/%monthnum%/%postname%/"
  ["use_trailing_slashes"]=>
  bool(true)
  ["author_base"]=>
  string(6) "author"
  ["search_base"]=>
  string(6) "search"

  (中略)

  ["rules"]=>
  array(70) {
    ["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/(.+?)/page/?([0-9]{1,})/?$"]=>
    string(53) "index.php?category_name=$matches[1]&paged=$matches[2]"

	(中略。URLのパターンと、置き換えるべき形のリストのペアが続く)

  }
  
  (中略)

  ["endpoints"]=>
  array(0) {
  }

  (中略)

}

上記のうち、$wp_rewrite->rulesがリライトルールのリストです。パターンと置き換えの方法が格納されているのがわかると思います。

同様に、$wp_queryオブジェクトを参照( example.com/http-testという固定ページでvar_dump( $wp_query ))すると以下の情報が得られます。

object(WP_Query) (49) {
  ["query"]=>
  array(2) {
    ["page"]=>
    string(0) ""
    ["pagename"]=>
    string(9) "http-test"
  }
  ["query_vars"]=>
  array(62) {
    ["page"]=>
    int(0)
    ["pagename"]=>
    string(9) "http-test"
    ["error"]=>
    string(0) ""
    
    (中略)

  ["queried_object"]=>
  object(WP_Post)#1740 (24) {
    ["ID"]=>
    int(57)
    ["post_author"]=>
    string(1) "1"
    ["post_date"]=>
    string(19) "2014-04-24 13:12:23"
    ["post_date_gmt"]=>
    string(19) "2014-04-24 04:12:23"
    ["post_content"]=>
    string(0) ""
    ["post_title"]=>
    string(9) "HTTP TEST"
    ["post_excerpt"]=>
    string(0) ""
    ["post_status"]=>
    string(7) "publish"

  (中略)

  ["is_single"]=>
  bool(false)
  ["is_preview"]=>
  bool(false)
  ["is_page"]=>
  bool(true)
  ["is_archive"]=>
  bool(false)
  ["is_date"]=>
  bool(false)
  
  (後略)

$wp_query->query_varsは配列になっていて、これらはURLからパースされたキーと値のペアになっています。
キーになれる文字列は決まっており、デフォルトではp(投稿のID)、w(週)、cat(カテゴリーのterm_id)、author(作成者のユーザーID)、orderby(アーカイブの並び順基準。dateなど)です。
WordPressはこれらをもとに、MySQLを検索して必要な情報を取得しています。

Rewrite APIの利用の利点

前置きが長くなってしまいましたが、プラグインからWordPressのRewrite APIにアクセスすることで、独自のリライトルールを追加して、WordPressの解釈方法を定義することが可能になります。

ボツ原稿はここまでです。次回”Rewrite APIその2 WordPressでアプリを作る基本(WordPressプラグイン開発のバイブルのボツ原稿から)”に続きます

↓ プラグインを作る方々への本、書きました。 ↓

“Rewrite APIその1 「Rewriteとパーマリンク」(WordPressプラグイン開発のバイブルのボツ原稿から)” への 3 件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です