How to Combine Javascript Files in WordPress Into One File

Continuing the previous discussion on how to combine CSS files in WordPress, this time, we’ll discuss how to combine javascript files in WordPress into one file.

This process is part of the HTTP request optimization to increase the speed of the website which we discussed in a previous article: Optimization HTTP Request To Accelerate Loading Websites

I. How to Combine Javascript Files In WordPress – The Manual Way

The conventional way of combining javascript files in WordPress is done by viewing the source of web pages, searching (Ctrl + F) javascript file with the keyword “javascript”, and then copy-paste the script into a new javascript file.

This method is not recommended because has a lot of drawbacks, such as:

  • It’s hard to find the name of the javascript file’s handle, it’s unlike the CSS files where we can find the handle name on the id attribute. This handle is important as we need it to deregister the scripts after we finishing the merging process.
  • Lack of flexibility. If there is an addition or subtraction of a javascript file, then we have to re-combine the that file manually.
  • We can’t guarantee the dependency between files will be going well. This is related to the sequence of javascript file that should be loaded.

II. How to Combine Javascript Files In WordPress Automatically

Let’s leave the manual way and turn on to a more elegant way – automatic way.

To combine the javascript files in WordPresss automatically, first, we MUST know all of the javascript files along with its handle name loaded on the web page WITHOUT seeing the web source as we did in the manual way.

1 Knowing all of the javascript files loaded in a web page

We can find all of information about the javascript files loaded in a WordPress page in the WP_Scripts object.

This object is stored in the $wp_scripts variable, we can call this variable in any hook, such as wp_head, wp_print_scripts (now wp_enqueue_scripts), wp_footer, init, etc.

Each hook gives different results (the number of javascript file is different) depending on how we load the javascript files.

Clearly, there are two locations where we can find all javascript files, that are:

  1. In the header (<head> tag). We can determine this using the wp_head hook. WordPress run this hook before loading the <body> tag.
  2. In the footer (before the </body>) tag, We can determine this using the wp_footer hook. WordPress run this hook right before the closing </body> tag.

You can try this by opening the functions.php file located in the theme folder that is being used, for example wp-content/themes/wdc/functions.php, then copy-paste the following code:

add_action( 'wp_head', 'show_head_scripts', 9999 );
add_action( 'wp_footer', 'show_footer_scripts', 9999 );

// Appear on the top, before the header
function show_head_scripts(){
	global $wp_scripts;
	echo '<pre>'; print_r($wp_scripts->done); echo '</pre>';
}
// Appear on the bottom, after the footer
function show_footer_scripts(){
	global $wp_scripts;
	echo '<pre>'; print_r($wp_scripts->done); echo '</pre>';
}

Open your web page, you’ll see lists of script handles on the top and bottom of the page.

2 Combining javascript files into one file in WordPress

To be able to combine all javascript files into one file, we must know javascript files that can be detected automatically before our web content displayed.

For this purpose, we can use the wp_enqueue_scripts hook, although this hook has some weaknesses (described later), at least this is the only trick we can use.

Furthermore, to combine javascript files into one file, the necessary steps are:

  1. Sort the javascript file handles according to its dependency, so that the merged file(later) can run without any errors. We can do this by invoking the all_deps method on the WP_Scripts object ( $wp_scripts->all_deps($wp_scripts->queue) );
  2. Get the code within javascript file (using file_get_contents) and combine each of that code. Don’t forget to include the localize script wp_localize_script (if any). This script can be found in the $wp_scripts->registered['handle']->extra['data']
  3. Write the combined code into a file (using file_put_contents) and load it using the wp_enqueue_scripts function.
  4. Deregister all script/handle that have been combined, do this ONLY after the combined process is completed, this is because, if we deregister a script, then its dependent script will also be deregistered too.

Next, to do all of those tasks, copy-paste the following code into your functions.php file:

