JavaScriptテンプレートを使ってみた

(3.6.0以降)
JavaScriptテンプレートを使ってみた - AJAXレスポンスの処理方法を考える

説明

前回の記事」で取り上げた「WordPress Events and News」ウィジェットでは入力された地名のAJAX処理してその地名近隣のイベント情報を表示している。特に表示部分では「JavaScriptテンプレート」が採用されており、今更ながら調べてみた。

「JavaScriptテンプレート」は3.6から

「JavaScriptテンプレート」がいつ頃登場したのかを確認するため手持ちのアーカイブを検索したところ、バージョン3.6が一番古かった(3.6のリリースは2013年8月なので、ほぼ4年前ということになる)。このバージョンで「/wp-includes/js/wp-util.js(以降wp-util.js)」が追加され、この中に「JavaScriptテンプレート」関連の機能が記述されている。

今回はサイトのトップページに「JavaScriptテンプレート」を使って何かを表示させるプラグインを考えてみた(とりあえずは「JavaScriptテンプレート」の機能を確認できるところまで)。プラグインの作成にあたってはCODEXの「Javascript Reference/wp.template」を参考にした。

「wp-util.js」は登録済み

機能確認用に作ったプラグインは、サイドバーのサイト内検索フォームの下に「JavaScriptテンプレート」を使って何かを表示するもの。ソースコードは次の通りとなる。

$my_sample_widget = new my_sample_widget();

class my_sample_widget {
	public function __construct() {
		add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) );
		add_action( 'wp_footer', array( $this, 'footer' ), 9999 );
	}

	public function scripts() {
		wp_enqueue_script( 'wp-util' );
	}

	public function footer() {
?>
<script id="tmpl-fields" type="text/template">
<ul>
<# _.each( data.names, function ( name ) { #>
<# if ( 1 === name.escape ) { #>
<li data-value="{{name.value}}">{{name.value}}</li>
<# } else if ( 2 === name.escape ) { #>
<li data-value='{{name.value}}'>{{name.value}}</li>
<# } else { #>
<li>{{{name.value}}}</li>
<# } #>
<# } ); #>
</ul>
</script>
<script type="text/javascript">
( function($) {
	$(document).ready( function () {
		var param = { names: [ 
			{ value:'apple', escape: 1 },
			{ value:'banana', escape: 2 },
			{ value:'cherry' }
			] };
		var template = wp.template( 'fields' );
		$( '.widget_search' ).after( template( param ) );
	} );
} )( jQuery );
</script>
<?php
	}
}

使用しているアクションは2つ。1つ目は'wp_enqueue_scripts'アクションを使用して'wp-util'という名前で登録されているwp-util.jsを組み込む。2つ目は'wp_footer'アクションを使用してページの下部にJavaScriptテンプレート部分(Aパート)と、検索フォームの下にJavaScriptテンプレートをレンダリングするJavaScriptのプログラム部分(Bパート)を出力している。

JavaScriptテンプレートはidで紐づけ

Aパートはscript要素を使用する。id属性は'tmpl-'から始める任意の名前を付ける必要がある。type属性は参考ページは'text/html'になっているが、ここでは「WordPress Events and News」ウィジェットに習って'text/template'を指定している。

script要素内には実際のテンプレートの中身として各種HTML要素を記述するほか、次に示す3種類のテンプレート専用の補間要素が指定できる。

  • <# JavaScriptコード #>
    任意のJavaScriptコードを記述
  • {{ 変数名 }}
    エスケープ処理して出力する変数を記述
  • {{{ 変数名 }}}
    エスケープ処理せずに出力する変数を記述

上記のJavaScriptコード部分ではunderscore.jsのメソッドが使用可能で、ここでは配列のループ処理を行う_.eachメソッドを使用している。_.eachメソッドの第1パラメータで指定しているdataがJavaScriptテンプレートのレンダリング時に受け取るパラメータが格納された変数名となる。ちなみに、このコード部分にはconsole.logメソッドも記述できる。

BパートではjQueryでページの初期化時の処理内容を記述している(WordPressでは標準で'$'が使用できないため、こんな記述になる)。肝となるwp.templateメソッドの引数にはAパートで指定したidから'tmpl-'を取り除いた名前を指定し、レンダリング関数を動的に生成してtemplate変数に格納する。その後、template変数にテンプレートで処理するデータとして指定し、レンダリングしている。

レンダリング結果の考察

実際にレンダリングされた内容は次の通りとなる(便宜上、余分な空白・改行を削除)。

<ul>
<li data-value="apple">apple</li>
<li data-value="banana">banana</li>
<li>cherry</li>
</ul>

ここで気になったのは、bananaの属性値の部分。テンプレートの記述は'(シングルクォーテーション)だが、出力されたものは"(ダブルクォーテーション)に変換されている。これは(WordPressの?)JavaScriptテンプレートの仕様のようだ。

次にBパートのパラメータの'apple'を'<i>a</i>"p\'p&le'に変更してエスケープ処理を確認してみる。レンダリング結果は次の通りとなる(抜粋)。

<li data-value="<i>a</i>&quot;p'p&amp;le">&lt;i&gt;a&lt;/i&gt;"p'p&amp;le</li>

ご覧の通り、要素の属性値と要素の内容部分とでは異なるエスケープ処理が行われていることがわかる。また、属性値の囲みが"に変換されるためか、属性値内のエスケープ処理では'は何もされずにそのまま出力されている。

今度はエスケープ処理なし側を確認するため、パラメータの'cherry'を'c<i>h</i>"e\'r&ry'に変更してみる。

<li>c<i>h</i>"e'r&amp;ry</li>

ご覧の通り、&以外はそのまま出力されている。なぜ&が&に変換されたのか気になり、Aパートのul要素の前に次の内容を追加してみた。

<p>&</p>
<p>&amp;</p>
<p>&nbsp;</p>

こちらのレンダリング結果は次のようになった。

<p>&amp;</p>
<p>&amp;</p>
<p>&nbsp;</p>

1行目のp要素内の&は&amp;に変換されているが、そのほかはそのまま出力されている。&のエスケープ処理はテンプレート全体のレンダリング時に行われ、その際は&を含んだエンティティ表記以外(単独の&)を対象に処理しているようだ。

'と&の仕様は意識しておきたい

JavaScriptテンプレートについてはおおむねその機能や使い方は把握できた。JavaScriptテンプレートを利用する方がメンテナンスしやすいので、今後は積極的に利用していきたいと思う。悩ましいのは、データのエスケープ処理を行うタイミングかな。。。

お勧めコンテンツ

remove_shortcode(2010年11月12日 登録)

void remove_shortcode( string $tag )
ショートコードを削除する。

wp_schedule_single_event(2014年5月23日 登録)

void wp_schedule_single_event( int $timestamp, string $hook [ , array $args = array() ] )
一度だけ実行するアクションをスケジュールに登録する。

pings_open(2010年3月8日 登録)

bool pings_open( [ mixed $post_id = NULL ] )
投稿ページ(情報)がトラックバック・ピンバックを許可しているかを調べる。

get_post_status(2011年9月18日 登録)

mixed get_post_status( [ mixed $ID = '' ] )
投稿情報のステータスを取得する。なお対象の投稿情報が添付ファイル(タイプが'attachment')の場合は、その添付元の投稿情報のステータスを取得する。

_e(2010年6月17日 登録)

void _e( string $text [ , string $domain = 'default' ] )
現在のロケールに応じた翻訳テキストを表示する。

最終更新日時 : 2017-06-06 10:56