I have finally managed to combine all my WordPress Javascript from my theme and plugins into a single bundle using the function below:
function merge_all_scripts() {
global $wp_scripts;
$wp_scripts -> all_deps($wp_scripts -> queue);
$merged_file_location = get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'merged-script.js';
$merged_script = '';
foreach( $wp_scripts->to_do as $handle) {
$src = strtok($wp_scripts->registered[$handle]->src, '?');
if (strpos($src, 'http') !== false) {
$site_url = site_url();
if (strpos($src, $site_url) !== false) $js_file_path = str_replace($site_url, '', $src);
else $js_file_path = $src;
$js_file_path = ltrim($js_file_path, '/');
} else {
$js_file_path = ltrim($src, '/');
}
if (file_exists($js_file_path)) {
$localize = '';
if (#key_exists('data', $wp_scripts->registered[$handle]->extra)) {
$localize = $obj->extra['data'] . ';';
}
$merged_script .= $localize . file_get_contents($js_file_path) . ';';
}
}
file_put_contents ( $merged_file_location , $merged_script);
wp_enqueue_script('merged-script', get_stylesheet_directory_uri() . '/merged-script.js', array(), '1.0', false );
foreach( $wp_scripts->to_do as $handle ) {
wp_deregister_script($handle);
}
}
add_action( 'wp_enqueue_scripts', 'merge_all_scripts', 99 );
Problem is it erases all inline woocommerce js defined in the "get_script_data" woocommerce function. I want it to include that aswell.
Otherwise content such as this will not get injected into the DOM, and therefore prevent the site from working properly:
var wc_add_to_cart_params = {"ajax_url":"\/wp-admin\/admin-ajax.php","wc_ajax_url":"\/?wc-ajax=%%endpoint%%","i18n_view_cart":"Se kurv","cart_url":"https:\/\/lawrence.dk\/bag\/","is_cart":"","cart_redirect_after_add":"no"};
I have a gltf model that I am loading into my website using the Babylon 3D Viewer for WordPress plugin, and I would like to defer the script so that it isn't affecting my load time. All of the plugins I found for async/deffering Javascript seem to not apply to 3rd party scripts like the one this plugin imports (from this url: https://cdn.babylonjs.com/viewer/babylon.viewer.js).
Is there any other way I can defer the script?
One way you might be able to do this is with the script_loader_tag filter. See below:
function mind_defer_scripts( $tag, $handle, $src ) {
// array of scripts to add defer tag to
$defer = [
'https://cdn.babylonjs.com/viewer/babylon.viewer.js'
];
// check if current script should be deferred
if ( in_array( $src, $defer ) ) {
return '<script src="' . $src . '" defer="defer" type="text/javascript"></script>' . "\n";
}
return $tag;
}
add_filter( 'script_loader_tag', 'mind_defer_scripts', 10, 3 );
Note if you know the "handle" you could use that in-place of src like below:
function mind_defer_scripts( $tag, $handle, $src ) {
// array of scripts to add defer tag to
$defer = [
'babylon'
];
// check if current script should be deferred
if ( in_array( $handle, $defer ) ) {
return '<script src="' . $src . '" defer="defer" type="text/javascript"></script>' . "\n";
}
return $tag;
}
add_filter( 'script_loader_tag', 'mind_defer_scripts', 10, 3 );
I'm creating a plugin for WordPress, when I use below code in plugin main file it load js in <head>, it works fine.
wp_enqueue_script ( 'custom-script', 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-v4- rtl/4.6.0-1/js/bootstrap.bundle.min.jsf');
but when I use it inside a function (for example show_form() ):
function show_form()
{
wp_enqueue_script ( 'custom-script', 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-v4- rtl/4.6.0-1/js/bootstrap.bundle.min.js');
require_once 'form.php';
}
it loads script at the bottom of the page (before </body>).
what's wrong with my code?
I need to enqueue script inside the <head> only when my form.php loads.
I know I can load script directly in form.php but i need to load script via wp_enqueue_script
When show_form() is called, you're already too far along in the execution path to go back and insert code into the head section.
Any JS you want to load should be fired on the wp_enqueue_scripts action. wp_enqueue_script() can be used to determine whether code loads in the head or footer of the site.
If there are two points at which you can insert code using wp_enqueue_script() and it's being inserted into the footer even though you haven't specified that, it's because you're calling enqueue script after the head scripts have been inserted.
You need to either determine whether a form is shown on the page earlier in the loading of the page or use your JS in a way that can be supported across the site.
Example:
function wpse_enqueue_form_scripts() {
if ( has_form() ) { // EXAMPLE... You need a way of determining this
wp_enqueue_script( 'custom-script', 'js url...');
}
}
add_action( 'wp_enqueue_scripts', 'wpse_enqueue_form_scripts' );
You're not following best practices.
Any script should be added to the Wordpress firing sequence via wp_enqueue_scripts() firing hook.
Fires when scripts and styles are enqueued.
Source # https://developer.wordpress.org/reference/hooks/wp_enqueue_scripts/
Furthermore, when you take a look at the wp_enqueue_script() function CODEX page you can see that it accept a bunch of arguments including a $in_footer variable.
$in_footer
(bool) (Optional) Whether to enqueue the script before instead of in the . Default false.
As a reminder you can also set a $deps variable.
$deps
(string[]) (Optional) An array of registered script handles this script depends on. Default value: array().
The proper way to enqueue for example Bootstrap 4.6.0 (in your case) is to add a dependency to Jquery and load both of them in the footer, not the header. As most of the time any related js action are unnecessary before the DOM as been fully loaded. In the following example I will be enqueuing both Jquery and Bootstrap in the footer, tho you can alway change true to false.
As you're using a CDN you should be checking is the source is available and have a fallback locally waiting. you should also include integrity and crossorigin attributes.
add_action( 'wp_enqueue_scripts', 'plugin_scripts' );
function plugin_scripts() {
/**
* Deregister Wordpress jquery core version.
* #link https://developer.wordpress.org/reference/functions/wp_deregister_script/
*/
wp_deregister_script( 'jquery' );
/**
* Register then enqueue jquery_js (Bootstrap 4.6.x required).
* #link https://developer.wordpress.org/reference/functions/wp_register_script/
* #link https://developer.wordpress.org/reference/functions/wp_enqueue_script/
*
* Check if CDN's url is valid, if not return fallback.
* #link https://www.php.net/manual/en/function.fopen.php
*
* Add rel='preload prefetch' <link> and required attributes to bootstrap_bundle_js.
* Filters the HTML link tag of an enqueued style & add required attributes.
* #link https://developer.wordpress.org/reference/hooks/script_loader_tag/
*/
$url_jquery_js = 'https://code.jquery.com/jquery-3.5.1.slim.min.js';
$ver_jquery_js = '3.5.1-slim-min';
$tst_jquery_js = #fopen( $url_jquery_js, 'r' );
$hnd_jquery_js = 'jquery_js';
if ( $tst_jquery_js !== false )
wp_register_script( $hnd_jquery_js, $url_jquery_js, [], $ver_jquery_js, true );
else
wp_register_script( $hnd_jquery_js, trailingslashit( get_template_directory_uri() ) . 'assets/js/jquery-3.5.1.slim.min.js', [], $ver_jquery_js, true );
wp_enqueue_script( $hnd_jquery_js );
add_filter( 'script_loader_tag', 'data_jquery_js', 10, 3 );
function data_jquery_js( $tag, $handle, $src ) {
if ( $handle === 'jquery_js' ) {
$integrity = 'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj';
$tag = str_replace(
[ "<script",
"></script>", ],
[ "<link rel='preload prefetch' href='" . esc_url( $src ) . "' as='script' integrity='" . $integrity . "' crossorigin='anonymous' />" . PHP_EOL . "<script",
"integrity='" . $integrity . "' crossorigin='anonymous'></script>", ],
$tag
);
};
return $tag;
};
/**
* Register then enqueue bootstrap_bundle_js (Bootstrap 4.6.x required).
* #link https://developer.wordpress.org/reference/functions/wp_register_script/
* #link https://developer.wordpress.org/reference/functions/wp_enqueue_script/
*
* Check if CDN's url is valid, if not return fallback.
* #link https://www.php.net/manual/en/function.fopen.php
*
* Add rel='preload prefetch' <link> and required attributes to bootstrap_bundle_js.
* Filters the HTML link tag of an enqueued style & add required attributes.
* #link https://developer.wordpress.org/reference/hooks/script_loader_tag/
*/
$url_bootstrap_bundle_js = 'https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/js/bootstrap.bundle.min.js';
$ver_bootstrap_bundle_js = '4.6.0';
$tst_bootstrap_bundle_js = #fopen( $url_bootstrap_bundle_js, 'r' );
$hnd_bootstrap_bundle_js = 'bootstrap_bundle_js';
if ( $tst_bootstrap_bundle_js !== false )
wp_register_script( $hnd_bootstrap_bundle_js, $url_bootstrap_bundle_js, [ 'jquery_js', ], $ver_bootstrap_bundle_js, true );
else
wp_register_script( $hnd_bootstrap_bundle_js, trailingslashit( get_template_directory_uri() ) . 'assets/js/bootstrap.bundle.min.js', [ 'jquery_js', ], $ver_bootstrap_bundle_js, true );
wp_enqueue_script( $hnd_bootstrap_bundle_js );
add_filter( 'script_loader_tag', 'data_bootstrap_bundle_js', 10, 3 );
function data_bootstrap_bundle_js( $tag, $handle, $src ) {
if ( $handle === 'bootstrap_bundle_js' ) {
$integrity = 'sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns';
$tag = str_replace(
[ "<script",
"></script>", ],
[ "<link rel='preload prefetch' href='" . esc_url( $src ) . "' as='script' integrity='" . $integrity . "' crossorigin='anonymous' />" . PHP_EOL . "<script",
"integrity='" . $integrity . "' crossorigin='anonymous'></script>", ],
$tag
);
};
return $tag;
};
};
I have script
<script src="js/app/script.js" charset="iso-8859-1"></script>
I need to enqueue this js in wordpress with charset. How can I do it ?
I tried do it like that
private static function includeScriptWithCharset($path, $charset){
// I need charset="iso-8859-1"
wp_enqueue_script ($path, plugins_url($path). " ". $charset);
}
I know this question is quite old now, however I have the answer for this, in case this still helps Serg, or helps anyone else who comes across this issue.
The way to do this is to use the WordPress 'script_loader_tag' hook as follows:
// First enqueue your scripts as follows:
wp_enqueue_script( 'my-script-handle', get_stylesheet_directory_uri() . '/some.js', array( 'jquery' ), '6.0');
wp_enqueue_script( 'my-other-handle', get_stylesheet_directory_uri() . '/someother.js', array( 'jquery' ), '6.0');
// Next use the script loader hook as follows:
function my_async_scripts( $tag, $handle, $src ) {
// the handles of the enqueued scripts we want to async
$async_scripts = array( 'my-script-handle', 'my-other-handle' );
if ( in_array( $handle, $async_scripts ) ) {
return '<script type="text/javascript" src="' . $src . '" charset="iso-8859-1"></script>' . "\n";
}
return $tag;
}
add_filter( 'script_loader_tag', 'my_async_scripts', 10, 3 );
I have various javascripts that are necessary plugins in one of my WordPress domains, and I know where in the php file it's called from.
I'm taking every measure I can take to speed up page loading times, and every speed tester on the web says to defer javascripts if possible.
I have read about the defer='defer' and the async functions in javascript and I think one of these will accomplish what I'm trying to accomplish. But I'm not understanding how I'd do so in a php file.
For instance, here is a snippet from one particular plugin's php file where the javascript file is being called:
function add_dcsnt_scripts() {
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'dcsnt', dc_jqsocialtabs::get_plugin_directory() . '/js/jquery.social.media.tabs.1.7.1.min.js' );
}
I've read that it's best to do something like this for faster page loading times:
<script defer async src="..."></script>
But I don't know how to accomplish that within a php file. I want to do this with all of my javascript files.
How would I accomplish deferring or asyncing this javascript snippet to is loads last and speeds up page load times? What would be the ideal way to increase page load times across all browsers? Thanks for any guidance anybody can offer!
Or more universal way:
function add_async_forscript($url)
{
if (strpos($url, '#asyncload')===false)
return $url;
else if (is_admin())
return str_replace('#asyncload', '', $url);
else
return str_replace('#asyncload', '', $url)."' async='async";
}
add_filter('clean_url', 'add_async_forscript', 11, 1);
so you can add async to any script without code changes, just add #asyncload to script url as:
wp_enqueue_script('dcsnt', '/js/jquery.social.media.tabs.1.7.1.min.js#asyncload' )
Trying to keep things somewhat modular and all encompassing, the following approach dynamically chooses how to embed the tag with the async or defer attributes by just appending a small identifier to the $handle name:
/**
* Add async or defer attributes to script enqueues
* #author Mike Kormendy
* #param String $tag The original enqueued <script src="...> tag
* #param String $handle The registered unique name of the script
* #return String $tag The modified <script async|defer src="...> tag
*/
// only on the front-end
if(!is_admin()) {
function add_asyncdefer_attribute($tag, $handle) {
// if the unique handle/name of the registered script has 'async' in it
if (strpos($handle, 'async') !== false) {
// return the tag with the async attribute
return str_replace( '<script ', '<script async ', $tag );
}
// if the unique handle/name of the registered script has 'defer' in it
else if (strpos($handle, 'defer') !== false) {
// return the tag with the defer attribute
return str_replace( '<script ', '<script defer ', $tag );
}
// otherwise skip
else {
return $tag;
}
}
add_filter('script_loader_tag', 'add_asyncdefer_attribute', 10, 2);
}
Example usage:
function enqueue_my_scripts() {
// script to load asynchronously
wp_register_script('firstscript-async', '//www.domain.com/somescript.js', '', 2, false);
wp_enqueue_script('firstscript-async');
// script to be deferred
wp_register_script('secondscript-defer', '//www.domain.com/otherscript.js', '', 2, false);
wp_enqueue_script('secondscript-defer');
// standard script embed
wp_register_script('thirdscript', '//www.domain.com/anotherscript.js', '', 2, false);
wp_enqueue_script('thirdscript');
}
add_action('wp_enqueue_scripts', 'enqueue_my_scripts', 9999);
Outputs:
<script async type='text/javascript' src='//www.domain.com/somescript.js'></script>
<script defer type='text/javascript' src='//www.domain.com/otherscript.js'></script>
<script type='text/javascript' src='//www.domain.com/anothercript.js'></script>
Thanks to #MattKeys #crissoca for inspiring my answer here.
This blog post links to two plugins of interest:
Asynchronous Javascript
Improve page load performance by asynchronously loading javascript using head.js
WP Deferred Javascripts
Defer the loading of all javascripts added with wp_enqueue_scripts, using LABJS (an asynchronous javascript library).
Haven't tested them but checked the code and they do pretty fancy stuff with WordPress scripts enqueuing process.
But then WPSE comes to rescue:
// Adapted from https://gist.github.com/toscho/1584783
add_filter( 'clean_url', function( $url ) {
if ( FALSE === strpos( $url, '.js' ) ) {
// not our file
return $url;
}
// Must be a ', not "!
return "$url' defer='defer";
}, 11, 1 );
Another solution using a different filter, which can be used to target a specific script handle:
function frontend_scripts()
{
wp_enqueue_script( 'my-unique-script-handle', 'path/to/my/script.js' );
}
add_action( 'wp_enqueue_scripts', 'frontend_script' );
function make_script_async( $tag, $handle, $src )
{
if ( 'my-unique-script-handle' != $handle ) {
return $tag;
}
return str_replace( '<script', '<script async', $tag );
}
add_filter( 'script_loader_tag', 'make_script_async', 10, 3 );
A simplified method. Add to your functions.php file to make make JavaScript asynchronous in Wordpress
// Make JavaScript Asynchronous in Wordpress
add_filter( 'script_loader_tag', function ( $tag, $handle ) {
if( is_admin() ) {
return $tag;
}
return str_replace( ' src', ' async src', $tag );
}, 10, 2 );
To gain control over which js files to defer and avoid conflicts you can append a variable to the url in the wp_register_script function like below.
wp_register_script( 'menu', get_template_directory_uri() . '/js/script.js?defer', array('jquery'), '1.0', true );
Then change the line:
if ( FALSE === strpos( $url, '.js' ))
To:
if ( FALSE === strpos( $url, '.js?defer' ))
The new filter looks like this.
add_filter( 'clean_url', function( $url )
{
if ( FALSE === strpos( $url, '.js?defer' ) )
{ // not our file
return $url;
}
// Must be a ', not "!
return "$url' defer='defer";
}, 11, 1 );
Very little modification code Mike Kormendy, which allows you to add 2 attributes at once:
// Async load
function add_asyncdefer_attribute($tag, $handle)
{
$param = '';
if ( strpos($handle, 'async') !== false ) $param = 'async ';
if ( strpos($handle, 'defer') !== false ) $param .= 'defer ';
if ( $param )
return str_replace('<script ', '<script ' . $param, $tag);
else
return $tag;
}
Result:
<script async defer type='text/javascript' src='#URL'></script>
I believe it's bad practice to defer/async WordPress jQuery. Better solution would be to exclude jQuery from the filter:
if (!is_admin()) {
add_filter( 'script_loader_tag', function ( $tag, $handle ) {
if ( strpos( $tag, "jquery.js" ) || strpos( $tag, "jquery-migrate.min.js") ) {
return $tag;
}
return str_replace( ' src', ' async src', $tag );
}, 10, 2 );
}
You can use defer instead of async
Incorporate the async attribute to the scripts so that they are only loaded once the whole page is loaded
<script type="text/javascript">
function ngfbJavascript( d, s, id, url ) {
var js, ngfb_js = d.getElementsByTagName( s )[0];
if ( d.getElementById( id ) ) return;
js = d.createElement( s );
js.id = id;
js.async = true;
js.src = url;
ngfb_js.parentNode.insertBefore( js, ngfb_js );
};
</script>
Source:Here
Something to add the clean_url filter solution, make sure to validate to use it only on the font-end maybe using if( ! is_admin() ){} popular plugins like ACF might give you a headache.
Update
Here is my modified version of the solution:
if( ! is_admin() ){
add_filter( 'clean_url', 'so_18944027_front_end_defer', 11, 1 );
function so_18944027_front_end_defer( $url ) {
if ( FALSE === strpos( $url, '.js' ) )
{ // not our file
return $url;
}
// Must be a ', not "!
return "$url' defer='defer";
}
}