エディター上でHTMLの属性値を全てエスケープする方法

プラグイン「WP Theme ShapeShifter Extensions」のTinyMCE機能で改善したことなんですが、ワードプレスのエディタ上では、ビジュアルエディタとHTMLエディタとの切り替え時に、HTMLの属性値が上手くエスケープされてない問題がありました。

まぁ今後改善されるのか、特に問題視していないのか知りませんが、例えばイメージファイルを追加する時、代替テキストに特殊文字が入っていると「エライこっちゃ」となってしまうんですよ。ええ、エスケープが一部解除されるんです。

参照:ビジュアルエディタとHTMLエディタの間の変換では、属性値のエンティティが解除される。

ええ、どこかでダウンロードしたイメージファイルの代替テキストなどに変なコードを入れられていて、それを使ってしまったら、どうするんだろと思ってしまいません?

もっと良い方法があるのかもしれませんが、とりあえず改善策の1つとして紹介していきます。

 

全ての要素の全ての属性値をエスケープする方法

まずはJavaScriptファイルがTinyMCEで読まれようにPHP側でコードを書きます。

add_action( 'admin_head', 'your_admin_head' );
function your_admin_head() {
	if ( 'true' == get_user_option( 'rich_editing' ) ) {
		add_filter( 'mce_external_plugins', 'your_mce_external_plugins' );
		add_filter( 'mce_buttons', 'your_mce_buttons' );
	}
}
function your_mce_external_plugins( $plugin_array ) {
	$plugin_array[ 'shapeshifter_button' ] = 'path/to/your-mce-javascripts.js';
	return $plugin_array;
}
function your_mce_buttons( $buttons ) {
	array_push( $buttons, 'shapeshifter_button' );
	return $buttons;
}

まぁこんな感じで良いんじゃないでしょうか?

最初の「get_user_option」はユーザー情報が取得できる時しか出来ませんので、「admin_head」などで呼び出してください。

 

JavaScriptファイルの編集

エスケープの方法ですが、ここではjQueryとUnderscore.jsを使用しており、jQueryの関数「attr」とUnderscore.jsの関数「escape」を使って、全ての要素の属性値をエスケープしています。

次に上の方法で読み込むファイルに以下のコードを記述します。

( function( window, jQuery, _ ) {
    tinymce.PluginManager.add( 'shapeshifter_button', function( editor, url ) {

        editor.on( 'GetContent', function( event ){

            // Escape
                $withWrapper = $( '<div class="tinymce-wrapper"></div>' ).append( event.content )
                event.content = escapeAttsValuesOnHTMLEditor( $withWrapper );

        });

        function escapeAttsValuesOnHTMLEditor( $eventContent ) {

            $eventContent.find( '*' ).each( function( index ) {

                // Data
                    var $this = $( this );
                    var atts = $this.context.attributes;
                    var attsNum = atts.length;

                // Exec
                    if( attsNum == 0 )
                        return;
                    for( var i = 0; i < attsNum; i++ ) {
                        $this.attr( atts[ i ].name, _.escape( $this.attr( atts[ i ].name ) ) );
                    }

            });

            return $eventContent.html();

        }

    });
}) ( window, jQuery, _ );

コード内の関数「escapeAttsValuesOnHTMLEditor」内では全てのエレメントを指定するセレクタ(アスタリスク)が使用されていますが、「img」など必要最低限の要素に絞ることも可能です。

僕は上のコードはボタンを追加するのに使っているファイルの一部を切り取っただけなのですが、恐らく大丈夫だと思います。

 

その他

もっと良い方法があれば知りたいんですが、まぁこれが一番簡単な方法じゃないかと思いました。

テーマのチェックでもエスケープをちゃんとしろと言いますが、これは特別視されないんでしょうかね。

一応補足としてですが、上記の方法は保存されるHTMLエディタ上に表示されるテキストをフィルターするもので、ビジュアルエディタのテキストに切り替わる時にかけられるフィルターではありません。

また、これは表示されるテキストをエスケープするものではなく、あくまでHTM要素の属性値をエスケープするものです。

表示されるテキストはワードプレスがエスケープしてくれますので、これは編集する必要はありません。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください