How to Combine Javascript Files In WordPress without Plugin?
To combine the javascript files in WordPress with php and without Plugin, 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.
Table of Contents
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:
- In the
header
(tag). We can determine this using thewp_head
hook. WordPress run this hook before loading the tag. - In the footer (before the ) tag, We can determine this using the
wp_footer
hook. WordPress run this hook right before the closing tag.
You can try this by opening the functions.php file located in the theme folder that is being used.
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 print_r($wp_scripts->done); } // Appear on the bottom, after the footer function show_footer_scripts(){ global $wp_scripts; echo print_r($wp_scripts->done); }
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:
- 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)
) - Get the code within javascript file (using
file_get_contents
) and combine each of that code. Don’t forget to include the localizescript wp_localize_script
(if any). This script can be found in the extra data$wp_scripts->registered['handle']->extra['data']
- Write the combined code into a file (using file_put_contents) and load it using the
wp_enqueue_scripts
function. - 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); $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 */ $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 $site_url = site_url(); /* If we are on local server, then change url to relative path */ 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 */ $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); } }
Make sure the combine process succeeded
Further, check whether the merger process has been successful, open your web page, and view the source.
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 you find any errors, then double check the error message, make sure the error was not caused by the javascript code in our merged script.
Check the rest of the scripts that has not been merged
Check our web page source again and search if there are other scripts that are not being merged.
Some scripts are enqueued very late and we won’t be able to catch them 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.
Why not using wp_footer()
hook while merging javascript files?
It is true that on wp_footer
hook, all javascript files can be detected, however, we can not use it because:
- 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 functionderegister_scripts
very lateadd_action('wp_footer','merge_all_scripts',999)
Notice the number of999
, that number means thatmerge_all_scripts
function will be loaded very late. Yet when it deregistered, the file will be lost, it can not be detected again. - 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.