WordPressではJavaScriptをHTMLの<script>に挿入するのにレジスタ・キューを使いますが、async, defer属性を付けるなどのカスタマイズにはちょっとした工夫が必要です。
今回は『WordPressらしい』方法で解決します。
いちばんかんたんな方法は『テンプレートに直書き』ですが、WordPressではスクリプトはレジスタとキューを使うしくみがあります。
これはインラインでも同じ。
キューに登録されたスクリプトの出力方法を変えることもできます。なぜレジスタとキューがあるのか考えてみましょう。これを使えってことです。
ということで、asyncとdeferを付けてみましょう。
asyncをつける
WPバージョン4.1以上
説明はあとにしてサンプルコードから。
function add_async() {
if ( is_admin() ) return;
add_action( 'script_loader_tag', function( $tag, $handle, $src ) {
$targets = [
// wp-includes/script-loader.php
'wp-embed', // wp-includes/js/wp-embed.min.js
// my create
'fontawesome', // https://kit.fontawesome.com/xxxxxxxx.js
// plugins
// jetapack
'mustache', // /wp-content/js/mustache.js?ver=8.3-202015
];
if ( in_array( $handle, $targets, true ) ) {
$tag = str_replace( '<script src=', '<script async src=', $tag );
}
return $tag;
}, 10, 3 );
}
'script_loader_tag' は、キューにあるスクリプトをHTML出力する直前に実行するフックです。
ここで<script>のフォーマットを変えます。
WordPressに組み込まれたものやプラグイン、自作したものでもOK。
$targetsでasyncを付けるスクリプトのハンドル・リストを作り、合致したものをstr_replaceで文字列置換します。
処理はたったこれだけ。
ちなみに、$targetsのハンドル名はWordPressやプラグインのソースをjsファイル名で検索して探しました。
(CSSはハンドル名がHTMLに出力されるが、スクリプトはそれがないのでちょっと面倒。)
次はdeferを付けます。お察しの人はもう分かったでしょう。上のコードを5文字変更するだけ。
管理画面はスクリプトの量がハンパないので使いません。(エラーが出まくるのが想像できる。)
また、function名はオリジナリティが必要です。今回のサンプルはクラス内で定義したものからもってきたのでシンプルですが。(add_async())
(あと、関数をむき出しするならfunction_exists()も必要。)
deferをつける
解説はいいかなとも思いますが、一応サンプルコードだけ。
function add_defer() {
if ( is_admin() ) return;
add_action( 'script_loader_tag', function( $tag, $handle, $src ) {
$targets = [
// wp-includes/script-loader.php
'jquery-core', // https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
'underscore', // /wp-includes/js/underscore.min.js
'backbone', // /wp-includes/js/backbone.min.js
'clipboard', // /wp-includes/js/clipboard.min.js
// themes
'pagetop', // /wp-content/themes/my-theme/lib/js/jquery.pagetop.js
'origin-script', // /wp-content/themes/my-theme/js/origin.js
'prism-script', // /wp-content/themes/my-theme/js/prism.js
// plugins
// jetpack
'postmessage', // /wp-content/plugins/jetpack/_inc/build/postmessage.min.js
'jetpack_resize', // /wp-content/plugins/jetpack/_inc/build/jquery.jetpack-resize.min.js
'jetpack-photon', // /wp-content/plugins/jetpack/_inc/build/photon/photon.min.js
'eu-cookie-law-script', // /wp-content/plugins/jetpack/_inc/build/widgets/eu-cookie-law/eu-cookie-law.min.js
'jetpack-lazy-images', // /wp-content/plugins/jetpack/_inc/build/lazy-images/js/lazy-images.min.js
'jetpack_likes_queuehandler', // /wp-content/plugins/jetpack/_inc/build/likes/queuehandler.min.js
'wpcom-notes-common', // /wp-content/mu-plugins/notes/notes-common-v2.js?ver=8.3-202015
'wpcom-notes-admin-bar', // /wp-content/mu-plugins/notes/admin-bar-v2.js
'google-translate-init', // /wp-content/plugins/jetpack/_inc/build/widgets/google-translate/google-translate.min.js
'google-translate', // //translate.google.com/translate_a/element.js?cb=googleTranslateElementInit
// contact-form-7
'contact-form-7', // /wp-content/plugins/contact-form-7/includes/js/scripts.js
// wordfence
'wordfenceAJAXjs', // /wp-content/plugins/wordfence/js/admin.ajaxWatcher.1581523568.js
// easy fancybox
'jquery-fancybox', // /wp-content/plugins/easy-fancybox/js/jquery.fancybox.js
'jquery-easing', // /wp-content/plugins/easy-fancybox/js/jquery.easing.js
'jquery-mousewheel', // /wp-content/plugins/easy-fancybox/js/jquery.mousewheel.js
];
if ( in_array( $handle, $targets, true ) ) {
$tag = str_replace( '<script src=', '<script defer src=', $tag );
}
return $tag;
}, 10, 3 );
}
deferをつけるスクリプトのポイントは、jQueryを使うなどロード順を守らなければいけないものを対象にします。
注意。インラインが消えないように
WordPressの公式ドキュメントもそうですが、こういう変更の仕方をよく見ます。
$tag = '<script type="text/javascript" src="' . esc_url( $src ) . '" id="dropboxjs" data-app-key="MY_APP_KEY"></script>';
これはいけません。$tagにはjsファイルのスクリプトだけでなく、インラインのスクリプトも含まれているから。
(インラインスクリプトがごっそり消える。)
script_loader_tagフックのパラメータにインラインがあればいいのですが、用意されていません。(WP5.4.1で確認。)
/**
* Filters the HTML script tag of an enqueued script.
*
* @since 4.1.0
*
* @param string $tag The `<script>` tag for the enqueued script.
* @param string $handle The script's registered handle.
* @param string $src The script's source URL.
*/
$tag = apply_filters( 'script_loader_tag', $tag, $handle, $src );
パラメータに追加されるのを待つのみです。
注意。動作確認をサボらない。
async, deferを付けたらスクリプトが正常に動作するのか確認しましょう。スクリプトの実行タイミングが変わるのでエラーになることがあります。
とくにjQueryまわりは注意。jQueryを使っているスクリプトはその前にjQuery本体のスクリプトがロードされている必要があります。
だからサンプルコードでも、jQueryまわりはロード順が不明なasyncではなく、ロード順を守ってくれるdeferを使っています。
それでもスクリプトエラーになることはあるので、エラーにならないことを確認しながら作業をしてください。