WordPressでテーマやプラグインで使われるJavaScriptを遅延や非同期読み込みするために、clean_urlを使ってdeferやasyncの属性を付与していたのですが、WordPress6.4以降は問題が発生します。原因と対処策についてお伝えします。
もくじ
ある日PageSpeed Insightsで問題に気づく
ある日、PageSpeed Insightsでサイト速度の計測してみました。
そこで問題が起きていることに気がつきました。
「レンダリングをブロックしているリクエスト」の項目に、以前は表示されていなかったスクリプトまで表示されていることに気がつきました。
しかも、 js/jquery/jquery.min.js?ver=3.7.1' defer charset='UTF-8 のように文字化けしているかのようなURLが表示されていました。
WordPress6.4でURLがエスケープされる仕様変更
いろいろ調べて原因がわかりました。以下にあるように、WordPress 6.4から、scriptタグのURLがエスケープされる仕様になったためです。
Script loading changes in WordPress 6.4
これまで、scriptタグにdefer属性を不要する場合、以下のように、clean_urlフィルターを利用していました。
|
1 2 3 4 5 |
function add_async_to_enqueue_script($url) { if(FALSE === strpos($url, '.js')) return $url; return "$url' defer charset='UTF-8"; } add_filter('clean_url', 'add_async_to_enqueue_script', 11, 1); |
これを、子テーマのfunction.phpやオリジナルのプラグインのplugin.phpに記載します。
この手法は、本来のclean_urlの使い方ではなく、トリッキーな使い方ですが、以下など多くのサイトでこの方法が紹介されていて、私も使っていました。
async属性でレンダリングをブロックするJavaScriptにfunction.phpに記述で対処
WordPress6.4から、scriptタグのURLがエスケープされるようになったため、シングルクオテーションが、 ' に変換されてしまい、上述したURLになったということでしょう。
読み込まれなくなってしまえば、すぐに気がつけたのでしょうが、 ? 以降の全ての文字列がバージョン番号かのように機能したため、読み込みは同期で行われていて、しばらく気がつけませんでした。この間、多くの読者さんに、表示が遅いなぁと思わせてしまった可能性があります。
clean_urlを使う方法はもうダメ
あまり大幅な変更をしたくなかっため、clean_urlフィルターを使う方法でdeferやasyncを付与できないか検討しました。シングルクオテーションではなくダブルクオテーションはどうか、バックスラッシュでエスケープするのはどうか、など試しましたが、全部ダメでした。
正攻法は当該ファイルをenqueueし直す
WordPress6.3でdeferやasyncはJavaScriptを登録する wp_register_script() や wp_enqueue_script() で指定できるようになりました。
なので、テーマやプラグインでしっかりdeferやasyncを指定していない場合は、子テーマやオリジナルのプラグインで、 wp_enqueue_script() で指定し直すことで付与できます。
|
1 2 3 4 5 |
function re_enqueue_required(){ wp_enqueue_script('cps-common', get_template_directory_uri() . '/js/common.js', array('jquery'), false, array('in_footer' => true,'strategy' => 'defer',)); } add_action( 'wp_enqueue_scripts', 're_enqueue_required', 13 ); |
ちなみに、以下で説明したように、 wp_enqueue_script() の引数の中には、一度、 wp_deregister_script() してからでないと反映されないものもあります。
しかし、私が検証した結果、ここで変更したいstrategyという部分は、 wp_deregister_script() しなくても反映されます。
script_loader_tagフィルターを使う
ただ、上述したenqueueし直すという正攻法は、一個ずつ対応する必要があります。
例えば、新しいプラグインを導入したとして、そこで使われるJavaScriptにdeferやasync が付与されていない場合、その度に子テーマやオリジナルのプラグインを修正して対応する必要があります。
流石にそれは面倒臭いので、clean_urlのようにフィルターで全体に対応できたら楽です。以下の記事でscript_loader_tagでできることがわかりました。
[WordPress] script要素にdefer/asyncを付与する方法
こちらはclean_urlと違って、URLだけでなくタグ全体を編集できるので、URLのエスケープの影響を受けずにdeferやasyncを付与できます。
私の場合、ちょっと置換の方法を変えて以下のようにdeferを付与しています。
|
1 2 3 4 5 6 7 |
function add_async_to_enqueue_script($tag, $handle, $src) { if(FALSE === strpos($src, '.js')) return $tag; if(preg_match('/ async| defer/', $tag) === 1) return $tag; return str_replace( '"></script>', '" defer></script>', $tag ); } add_filter('script_loader_tag', 'add_async_to_enqueue_script', 10, 3); |
WordPressのアプデで悪い影響を受けないために
そもそも、WordPressのアップデートで、このような大きな変更がある場合、通知する仕組みがあれば良いのにと思いました。例えば、clean_urlフィルターを子テーマやプラグインで使っていれば、検知してアラートを出すなどはできるのではないでしょうか。
こちらで対応できることとしては、WordPressのアップデート時はPageSpeed Insightsで確認する習慣をつければ、このようなことを防げる可能性が高いので今後はしていきます。
さいごに
clean_urlフィルターを使ってasyncやdeferを付与していると起きる問題についてご説明しました。
上記の対処策で対応できますので、参考にしてみてください。