For a while now i had this urge to create plugin that is merging CSS and JS into one file on the go. Two months ago i stumbled onto job to find script that is causing the white screen for 100-200 ms when page finishes the loading. This website used WordPress and, had something like 32 scripts and 18 css files and was loading like crap. Theme was Salient and it had separate .js file for each easing effect. It took almost fifteen seconds to load and render everything. Theme wasn’t at fault here, but sure it added to the issue. Anyway, since then i had this wish and idea to create that plugin.

How hard can it be to create a plugin to loop through array, merge files, and then minify the content? Doing merge and minify every time page is loaded would strain server too much, so some kind of cache must be added. There’s also need for some options to control what files to include and what not. External and internal alike.

First we need is to make sure function for combining the css and js will run at the end of the action. This can be done by first running function to check last priority within wp_enqueue_scripts. With add_action functions are stored in $GLOBALS['wp_filter']['action_name']->callbacks. Priority is used as key to store array with function and number of arguments that function accepts.
Here’s the example for wp_enqueue_scripts:

Array
(
    [10] => Array
        (
            [0000000065f0efd90000000046cec743] => Array
                (
                    [function] => Closure Object
                        (
                        )

                    [accepted_args] => 1
                )

            [wordfence::enqueueAJAXWatcher] => Array
                (
                    [function] => wordfence::enqueueAJAXWatcher
                    [accepted_args] => 1
                )

        )

    [11] => Array
        (
            [twentyfifteen_header_background_color_css] => Array
                (
                    [function] => twentyfifteen_header_background_color_css
                    [accepted_args] => 1
                )

        )

    [1000] => Array
        (
            [wp_localize_jquery_ui_datepicker] => Array
                (
                    [function] => wp_localize_jquery_ui_datepicker
                    [accepted_args] => 1
                )

        )

)

And now all we need to do is return biggest key number, and add another action with said number as priority. Here’s the function in question:

ome way to know if file is modified so we can generate new file. Checking file last modification date time is an option but it needs to retrieve the file even if it’s just metadata. Luckily, WordPress has version argument for style and script that’s used as file argument for browser caching. This combined with handle name can be used as string for sha1 filename, and with this we can check if new file needs to be generated. This will also make file generation flexible because you can enqueue different styles/scripts on different pages.

Once we have filename checked and list of files that are in queue together with dependencies we can retrieve the content. We will retrieve content with file_get_contents. There’s a chance this function will return false instead of content so we need some fail safe mechanism. There’s already functionality to ignore the file so we can use that and merge both variables before checking it with fnmatch. We’ll use two variables for this because second var will be used for errors only and will update_option only on demand so next time when it’s trying to generate new file, it will ignore that file and not attempt to retrieve the content.

Since file will be in different directory, relative URLs won’t work. We need to convert that to the absolute URLs. After that all that’s left is combining, minifying the code, and of course writing the file.

Regex to find relative URLs is kinda complicated. We need to ignore http, https, data, and #refference (in case of clip-path: url(#clip-shape)).
Here’s the abomination that does that: /url\((?!\s*([\'"]?(((?:https?:)?\/\/)|(?:data\:?:)|(?:#))))\s*(.+?)\)/.
We then need to loop though matches, find if url is in different folder than file, get that folder from url from file location and replace it with absolute url.

For quite a while now plugin has been activated on one website and it works good.

Results are much better than anticipated. This is only with css enabled because i totally forgot that scripts can be enqueued in header and footer separately so we’ll need to change functions for js. This wouldn’t be a problem if some themes/plugins were not bad written and try to run jQuery in the middle of content, while page is still loading.

This post contains affiliate link, which means I will receive commission if you make a purchase using said link.