wp_localize_script と wp_add_inline_script の違い|JSへ値を渡す方法

結論

PHP の値を JavaScript に渡す手段は主に2つあります。

  • wp_localize_script(): 翻訳文字列(ローカライズ)を渡す本来の用途向け。第3引数の配列を var 名前 = {...} の形で出力する。スカラー値が文字列になる。
  • wp_add_inline_script(): 任意の JS コードを、スクリプトの前(before)か後(after)に追加する。WordPress 4.5.0 で追加。型を保った JSON を渡せる。

公式リファレンスにも、wp_localize_script() は「実際に文字列をローカライズするとき」に使い、一般的なデータの受け渡しには wp_add_inline_script() を使うよう書かれています。新規実装なら、翻訳以外は wp_add_inline_script() に wp_json_encode() を組み合わせるのが無難です。

原因・仕組み

wp_localize_script() が内部で作る JS では、トップレベルのスカラー値は文字列になります。リファレンスにも、真は "1"、偽は空文字になる旨の記載があります。そのため、true を渡したつもりが JS 側で "1" になり、if ( cfg.debug === true ) が成立しない、という不具合が起こります。

出力位置も異なります。localize のデータは、対象スクリプトの直前に <script id="ハンドル-js-extra"> として出力されます。wp_add_inline_script() は、before を指定すると直前、after(既定)なら直後です。どちらも、対象のハンドルが登録(またはキューに追加)済みである必要があります。

手順(サンプルコード)

同じ設定値を、2つの方法で渡して比較する例です。

add_action( 'wp_enqueue_scripts', function () {
    wp_register_script( 'ks-main', get_theme_file_uri( 'js/main.js' ), array(), '1.0', true );
    wp_enqueue_script( 'ks-main' );

    $cfg = array(
        'ajaxUrl' => admin_url( 'admin-ajax.php' ),
        'perPage' => 10,
        'debug'   => true,
        'labels'  => array( 'ok' => '完了', 'max' => 3 ),
    );

    // 方法1: localize(翻訳文字列向け。数値・真偽が文字列になる)
    wp_localize_script( 'ks-main', 'ksLocalized', $cfg );

    // 方法2: inline(型を保つ。before で main.js より先に定義)
    wp_add_inline_script( 'ks-main', 'window.ksInline = ' . wp_json_encode( $cfg ) . ';', 'before' );
} );

翻訳文字列だけを渡すなら、localize も適切です。その場合は __() で翻訳した文字列を配列に入れます。

動作確認(検証環境と結果)

WordPress 7.1.2、PHP 8.2.12 で、フッターのスクリプト出力を取得しました(php C:Tempwp-testrun.php localize-script-vs-add-inline-script.php)。

  • localize の出力: var ksLocalized = {"ajaxUrl":"http://localhost/wp-admin/admin-ajax.php","perPage":"10","debug":"1","ratio":"1.5","labels":{"ok":"完了","max":3}};。トップレベルの perPage は "10"、debug は "1"、ratio は "1.5" と文字列になった。入れ子の labels.max は数値 3 のままだった。
  • inline(before)の出力: window.ksInline = {"ajaxUrl":"http://localhost/...","perPage":10,"debug":true,"ratio":1.5,...}。型が保たれた。
  • 出力順は、ks-main-js-extra(localize)、ks-main-js-before、本体の ks-main-js、ks-main-js-after の順になった。
  • 未登録のハンドル ks-nothing への wp_add_inline_script() と wp_localize_script() は、どちらも false を返し、何も出力されなかった。

ブラウザ上で JS の値の型を typeof で確認する検証は、行っていません。

wp_localize_script と wp_add_inline_script の違いの注意点

  • wp_add_inline_script() に <script> タグを含めてはいけません(含めるとタグが取り除かれる旨が公式に記載されています)。
  • JSON を渡すときは json_encode() ではなく wp_json_encode() を使います(wp_json_encode() の使い方|説明・引数・注意点)。
  • 渡す値に、ユーザー入力が含まれる場合、wp_json_encode は JS 文字列としては安全に出力しますが、JS 側で innerHTML に入れる処理でXSSにならないように注意します。
  • nonce は、キャッシュされるページに埋め込むと期限切れになります(wp_create_nonce() の使い方|説明・引数・注意点)。
  • 大きなデータをインラインで出すと、HTML が肥大化します。大量なら REST API で別取得にします。

wp_localize_script と wp_add_inline_script の違いでよくあるミス

  • wp_localize_script() を、対象ハンドルの登録(wp_register_script() または wp_enqueue_script())より前に呼び、何も出力されない(本検証でも未登録ハンドルへの呼び出しは false)。
  • true を渡して JS 側で === true と比較する。文字列の "1" になる。
  • wp_add_inline_script() を、wp_head の中の独立した場所で呼び、対象ハンドルが未登録のまま。
  • 変数名にハイフンを含める。JS の変数名として不正になります。
  • module 型のスクリプトにインラインでグローバル変数を渡し、スコープが合わない。

wp_localize_script と wp_add_inline_script の違いのチェックリスト

  • 翻訳文字列か、設定値かを判断したか。
  • 設定値なら wp_add_inline_script と wp_json_encode を使ったか。
  • 対象ハンドルは、呼び出し時点で登録済みか。
  • JS 側の型比較を、実際の出力に合わせたか。
  • ユーザー入力を含む値は、描画時にエスケープしているか。

wp_localize_script と wp_add_inline_script の違いのFAQ(よくある質問)

Q. wp_localize_script は非推奨ですか。
A. 公式リファレンスの時点では非推奨とはされていません。翻訳文字列以外の用途では、wp_add_inline_script が推奨されています。

Q. before と after はどう使い分けますか。
A. 本体が読み込まれる時点で変数が必要なら before、本体の関数を呼ぶ処理なら after を使います。

Q. 複数回呼べますか。
A. wp_add_inline_script は同じハンドルへ複数回追加でき、本検証でも before と after を併用できました。

筆者の見解(wp_localize_script と wp_add_inline_script の違い)

私見では、新しく書くコードで wp_localize_script を設定値の受け渡しに使う理由は、あまりありません。型が変わる挙動は、気づきにくい不具合の元だからです。ただし、既存のテーマやプラグインは localize を使っていることが多く、すぐ全部を書き換える必要まではないとも考えます。触るついでに、少しずつ置き換えるのが現実的です。

wp_localize_script と wp_add_inline_script の違いの関連項目

出典(一次情報)

タイトルとURLをコピーしました