WordPress の記事内にちょっとした JavaScript を記述しようと思ったのだが、なかなかうまくいかなかったので、WordPress の動作と JavaScript を記述する方法を検証してみた。
※本記事は WordPress 3.7.1–ja を利用したときに掲載した記事です。
WordPress の処理
WordPress は記事内の文字列をそのまま出力しているわけではなく、整形して出力している。JavaScript を記述する上で影響のありそうな処理をまとめる。
- 改行コードは<br/>に置き換える
- & は> & に変換する
onclick ハンドラーや、<script/>タグなどは削られないようだ。
ただし、onclick ハンドラーを書いて Chrome で「プレビュー」ボタンを押すと、以下のような警告が表示される。
The XSS Auditor refused to execute a script in 'https://www.united-bears.co.jp/blog/?p=2049&preview=true' because its source code was found within the request. The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.
Chrome のクロスサイトスクリプティング対策にひっかかって、ハンドラーの中身を消されてしまう。XSS Auditor の動作はきちんと調べていないので不明な点が多いのだが、「プレビュー」ボタンを押さずに URL を直接指定すれば動作する。警告の内容通り、リクエストに含まれる内容と HTML を比較し、リクエストに含まれる内容が直接出力された場合、チェックに引っかかるようだ。なお、対策は書いてあるとおり「X-XSS-Protection」か「Content-Security-Policy」ヘッダーを出力すればいいらしい。
JavaScript の記述
注意事項と対策
JavaScript を記述する際の注意事項は、2つ。
- 無駄な改行コードを含めない。2つ以上改行コードが続くと<br/>に変換されてしまい、エラーになる
- & を利用しない
最初の注意事項は、ソースコードが見にくくなる可能性があることを除けばなんの問題もない。2つめは少しやっかいだ。論理積(&)と、論理演算子(&&)が使えないからだ。
論理演算子の方は、if 文をネストするか ? 演算子を使えばよいだけなので、それほど難しくない(コードは汚くなるが)。
if(condition1 && condition2) { return true } if(condition1) { if(condition2) { return true } } return condition1 ? (condition2 ? true : false) : false;
論理積(&)を使えない問題は、ド・モルガンの法則でしのいだ。
return m & n; return ~(~m | ~n);
JavaScript を記述した例
Chrome の XSS Auditor にひっかかると面倒なので(ほかのブラウザも引っかかるかもしれない)、タグにはイベントハンドラーを追加せず、<script/>タグに JavaScript を記述する方法を選んだ。WordPress には jQuery が含まれているので、jQuery も活用することにした。実際の例は、本ブログのツールカテゴリーにある。
一番単純な、「UNIX time と日時表記(地方時)の相互変換」の記事に記述された JavaScript を抜粋してみた。
<script type="text/javascript" src="/blog/wp-includes/js/jquery/jquery.js"></script> <script type="text/javascript"> jQuery(document).ready(function(){ var WEEK_DAY = ['日', '月', '火', '水', '木', '金', '土', '日']; var now = new Date(); jQuery('#unixtime_now').html(now.getTime()); jQuery('#localtime_now').html( now.getFullYear() + '/' + ('0' + (now.getMonth() + 1)).slice(-2) + '/' + ('0' + now.getDate()).slice(-2) + '(' + WEEK_DAY[now.getDay()] + ') ' + ('0' + now.getHours()).slice(-2) + ':' + ('0' + now.getMinutes()).slice(-2) + ':' + ('0' + now.getSeconds()).slice(-2) + '.' + ('000' + now.getMilliseconds()).slice(-3) ); jQuery('#show_unixtime').click(function() { var result = jQuery('#unixtime_result'); result.html(''); var input = jQuery('#unixtime').val(); if(!input) { result.html('ミリ秒を入力してください。'); return; } ... 以下略 }); </script>
ちょっと見にくいが & を使えないことをのぞき、普通に JavaScript をかけるようだ。