add_action( 'wp_enqueue_scripts', 'merge_all_scripts', 9999 );
function merge_all_scripts() 
{
	global $wp_scripts;
	
	/*
		#1. Reorder the handles based on its dependency, 
			The result will be saved in the to_do property ($wp_scripts->to_do)
	*/
	$wp_scripts->all_deps($wp_scripts->queue);	
	
	// New file location: E:xampp\htdocs\wordpresswp-content\theme\wdc\merged-script.js
	$merged_file_location = get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'merged-script.js';
	
	$merged_script	= '';
	
	// Loop javascript files and save to $merged_script variable
	foreach( $wp_scripts->to_do as $handle) 
	{
		/*
			Clean up url, for example wp-content/themes/wdc/main.js?v=1.2.4
			become wp-content/themes/wdc/main.js
		*/
		$src = strtok($wp_scripts->registered[$handle]->src, '?');
		
		/**
			#2. Combine javascript file.
		*/
		// If src is url http / https		
		if (strpos($src, 'http') !== false)
		{
			// Get our site url, for example: http://webdevzoom.com/wordpress
			$site_url = site_url();
		
			/*
				If we are on local server, then change url to relative path,
				e.g. http://webdevzoom.com/wordpress/wp-content/plugins/wpnewsman/css/menuicon.css
				become: /wp-content/plugins/wpnewsman/css/menuicon.css,
				this is for reduse the HTTP Request
				
				if not, e.g. https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css,
				then leave as is (we'll skip it)
			*/
			if (strpos($src, $site_url) !== false)
				$js_file_path = str_replace($site_url, '', $src);
			else
				$js_file_path = $src;
			
			/*
				To be able to use file_get_contents function we need to remove slash,
				e.g. /wp-content/plugins/wpnewsman/css/menuicon.css
				become wp-content/plugins/wpnewsman/css/menuicon.css
			*/
			$js_file_path = ltrim($js_file_path, '/');
		}
		else 
		{			
			$js_file_path = ltrim($src, '/');
		}
		
		// Check wether file exists then merge
		if  (file_exists($js_file_path)) 
		{
			// #3. Check for wp_localize_script
			$localize = '';
			if (@key_exists('data', $wp_scripts->registered[$handle]->extra)) {
				$localize = $obj->extra['data'] . ';';
			}
			$merged_script .=  $localize . file_get_contents($js_file_path) . ';';
		}
	}
	
	// write the merged script into current theme directory
	file_put_contents ( $merged_file_location , $merged_script);
	
	// #4. Load the URL of merged file
	wp_enqueue_script('merged-script',  get_stylesheet_directory_uri() . '/merged-script.js');
	
	// 5. Deregister handles
	foreach( $wp_scripts->to_do as $handle ) 
	{
		wp_deregister_script($handle);
	}
}

3 Make sure the combine process was succeeds


Further, check whether the merger process has been successful, open your web page, and view the source

If successful it will look like the following figure:

How to Combine Javascript FIles in WordPress - Result

Then, make sure the merged script has no errors, to do so, open the browser’s Developer Tools (Press F12 on Google Chrome) and select the console tab.

If there is no error, then the console will look like the following:

Chrome Console

If you find any errors, then double check the error message, make sure the error was caused by the javascript code in our merged script.

Examples of an error, but not caused by javascript code, instead, file not found: Failed to load resource: net::ERR_INTERNET_DISCONNECTED or Failed to load resource: the server responded with a status of 404 (Not Found)

4 Check the rest of the scripts that has not been merged

Check our web page source again, find (Ctrl+F) the word <script, if you find that only the merged script exists, then it’s fine, but sometimes  there are another scripts that are not merged, such as wp-embed.min.js and akismet.js

This is because those scripts are enqueued very late that we won’t able to catch it earlier.  This condition typically occurs on scripts that are loaded in the footer. If you use Akismet plugin and activate the comment post, then for sure you will face this as akismet.js is used in a comment form

How to solve it? the only way is we have to use the manual method

To do so, first, run wp_footer() hook and use $wp_scripts global variable to show all of the scripts, further, compare those scripts with scripts that have been combined to find the rest of the scripts, then, save those scripts to someplace e.q. a database table, next time, while merging javascript files, we include those files.

This way is quite long and complex, you can learn the APH Merge plugin script that I developed

Why we don’t use wp_footer() hook while merging javascript files?

Why don’t we use that hook? whereas using this hook we’ll know all scripts loaded in the page.

well, it’s right that on that hook, all javascript files can be detected, however, we can not use it because:

  1. We must deregister those scripts earlier add_action('wp_footer', 'deregister_scripts') while to be able to know all the files that are loaded, we need to run our function deregister_scripts  very late add_action('wp_footer','merge_all_scripts',999)
    Notice the number of 999, that number means that merge_all_scripts function will be loaded very late. Yet when it deregistered, the file will be lost, it can not be detected again.
  2. If we use wp_footer (), we can not put the merged file into the header, because it was too late, the header has already been executed.

Closing…

So far, We can combine javascript files in WordPress into one file easily.

But, in some situations (like the previous above), there are some files that can not be directly detected, such as: wp-embed.js and akismet.js.

It usually happens on a javascript file that is loaded very late on the footer.

The only way to overcome this is to use the manual way, save those file handles in someplace such as in a database table,  then while merging javascript files, we include those files.

In Addition, If you have no time to do such task, you may want to try APH Merge Scripts plugin that will take care all of this for us.

Subscibe Now

Loves articles on webdevzoom.com? join our newsletter to get quality article right to your inbox. Nothing else, just quality stuff!!!

