-
-
Save adamsilverstein/ec18b67a72ff74dec12624e989e23142 to your computer and use it in GitHub Desktop.
| <?php | |
| /** | |
| * Register scripts with a `defer` or `async` strategy in a backwards compatible manner. | |
| * | |
| * From WordPress 6.3 onwards, the `wp_register_script` function accepts an `$args` array that | |
| * can include a `strategy` key with a value of either `async` or `defer`. | |
| * | |
| * This helper function handles the backwards compatibility for older versions of WordPress. When a | |
| * `strategy` key is present in the `$args` array (and is either `defer` or `async`), the | |
| * `script_loader_tag` filter is used to add the attribute to the script tag. | |
| * | |
| * Note that for older versions of WordPress, dependencies is not considered - the attribute is added unconditionally. | |
| * | |
| * When support for WP<6.3 is no longer required, simply replace all instances of this function with | |
| * `wp_register_script()`. | |
| * | |
| * @see wp_register_script() | |
| * | |
| * @param string $handle Name of the script. Should be unique. | |
| * @param string|false $src Full URL of the script, or path of the script relative to the WordPress root directory. | |
| * If source is set to false, script is an alias of other scripts it depends on. | |
| * @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array. | |
| * @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL | |
| * as a query string for cache busting purposes. If version is set to false, a version | |
| * number is automatically added equal to current installed WordPress version. | |
| * If set to null, no version is added. | |
| * @param array|bool $args { | |
| * Optional. An array of additional script loading strategies. Default empty array. | |
| * Otherwise, it may be a boolean in which case it determines whether the script is printed in the footer. Default false. | |
| * | |
| * @type string $strategy Optional. If provided, may be either 'defer' or 'async'. | |
| * @type bool $in_footer Optional. Whether to print the script in the footer. Default 'false'. | |
| * } | |
| * @return bool Whether the script has been registered. True on success, false on failure. | |
| */ | |
| function wpnext_register_script( $handle, $src, $deps, $ver, $args ) { | |
| // If >= 6.3, re-use wrapper function signature. | |
| if ( version_compare( strtok( get_bloginfo( 'version' ), '-' ), '6.3', '>=' ) ) { | |
| wp_register_script( | |
| $handle, | |
| $src, | |
| $deps, | |
| $ver, | |
| $args | |
| ); | |
| } else { | |
| wp_register_script( | |
| $handle, | |
| $src, | |
| $deps, | |
| $ver, | |
| isset( $args['in_footer'] ) ? $args['in_footer'] : false | |
| ); | |
| if ( isset( $args['strategy'] ) ) { | |
| wp_script_add_data( $handle, 'strategy', $args['strategy'] ); | |
| } | |
| } | |
| } | |
| /** | |
| * Enqueue scripts with a `defer` or `async` strategy in a backwards compatible manner. | |
| * | |
| * From WordPress 6.3 onwards, the `wp_enqueue_script` function accepts an `$args` array that | |
| * can include a `strategy` key with a value of either `async` or `defer`. | |
| * | |
| * This helper function handles the backwards compatibility for older versions of WordPress. When a | |
| * `strategy` key is present in the `$args` array (and is either `defer` or `async`), the | |
| * `script_loader_tag` filter is used to add the attribute to the script tag. Note that | |
| * for older versions of WordPress, dependency is not managed and the attribute is added unconditionally. | |
| * | |
| * When support for WP<6.3 is no longer required, simply replace all instances of this function with | |
| * `wp_enqueue_script()`. | |
| * | |
| * @see wp_enqueue_script() | |
| * | |
| * @param string $handle Name of the script. Should be unique. | |
| * @param string $src Full URL of the script, or path of the script relative to the WordPress root directory. | |
| * Default empty. | |
| * @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array. | |
| * @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL | |
| * as a query string for cache busting purposes. If version is set to false, a version | |
| * number is automatically added equal to current installed WordPress version. | |
| * If set to null, no version is added. | |
| * @param array|bool $args { | |
| * Optional. An array of additional script loading strategies. Default empty array. | |
| * Otherwise, it may be a boolean in which case it determines whether the script is printed in the footer. Default false. | |
| * | |
| * @type string $strategy Optional. If provided, may be either 'defer' or 'async'. | |
| * @type bool $in_footer Optional. Whether to print the script in the footer. Default 'false'. | |
| * } | |
| */ | |
| function wpnext_enqueue_script( $handle, $src, $deps, $ver, $args ) { | |
| wpnext_register_script( $handle, $src, $deps, $ver, $args ); | |
| wp_enqueue_script( $handle ); | |
| } | |
| if ( version_compare( get_bloginfo( 'version' ), '6.3', '<' ) ) { | |
| add_filter( | |
| 'script_loader_tag', | |
| static function( $tag, $handle ) { | |
| $strategy = wp_scripts()->get_data( $handle, 'strategy' ); | |
| if ( in_array( $strategy, array( 'async', 'defer' ), true ) && false === strpos( $tag, $strategy) ) { | |
| $tag = str_replace( '<script ', '<script ' . $strategy . ' ', $tag ); | |
| } | |
| return $tag; | |
| }, | |
| 10, | |
| 2 | |
| ); | |
| } |
@adamsilverstein Here's a hybrid of the two approaches: https://gist.github.com/westonruter/9694840a1cb940e66bdfb650e34c325e
Also I think the wrapper for wp_enqueue_script() can reduce a lot of code by simply calling wp_enqueue_script() after calling the wrapper for wp_register_script().
@adamsilverstein Here's a hybrid of the two approaches: westonruter/9694840a1cb940e66bdfb650e34c325e
Great!
Also I think the wrapper for wp_enqueue_script() can reduce a lot of code by simply calling wp_enqueue_script() after calling the wrapper for wp_register_script().
Nice!
I'll update here based on that (except the WP_HTML_Tag_Processor bit so the code can work with older WP versions)
@adamsilverstein I would just suggest making the replacement logic a bit more robust, for example:
$tag = str_replace( '<script ', '<script ' . $args['strategy'] . ' ', $tag );This would prevent situations where the occurrence of ' src' somewhere in the string is mistakenly replaced, for example in this string:
<script src="/foo.js" class="foo-js src-local"></script>@adamsilverstein I would just suggest making the replacement logic a bit more robust, for example:
Good suggestion. Done!
Thanks for the feedback!
Right, that makes sense. I like how your approach only adds a single filter, that is much cleaner. I don't think I'll use
WP_HTML_Tag_Processorthough since it might not be available and thestr_replaceapproach already feels reliable and performant.I also like the wrapper functions because they maintain the same function signature, making implementation simple.