WordPress

wp_enqueue_script(), wp_enqueue_style() のタグからtype属性を除いてHTML5ぽくしつつ、scriptタグでも条件付きコメントを使えるようにする方法

TABLEofCONTENTS

WordPress テーマの HTML5 化ネタ第1弾です。IE 向け script タグ条件付きコメント対応のおまけつき。

テーマを HTML5 にしてみた!けれど…

<!DOCTYPE html> から始まって <section> <article> を駆使して HTML5でテーマを作った!と思ったら、

  • wp_enqueue_style() して出力される link タグに type="text/css" がついていたり
  • wp_enqueue_script() して出力される script タグに type="text/javascript" がついていて

げんなりしてしまったこと、ありませんか? 私はあります。デフォルトのタイプ属性として定義済だから省略できるわけで、あっても間違いではないのですが、HTML ソースがシンプルになって気持ちがいいのも HTML5 の効果だとすれば、無くてもいいものは無い方がいいですね。
それじゃぁ、と header.php に直接タグを書こうとすると「それは違うよね」とどこからか声が聞こえてきます…
こんなときは WordPress カスタマイズ虎の巻 をひも解いてみましょう。

その壱 フィルターで書き換えるべし

スタイルの方は style_loader_tag というフィルターフックで link タグを書き換えることができます。

preg_replace( array( "| type='.+?'\s*|", '| />|' ), array( ' ', '>' ), $tag );

こんな感じで良さそうです。type 属性を削除するついでに />(これは何と呼ぶんでしょうか…)を > に置換しています。HTML5 的には /> でも良いのですが、無くてもいいものは無い方がいいルールに従ってシンプルに徹します。

一方、スクリプトの方は style_loader_tag に相当するフィルターが無く、タグがいきなり echo されています。困りましたね… WordPress カスタマイズ虎の巻 を読み進めましょう。

その弐 クラスを継承すべし

スクリプト関連の処理は WP_Scripts クラスが担っていて、必要になったときにこれを new したインスタンスがグローバル変数の $wp_scripts に代入されます。ということは、WP_Scripts クラスを継承して処理を書き換えてグローバル変数の $wp_scripts に突っ込めば、こちらの思うがままということになります。というわけで継承してみました。

継承ついでに header.php に html5.js の条件付きコメントを直書きしなくて済むようにしておきました。

スクリプトで条件付きコメントを使う

wp_enqueue_style() したスタイルは条件付きコメントで囲って link タグを出力することができます。wp_enqueue_styles アクションをフックして、

wp_enqueue_style( 'ie7', get_stylesheet_directory_uri() . '/css/ie7.css' );
$GLOBALS['wp_styles']->add_data( 'ie7', 'conditional', 'lte IE 7' );

とすれば、HTML ソースに、

<!--&#91;if lte IE 7&#93;>
<link rel='stylesheet' href='http://example.com/wp-content/themes/mytheme/css/ie7.css?ver=3.5' media='all'>
<!&#91;endif&#93;-->

のように出力されます。どちらかというとスクリプトの方が需要がある気がしますが、WordPress はスタイルしかサポートしていないため、上記の PM_Scripts クラスで実装しました。wp_enqueue_scripts アクションをフックして、

wp_enqueue_script( 'html5', get_stylesheet_directory_uri() . '/js/html5.js' );
$GLOBALS['wp_scripts']->add_data( 'html5', 'conditional', 'lt IE 9' );

とすれば、HTML ソースに、

<!--&#91;if lt IE 9&#93;>
<script src='http://example.com/wp-content/themes/mythemes/js/html5.js?ver=3.5'></script>
<!&#91;endif&#93;-->

のように出力されます。

IE のためだけの対応をしなくてよい未来は、もうすぐやってきますよ…きっと…

add_data() 豆知識

使う機会はあまりありませんが WP_Styles, WP_Scripts クラスの add_data() メソッドでいろいろなことができます。

$GLOBALS['wp_styles']->add_data( 'スタイルのID', 'alt', true );
        -----> link タグの rel 属性を rel='alternate stylesheet' にします
$GLOBALS['wp_styles']->add_data( 'スタイルのID', 'title', 'タイトルですよ' );
        -----> link タグに title='タイトルですよ' を追加します
$GLOBALS['wp_scripts']->add_data( 'スクリプトのID', 'data', 'JavaScript のコード' );
        -----> script タグの前にインラインでスクリプトを出力します。

wp_localize_script() 豆知識

話題がどんどんそれてますが、Ajax でポストするデータを PHP から JavaScript に渡すときに良く使う関数を紹介します。本来は wp_localize_script() の名のとおり、スクリプト内で使うテキストをローカライズするためのものだと思われます。なお、この関数は対象とするスクリプトを enqueue した後で呼ぶ必要があります。以下のように書くと、

wp_enqueue_script( 'my_script', get_stylesheet_directory_uri() . '/js/my_script.js' );

$params = array(
    'action'      => 'my_action'
  , '_ajax_nonce' => wp_create_nonce( 'my_action' )
  , 'post_id'     => $post->ID
);

wp_localize_script( 'my_script', 'my_var', array(
    'ajaxurl' => admin_url( 'admin-ajax.php' )
  , 'params'  => $params
) );

HTML ソースには以下のように出力されます。

<!--
var my_var = { json_encode() された変数の値 };
//-->

インラインの方は HTML5 ぽく CDATA を無くしてあります。これで my_script.js 内の JavaScript から my_var.ajaxurl my_var.params.action などの値を使うことができますね。

まとめ

style_loader_tag フィルターと PM_Scripts クラスの使い方は以下のとおり。ここでは link タグに付く ID も消しています。

WP_Styles, WP_Scripts, enqueue 関連は concat(enqueue された内容を連結して出力)の仕組みもあったりと、結構奥の深いつくりになっていますよ。ぜひコードを読んでみてください。
また、今回のクラスを継承してカスタマイズする方法は、適切なフックがない場合に有効なケースが多いです。覚えておいて損はないですよ。

ではまた。