Rewrite APIその2 WordPressでアプリを作る基本(WordPressプラグイン開発のバイブルのボツ原稿から)

WordPressプラグイン開発のバイブルという本がありまして、大絶賛大好評販売中なのですが、ボツ原稿を載せていくシリーズの、Rewrite APIの第二弾です。

書籍のご購入はこちらから。

前回の記事は、Rewrite APIその1 「Rewriteとパーマリンク」(WordPressプラグイン開発のバイブルのボツ原稿から)です。

前回のまとめをさくっと言いますと、WordPressにはパーマリンクという機能があり、カテゴリや日付、ポストIDやpostnameなどを組み合わせて、URLの構造を設定できますが、その機能はウェブサーバーのリライト機能とWordPressのリライト機能が組み合わさって実現されているということでした。

このことは、WordPressプラグイン開発のバイブルの中の第六章「WordPressのデータ構造とクエリを理解する」という章の中でも詳しく解説されていますので読んでみてくださいね。

Rewrite APIを利用することでWordPressをブログでもCMSでもなくアプリケーションプラットフォームとして活用する方法の第一歩でございますですよ。

では、以下、コピペになります。前回同様、校正前のものになります。誤字脱字、間違いはご連絡くださいな。

Rewrite APIの利用の利点

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

Rewrite APIの関数

以下は、Rewrite APIを利用する際に使う関数の一覧です。

関数 内容
add_rewrite_rule() リライトルールを追加する
add_rewrite_tag() 構造タグを追加する
add_rewrite_endpoint() リライトエンドポイントを追加する
flush_rewrite_rules() 既存のリライトルールを削除し、リライトルールを生成、保存する
add_permastruct() パーマリンク構造を追加する
add_feed() フィードを追加する

add_rewrite_rule()

それでは、ここからはいくつかの関数について事例を挙げながら説明をしていきます。

add_rewrite_rule()関数は、$wp_rewrite->rulesにリライトルールを追加するための関数です。

add_rewrite_rule( $rule, $rewrite, $position );
  • $rule: 正規表現でマッチする文字列を指定します
  • $rewrite: $ruleにマッチする文字列をどういうURLに変換するのかを指定します。$match配列でマッチした文字列を利用できます。
  • $position: ’top’か’bottom’を指定して、新しいルールの挿入位置を決めることができます。’top’を指定すると一番最初に挿入されるので、最優先され、bottomは最後に挿入されるので、他のすべての正規表現の後にマッチングがチェックされます。未指定のときはbottom。

例として、ウェブサイト内に、example.com/twitterというページを作成し、example.com/twitter/<username>というページにリクエストがあった時に、@usernameというTwitter IDのユーザーの情報を表示するケースを想定します。

ツイッターログインをさせるアプリケーションを作り、そのユーザーの情報を表示したり集めたり解析したりするアプリなどを想像してください。(同じことを、このあと説明する add_rewrite_endpoint() でも行えます)

準備として、/twitterというスラッグを持つページを作成します。

twitterというスラッグを持つ固定ページを作成
twitterというスラッグを持つ固定ページを作成

次に、twitter/<username>というURLでリクエストが来た場合に、このページが表示されるように、リライトルールを追加します。以下のコードを有効化したプラグインか、テーマのfunctions.phpに追記します。

add_action( 'init', 'my_add_twitter_rewrite_rule' );
function my_add_twitter_rewrite_rule() {
	add_rewrite_rule(
		'twitter/?[^/]*',
		'index.php?pagename=twitter&twitter_id=$matches[1]',
		'top'
	);
}

ここまでの作業で、example.com/twitter/shinichinや、example.com/twitter/miya0001などの形のURLのリクエストが来た場合には、example.com/twitterページが表示されるようになります。なぜならば、”twitter/なんらかの文字列”という$ruleに合致していて、index.php?pagename=twitter&twitter_id=shinichinにリライトが行われるようになっているからです。

404にならない
404にならず、pagename=twitterの固定ページが表示されました。