24 Responses

  • Hi Agus!

    I have been trying to merge JS files into a single file, for days I was trying to do that with no success.

    Luckily I found this post of yours and your amazing APH Merge Scripts plugin!

    I just have a doubt now…

    After I merged the CSS and JS, what should I do next? O_o

    Thanks!

    • Hi Renato,
      Thank you for using my plugin

      There are several things to consider to speed up WordPress

      Some of them are:
      1. Enabling caching for static assets such as images, CSS, and javascript files by modifying .htaccess file. This will be difficult when the asset loaded from a third party server such as google analytics or facebook.

      2. Optimization picture. There are many plugins that can be used for this, such as Kraken.io

      3. Avoid render blocking render CSS. It is difficult to because we have to print CSS code in the header.

      4. Avoid render blocking javascript by putting all javascript files in the footer. This is not really safe because some plugins hard coded their javascript code (not using the WordPress API) — that depends on javascript library (jQuery) — in the body

      5. Decrease server response time by caching the page. This can be done by using w3 total cache plugin. However, this method has major drawbacks since most “popular post plugin” doesn’t work while using this kind of plugins.

  • Hello Agus,

    Thanks for this tutorial, it works fine but it doesn’t work with woocommerce. Also it doesn’t handle wp_localize_script correctly, it misses some data and vars.
    Is there any other way to get all localized data that created by other plugins ?

    Thanks.

    • Hi Awran, Thank you for your feedback

      I have tested this plugin with wp_localize_script and it’s working, but some plugin hard code their javascript manually so it can’t be detected automatically.

      Could you tell me what plugin that come with wp_localize_script and makes this plugin not work?

  • Thank you so much!
    I was trying to get access to a file in my wordpress theme usign file_get_contents but it was hard to insert the right relative path.
    This helped me to solve my problem
    /*
    To be able to use file_get_contents function we need to remove slash,
    e.g. /wp-content/plugins/wpnewsman/css/menuicon.css
    become wp-content/plugins/wpnewsman/css/menuicon.css
    */

    THANK YOU

  • Not working for me:
    1) There were problem with admin-ajax.php which was loaded as script, but has some php code. So I exluded that file:
    if (file_exists($js_file_path) && basename ($js_file_path) != ‘admin-ajax.php’)

    2) JQuery is not loaded as first and that made second problem.
    My script is called in this way:
    wp_enqueue_script(‘viewMore’, get_stylesheet_directory_uri() . ‘/js/viewMore.min.js’, array(‘jquery’), null, true);
    so – it’s calles in footer and with jquery as dependency.

    jQuery: I use version 3, so I had to change default version:
    =====
    wp_deregister_script( ‘jquery’ );
    wp_deregister_script( ‘jquery-core’ );
    wp_register_script( ‘jquery-core’, “//code.jquery.com/jquery-3.2.1.min.js”, array(), null );
    wp_deregister_script( ‘jquery-migrate’ );
    wp_register_script( ‘jquery-migrate’, “//code.jquery.com/jquery-migrate-3.0.0.min.js”, array(), null );
    wp_register_script( ‘jquery’, false, array( ‘jquery-core’, ‘jquery-migrate’ ), null );
    =====
    Maybe this is a source of problem with order?

    Regards

      • 1) Before exclude admin-ajax.php:
        Uncaught SyntaxError: Unexpected string
        /** Load WordPress Bootstrap */
        require_once( dirname( dirname( __FILE__ ) ) . ‘/wp-load.php’ );

        2) After excludin ajax:
        Uncaught ReferenceError: jQuery is not defined

      • 1) add new line after each merged script. One of scripts has last line like this:
        } //End ctf_js_exists check;
        so first line of next script was ignored!

        2) there was a problem with external files and “file_exists”. So I used file_get_contents without checking if file exists. I used “@” for hide warnings.

        My corrections:
        if ((
        $content = @file_get_contents($js_file_path) OR
        $content = @file_get_contents(‘https:’.$js_file_path) OR
        $content = @file_get_contents(‘http:’.$js_file_path)
        ) && basename($js_file_path) != ‘admin-ajax.php’)
        {
        // #3. Check for wp_localize_script
        $localize = ”;
        if (@key_exists(‘data’, $wp_scripts->registered[$handle]->extra)) {
        $localize = $obj->extra[‘data’] . ‘;’;
        }
        $merged_script .= $localize . ‘
        ‘. $content . ‘;’;
        }

        Other problem: file is generated for each site, for each user. It can make conflict… Maybe it will be better to do it once for a day (a week or a year)?

        And another one: MINIFICATION – mon js has 232 Kb before and 105Kb after minification…

  • this is an excellent post regarding merging js and it works flawlessly – you mention previously discussing merging css styles – i’ve searched your site high and low but cant find a post about it on your site.

    i tried to manipulate this js merge script example to combine css but wasnt successful – do you have any pointers to do it without a plugin?

    thanks in advance

    • Hi, I’m sorry, I forget to write that post. Merging CSS files easier than js file, because all CSS files loaded in the beginning.
      For the code, you can learn it by downloading aph-merge-script plugin and open the aphms-front.php file

      Things to consider are:
      – Be careful for url asset e.q.: background(‘../../img/background.jpg’) as it mostly relative path.
      – Notice the @import rule e.q @import url(‘css/bootstrap.min.css’) as we have to load that CSS file in the right order. Currently, aphms-front.php doesn’t accommodate that rule, I have fixed it but have no time to upload.

      For practice, you could try to work with the Prolog Blogging Theme http://demo.themeum.com/wordpress/prolog/

Leave a Reply to jay Cancel reply

Like Us

Newsletter

Great information from webdevzoom.com right to your inbox

We value your privacy

Social