この記事は最後に更新してから1年以上経過しています。
説明
「前回の記事」で取り上げた「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コード部分では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>"p'p&le"><i>a</i>"p'p&le</li>
ご覧の通り、要素の属性値と要素の内容部分とでは異なるエスケープ処理が行われていることがわかる。また、属性値の囲みが"に変換されるためか、属性値内のエスケープ処理では'は何もされずにそのまま出力されている。
今度はエスケープ処理なし側を確認するため、パラメータの'cherry'を'c<i>h</i>"e\'r&ry'に変更してみる。
<li>c<i>h</i>"e'r&ry</li>
ご覧の通り、&以外はそのまま出力されている。なぜ&が&に変換されたのか気になり、Aパートのul要素の前に次の内容を追加してみた。
<p>&</p>
<p>&</p>
<p> </p>
こちらのレンダリング結果は次のようになった。
<p>&</p>
<p>&</p>
<p> </p>
1行目のp要素内の&は&に変換されているが、そのほかはそのまま出力されている。&のエスケープ処理はテンプレート全体のレンダリング時に行われ、その際は&を含んだエンティティ表記以外(単独の&)を対象に処理しているようだ。
'と&の仕様は意識しておきたい
JavaScriptテンプレートについてはおおむねその機能や使い方は把握できた。JavaScriptテンプレートを利用する方がメンテナンスしやすいので、今後は積極的に利用していきたいと思う。悩ましいのは、データのエスケープ処理を行うタイミングかな。。。
最終更新 : 2018年08月21日 09:37
お勧め
delete_post_meta(2018年5月27日 更新)
wp_is_numeric_array(2018年5月27日 更新)
get_tag_regex(2013年8月3日 更新)
get_all_page_ids(2012年5月30日 更新)
the_post_thumbnail_caption(2018年5月27日 更新)