次に、<username>の部分を変数として受け取れるように設定を行います。twitter_idというパラメータをWordPressのクエリ変数(query_var)に追加します。twitter_idというGETパラメータがリライト後のURLに含まれていますが、前回のリライトルールの項で見たように、WordPressはこの文字列twitter_idを$wp_query->query_varsとして、デフォルトでは受け付けないためです。

add_filter( 'query_vars', 'my_add_twitter_to_qvar' );
function my_add_twitter_to_qvar( $vars ) {
	$vars[] = 'twitter_id';
	return $vars;
}

これで、$wp_query->query_varsに、’twitter_id’が追加されました。

追加された変数は、get_query_var('var_name')で取得できますので、以下のコードを追加して、確認してみます。

add_filter( 'template_redirect', 'show_wp_query' );
function show_wp_query() {
	if ( is_page( 'twitter' ) && !empty( get_query_var( 'twitter_id' ) ) ) {
		global $wp_query;
		echo '<pre>';
		var_dump( $wp_query );
		echo '</pre>';
		exit;
	}
}
$wp_query->query_vars[twitter_id]に格納されている。
$wp_query->query_vars[“twitter_id”]に格納されている。

あとは、$twitter_id = get_query_var( 'twitter_id' );でURLからTwitter IDを受け取り、Twitter APIからユーザー情報を取得して表示するのみです。

add_filter( 'template_redirect', 'show_twitter_userinfo' );
function show_twitter_userinfo() {
	if ( is_page( 'twitter' ) && !empty( get_query_var( 'twitter_id' ) ) ) {
		
		add_filter( 'the_content', 'get_user_info' );
			
	}
}

function get_user_info( $content ) {
	
	// 実際のアプリケーションではtwitter api から情報を取得して表示。
	$twitter_id = get_query_var( 'twitter_id' );
	return $twitter_id;
	
}

add_rewrite_endpoint()

add_rewrite_endpoint()は、WordPressの通常のURLの末尾にリライトエンドポイントを追加し、その後ろに来るスラッグを変数として受け取るための関数です。

リライトエンドポイントというのは、URLの末尾になんらかの文字列があった場合に、なんらかの動作をさせるための仕組みで、デフォルトの状態のWordPressから例をとると、”feed”があります。

  • example.com/feed : ブログのフィードが表示される
  • example.com/category/wp/feed:wpカテゴリのフィードが表示される
  • example.com/cptname/feed:cptnameというカスタム投稿のフィードが表示される

上記の例で分かるように、feedがエンドポイントとなり、その前までのURLを見てフィードを返すようになっているわけです。

add_rewrite_endpoint( $name, $places, $query_var = null );
  • $name: エンドポイントの名前
  • $places: エンドポイントが来る場所の指定。下のテーブルにあるリストを参照
  • $query_var: 対応するクエリ変数の名前。指定しない場合には$nameとおなじになる
名前 内容
EP_NONE なし
EP_PERMALINK 投稿のパーマリンク
EP_ATTACHMENT 投稿に添付されたファイルを表示するためのページ
EP_DATE Date アーカイブ
EP_YEAR 年別アーカイブ
EP_MONTH 月別アーカイブ
EP_DAY 日別アーカイブ
EP_ROOT ルートページ(トップページ)
EP_COMMENTS コメントページ
EP_SEARCH 検索結果ページ
EP_CATEGORIES カテゴリーアーカイブ
EP_TAGS タグアーカイブ
EP_AUTHORS 著者アーカイブ
EP_PAGES 固定ページ

また、EP_ALL_ARCHIVESは、EP_DATE | EP_YEAR | EP_MONTH | EP_DAY | EP_CATEGORIES | EP_TAGS | EP_AUTHORSと同じになり、EP_ALLEP_PERMALINK | EP_ATTACHMENT | EP_ROOT | EP_COMMENTS | EP_SEARCH | EP_PAGES | EP_ALL_ARCHIVESと同じになります。

