How to Combine CSS Files Into One File In WordPress
To speed up access to our websites, we need to minimize the number of HTTP requests, one way to achieve it is to combine CSS files, so, in this article, we’ll discuss how to combine CSS files in WordPress into one file.
As a WordPress user, using a lot of CSS files is an unavoidable thing, this happens because our theme uses various CSS file, in addition, some of our plugins also use separate CSS files, so that combining CSS file become a very important task.
I. How to Merge/Combine CSS files in WordPress manually
To combine CSS files manually, do the following steps:
- Identify CSS files that are used, the easiest way is open your web page and right-click on it and choose view source, in the source page, find (Ctrl + F) a word “stylesheet”
Notice the id of each style (as in the red box), the word before
-css
is the name of the CSS file handle, the handle is used by WordPress to identify each CSS files. - Next, open each CSS file by opening the link in the
href
attribute, then, copy-paste all CSS code into a single file, for example:merged-style.css
and place it in our theme directory that is being used, for example inwp-content\themes\wdc\merged-style.css
- Open the
functions.php
file in the theme directory and load themerged-style.css
file using the function:wp_enqueue_style('merged-style', get_stylesheet_uri (). '/merged-style.css')
- Deregister all CSS file handle that we have combined by using the function:
wp_deregister_style('handle-name')
. Done.
Although it looks simple, this method has a lot of drawbacks
Combining CSS files in WordPress manually has several drawbacks such as:
- If there are CSS files are added/removed, either when changing the theme or installing/uninstalling plugins, then we have to re-combine all of CSS files manually.
- Dependency between CSS file could not be guaranteed work well.
- The use of relative URLs such as in background image will potentially result an error (file not found) – explained later.
II. How to Combine CSS Files in WordPress Automatically
The better solution to overcome those disadvantages is to use an automated way, we can do this easily by using the WP_Styles
class that stored in the $wp_styles
variable
WP_Styles and $wp_styles
WP_Styles
and $wp_styles
are WordPress class(object) and built-in variable that are used to handle the entire styles that are loaded on a page, this class can be called on many WordPress hooks, like wp_enqueue_style
, wp_print_styles
, wp_head
, init
, etc.
To view the content of this object, open the functions.php file located in the theme directory, and then copy-paste the following code:
add_action('admin_enqueue_scripts', 'show_all_styles');
function show_all_styles()
{
// use global to call variable outside function
global $wp_styles;
// show all data
echo '<pre>'; print_r($wp_styles); echo '</pre>';
}
Next, open a web page, you’ll see the properties of this object either in an object
or array
form.
Note that there is a queue
property ($wp_styles->queue
), this property contains list of style handles that will be loaded on the page.
BUT these handles has not been sorted by its dependency, hence to be able to work properly, we need to re-arrange them using all_deps()
method, which we’ll discuss shortly.
Get all of the style handles based on its dependency
WP_Styles
object has a lot of method, one of them is all_deps
method. To see a complete list is of the methods, visit this page: Class Reference/WP Styles »WordPress Codex
This method will automatically sort the css files according its dependency and the results will be stored on the to_do
property ($wp_styles->to_do
)
The following code will print all styles sorted by its dependency:
add_action('wp_enqueue_scripts', 'show_all_styles');
function show_all_styles()
{
// use global to call variable outside function
global $wp_styles;
// arrange the queue based on its dependency
$wp_styles->all_deps($wp_styles->queue);
// The result
$handles = $wp_styles->to_do;
echo '<pre>'; print_r($handles); echo '</pre>';
}
Well, now the $handles
variable already contains all of the styles that have been sorted by its dependency, so it ready to use for processing the handles.
Combine all of the styles
Once we get all of the handle, then we ready to combine all of the CSS file.
Step we need:
- Combine all the css code on each css file and then save it in a file (e.g.
merged-styles.css
). To find the location of the css file: (1) find theregistered
property ($wp_styles->registered
), (2) Find the name of the handle in the array key ($wp_styles->registered['handle'])
and then find the URL path. - Load the merged file using
wp_enqueue_style()
function. - Deregister all CSS File handles that have already been merged using
wp_deregister_scripr()
function. - Copy-paste the following code into
functions.php
file in the theme directoryadd_action('wp_print_styles', 'show_all_styles'); function show_all_styles() { // use global to call variable outside function global $wp_styles; // arrange the queue based on its dependency $wp_styles->all_deps($wp_styles->queue); // The result $handles = $wp_styles->to_do; $css_code = ''; // New file location: E:xampp\htdocs\wordpress\wp-content\theme\wdc\merged-style.css $merged_file_location = get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'merged-style.css'; // loop all styles foreach ($handles as $handle) { /* Clean up the url, for example: wp-content/themes/wdc/style.min.css?v=4.6 become wp-content/themes/wdc/style.min.css */ $src = strtok($wp_styles->registered[$handle]->src, '?'); // #1. Combine CSS File. // If the src is url if (strpos($src, 'http') !== false) { // Get thr site url, e.g. http://webdevzoom.com/wordpress $site_url = site_url(); /* If the css file come from local server, change the full url into relative path For example: http://webdevzoom.com/wordpress/wp-content/plugins/wpnewsman/css/menuicon.css Become: /wp-content/plugins/wpnewsman/css/menuicon.css Otherwise, leave it as is, e.g: https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css */ if (strpos($src, $site_url) !== false) $css_file_path = str_replace($site_url, '', $src); else $css_file_path = $src; /* In order to be able to use file_get_contents function, we need to remove preceding slash, For example: /wp-content/plugins/wpnewsman/css/menuicon.css Become: wp-content/plugins/wpnewsman/css/menuicon.css */ $css_file_path = ltrim($css_file_path, '/'); } else { $css_file_path = ltrim($src, '/'); } // Check wether file exists then merge if (file_exists($css_file_path)) { $css_code .= file_get_contents($css_file_path); } } // write the merged styles into current theme directory file_put_contents ( $merged_file_location , $css_code); // #2. Load the URL of merged file wp_enqueue_style('merged-style', get_stylesheet_directory_uri() . '/merged-style.css'); // #3. Deregister all handles foreach ($handles as $handle) { wp_deregister_style($handle); } }
- Make sure everything goes well, open a web page and check the CSS file, there should only be one file, namely
merged-styles.css
Again, this way contain a serious drawbacks. The use of relative paths in the url, such as background-image
will cause a serious error “file not found”, this will potentially break our site layout
For example, css in a particular plugin uses an image from the img
directory inside the plugin directory, e.g. background: url('img/plg_logo.png')
, when we combine this css code and we place in the new location, for example in a theme directory, then for sure the plg_logo.png
file will not be found.
III. How to Combine CSS files in WordPress automatically – Fixing Relative Path
Next, we need to correct the relative path, so all CSS files will work properly.
We don’t need to write our own script to accomplish this task because it requires a fairly complex analysis (if you have times yo may do this task).
Instead, there are several libraries that are ready to use, but the problem is, not much of them up to date following the development of the CSS itself.
One that is quite up to date is “Path Converter” and Minify developed by Matthias Mullie, but in fact, we can not directly use it.
If we want to use path converter, first, we need to parse the CSS code to find the relative path, then use this tool to convert the URL.
Otherwise, if we wan’t to use the Minify, we need to write each css file to a file, this is the only way this tool convert the relative path automatically, this not efficient (especially with lots of css file), we want to combine all css files at once then write it to a file, instead.
So, we need a little modification:
- In
Minify.php
file, add/modufy the following script:abstract class Minify { private $toPath = ''; public function setToPath($path) { $this->toPath = $path; } public function minify($path = null) { $toPath = $this->toPath ?: $path; $content = $this->execute($toPath); // save to path if ($path !== null) { $this->save($content, $path); } return $content; } }
Or, you can download the final code here.
- But, you’ll want to check the latest version on github and then read the manual, if it still not support custom
from-to converter
, change theMinify.php
file according to the above code - While using Minify, don’t forget to include the “Path Converter” library which needed by the Minify to change the relative path automatically, just download the Converter.php file and placed it in the
src
directory - Further, copies all of the “Minify” file to our theme directory, e.g. wp-content/themes/yourtheme/Minify, the structure as shown below:
Combine and Minify
After modifying the file Minify.php
file, change our code that we have created earlier into the following:
add_action('wp_enqueue_scripts', 'show_all_styles');
function show_all_styles()
{
// use global to call variable outside function
global $wp_styles;
// arrange the queue based on its dependency
$wp_styles->all_deps($wp_styles->queue);
// The result
$handles = $wp_styles->to_do;
$css_code = '';
// New file location: E:xampp\htdocs\wordpress\wp-content\theme\wdc\merged-style.css
$merged_file_location = get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'merged-style.css';
//Including Minifylibrary
require_once('minify\src\Minify.php');
require_once('minify\src\CSS.php');
require_once('minify\Converter.php');
// loop all styles
foreach ($handles as $handle)
{
/*
Clean up the url, for example: wp-content/themes/wdc/style.min.css?v=4.6
become wp-content/themes/wdc/style.min.css
*/
$src = strtok($wp_styles->registered[$handle]->src, '?');
// #1. Combine CSS Files.
// If src is url
if (strpos($src, 'http') !== false)
{
// dapatkan site url, misal: http://jagowebdev.com/wordpress
$site_url = site_url();
/*
If the css file come from local server, change the full url into relative path
For example: http://webdevzoom.com/wordpress/wp-content/plugins/wpnewsman/css/menuicon.css
Become: /wp-content/plugins/wpnewsman/css/menuicon.css
Otherwise, leave it as is, e.g: https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css
*/
if (strpos($src, $site_url) !== false)
$css_file_path = str_replace($site_url, '', $src);
else
$css_file_path = $src;
/*
In order to be able to use file_get_contents function, we need to remove preceding slash,
For example: /wp-content/plugins/wpnewsman/css/menuicon.css
Become: wp-content/plugins/wpnewsman/css/menuicon.css
*/
$css_file_path = ltrim($css_file_path, '/');
}
else
{
$css_file_path = ltrim($src, '/');
}
// Cek wether file exists, then merge
if (file_exists($css_file_path)) {
$minifier = new MatthiasMullie\Minify\CSS($css_file_path);
$minifier->setToPath( $merged_file_location );
$css_code .= $minifier->minify($css_file_path);
}
}
// write the merged styles into current theme directory
file_put_contents ( $merged_file_location , $css_code);
// #2. Load the URL of merged file
wp_enqueue_style('merged-style', get_stylesheet_directory_uri() . '/merged-style.css');
// #3. Deregister all handles
foreach ($handles as $handle)
{
wp_deregister_style($handle);
}
}
Explanation:
- On line 19-21, we add the library files
- On line 66-68, we use the Minify class to minify the CSS files and simultaneously adjust the url path (if any) in accordance with the new location of the merged file (
merged-style.css
).
Done. Check whether the process works well. Open your web page and view it source, then open the merged-style.css
by clicking the href
attribute of <link>
tag.
Furthermore…
Despite we have successfully combined all css files, we need to consider other important matters, such as:
- The use of cache. Combining CSS file each time the page is loaded is not efficient at all, so we need to cache (server side cache) the merged file.
- Use dynamic file name. If we only use single file name and the file is cached by the browser, then if we generate new merged file, the browser will still use the old one because the file name is same, hence we need to change our merged file name each time we merging the CSS file.
- The use of other compressor tools such as YUI Compressor.
With the addition of those features, not relevant anymore if we still made it in the theme, so we need to separate it into a plugin.
To achieve that, you’ll want to develop your own plugins by learning the existing plugin, or use the existing one.
There are lot of plugins that do the such task, on of them is MinQueue, this plugin is nice but can not automatically combine all javascript and css files into one file, so I developed a plugin: APH Merge Script, you my want to give it a try.
Closing…
So far, we can combine CSS files in WordPress into one file using either manual way or automatic way.
The manual way is not recommended because it contains many-many drawbacks, while using the automatic way, we need to make some adjustments especially to the url path which is certainly not easy task.
Well, as an alternative, we can use a plugin such as MinQueue or APH Merge Scripts.
Subscibe Now
Loves articles on webdevzoom.com? join our newsletter to get quality article right to your inbox. Nothing else, just quality stuff!!!