たとえば、URLの末尾に/jsonをつけるとページの情報をjsonで返すAPIを作りたい場合を想定して説明します。

  • トップページの場合: http://example.com/json
  • 固定ページの場合: http://example.com/pagename/json
  • カテゴリーアーカイブの場合: http://example.com/category/my-cat/json
  • 投稿のページの場合: http://example.com/2014/04/26/sample-post/json

のように、エンドポイントjsonを登録して、末尾にjsonがある場合には、なんらかの処理を追加することができます。

add_rewrite_endpoint( 'json', EP_ALL );

また、add_rewrite_endpoint()は、エンドポイントの直後に来るスラッグを、エンドポイント名を変数名とする変数の値として使えるようにしてくれます。違う変数名にしたい場合は第三引数に名前を指定します。
たとえば、add_rewrite_rule()で説明したhttp://example.com/twitter/<username>へアクセスがあった場合にTwitter IDをもとに何かの情報を取得するような場合には、以下のように指定します。

add_rewrite_endpoint( 'twitter', EP_ROOT, 'twitter_id' );

リサイズされた画像のURLを返すAPIを作ってみる

それでは、add_rewrite_endpoint()を使って、アタッチメントページURLの末尾に/resize/<サイズ名>を追加したURLにアクセスすると画像アップロード時にWordPressがリサイズしたファイルへのパスを取得できる機能を作ってみましょう。

アタッチメントページのURLの末尾に/resize/large, /resize/thumbnailといったスラッグを付けて、リサイズされた画像を返す機能です。

もともとのアタッチメントページのURLは、http://example.com/archives/1/imgnameです。largeサイズの画像を返したい場合はhttp://example.com/archives/1/imgname/resize/largeにアクセスし、サムネイルサイズの画像を返したい場合は、http://example.com/archives/1/imgname/resize/thumbnailにアクセスします。

前述のとおり、add_rewrite_endpoint()はエンドポイントの名前を$wp_query->query_varsに登録し、エンドポイント直後のスラッグを値として渡します。http://example.com/archives/1/imgname/resize/thumbnailは、http://example.com/?attachment=imgname&resize=thumbnailにリライトされ、$resize=thumbnailをquery_varとして受け取ることができるということです。

<?php
add_action( 'init', 'add_resize_endpoint' );
function add_resize_endpoint() {
	add_rewrite_endpoint( 'resize', EP_ATTACHMENT );
}

add_action( 'template_redirect', 'resize_template_redirect' );
function resize_template_redirect() {

	// 変数として受け取れる値
	$resize = get_query_var( 'resize' );
	
	// 画像アップロード時にWordPressが作成する画像のサイズの名前を取得
	$image_sizes = get_intermediate_image_sizes();
	$image_sizes[] = 'full'; // 'full'も追加
	
	// $resizeが登録されていない時、あるいは、アタッチメントページが表示されていない時はそのまま返す
	if ( '' == $resize  || ! is_attachment() )
		return;

	$resize_img_src = wp_get_attachment_image_src( get_the_ID(), $resize );
	echo $resize_img_src[0];
	// exitしないと、アタッチメントページの表示に進んでしまう
	exit;
}
アタッチメントページの末尾に/resize/mediumを追加して、URLを取得できる
アタッチメントページの末尾に/resize/mediumを追加して、URLを取得できる

この例では、以下のWordPressの関数を使っています。

  • get_intermediate_image_sizes()
  • is_attachment()
  • wp_get_attachment_image_src()

add_rewrite_endpoint()を利用する方法の利点として、こうしたWordPressの機能を丸々使うことができるということがあります。

この例のようなURLを表示するだけではなく、ブラウザで閲覧されるウェブアプリを公開するような場合には、ツールバーも出ますし、他のプラグインもそのまま利用することができ、WordPressの機能をフル活用してアプリケーションを開発することが可能になるのです。

add_rewrite_tag()とadd_permastruct()

  • add_rewrite_tag( $tagname, $regex, $query ): 構造タグを追加する。引数はタグ名、とりうる値の正規表現、スラッグを置き換えるクエリ文字列。
  • add_permastruct( $name, $struct, $args ): ページネーションやフィードなどのリライトルールを含めてパーマリンク構造を追加する。引数は名前、構造、オプション。

構造タグとは、パーマリンク設定のページで使われる、%year%や%post_id%、%category%などのタグのことです。
パーマリンク構造とは、構造タグを並べて、組み合わせて作るURLの構造のことです。add_permastruct()の第三引数では、以下を配列で指定することができます。

キー 内容
with_front WP_Rewrite::$front(投稿のパーマリンク構造/archive/などの静的な部分)を付けるかどうかを真偽値で指定。デフォルトはtrue
ep_mask エンドポイントマスク。整数値で指定。デフォルトはEP_NONE
paged アーカイブで、ページネーションのためのパーマリンク構造(/page/2など)をサポートするかどうかを真偽値で指定。デフォルトはtrue
feed フィードのためのパーマリンク構造(/feed/atomなど)をサポートするかどうかを真偽値で指定。デフォルトはtrue
forcomments (boolean) Should the feed rules be a query for a comments feed? Default is false.
walk_dirs (boolean) Should the ‘directories’ making up the structure be walked over and rewrite rules built for each in turn? Default is true.
endpoints 生成されたリライトルールでエンドポイントをサポートするかどうかを真偽値で指定。デフォルトはtrue

次のコードは、bookというカスタム投稿タイプを追加していて、投稿のパーマリンク構造とは別の構造にしたい場合のものです。投稿は、/archive/%post_id%であったとしても、カスタム投稿タイプbookでは、'/books/%year%/%monthnum%/%book%';とすることができます。フィードは提供しない設定を第三引数で指定しています。

add_action( 'init', 'add_book_tag_permastruct' );
function add_book_tag_permastruct() {
	add_rewrite_tag( "%book%", '([^/]+)', "book=" );
	$book_struct = '/books/%year%/%monthnum%/%book%';
	add_permastruct( 'book', $book_struct, array( "feed" => false ) );	
}

以上のように設定を行った後、flush_rewrite_rules()などが実行されると、必要なリライトルールがまとめて保存されます。

add_feed()を利用してRSSフィードを拡張してJSONを返せるようにする

この項目は、第15章プラグイン・クックブックに詳しく掲載されています

flush_rewrite_rules()

リライトルールやエンドポイントの追加と活用について見てきました。

ここまで触れてきませんでしたが、これらが有効に働くようにするためには、プラグインによるリライトルールの追加時に、WordPressのデータベースにtransientキャッシュとして登録されているリライトルールを変更する処理を加えなければなりません。

flush_rewrite_rules( $hard )は、キャッシュされているリライトルールを削除し、カスタム投稿タイプやプラグインによるリライトルールの追加などを反映した新しいものを保存し直す関数です。引数の$hardは真偽値をとり、trueあるいは未指定の場合にはapacheの.htaccess、IISのweb.configも更新します。falseの場合にはデータベースのみの更新です。通常はfalseで大丈夫です。

プラグインからリライトルールの追加を行う場合には、プラグインの有効化時にリライトルールを書き換え、プラグインの無効化時に追加したものを削除する必要があります。

ただし、いくつか注意すべきことがあり、プラグインの有効化時と無効化時のフックだけでフラッシュする記述だと以下の場合に、プラグインのリライトルールが消えてしまいます。

  • 管理者によってパーマリンク設定のページが開かれたためflush_rewrite_rules()が実行される
  • 他のプラグインによってflush_rewrite_rules()が実行される

また、wp-cliからプラグインが無効化された場合には、プラグイン独自のリライトルールは消されずに残ってしまいます。そのため、現在のところ以下のようなやり方をしておいてください。

(上記を考慮したプラグインの書き方は、書籍の購入か、ソース配布ページに該当部分がUPされるのをお待ちください。)

コピペ部分、以上です。

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

コメントを残す

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

Rewrite APIその2 WordPressでアプリを作る基本(WordPressプラグイン開発のバイブルのボツ原稿から)」への3件のフィードバック