Selective enqueueing of WordPress scripts and styles through conditional loading

Both in front and back end, WordPress themes and plugins usually enqueue styles and scripts; the real cornerstone of the our work. Security systems, communications, silent or programmed operations, intelligent data process… Most of these common operations have in their backgrounds the loading of scripts and styles. Today we’re going to see how design a selective loading of these components.

Big, big tires

Habitually, the loading of scripts and styles is made by themes and plugins through the functions.php and the /root-plugin-folder/plugin-name.php files respectively. In both cases, usually there is (are) a little function in these php files that programmes the loading of all of these essential components.

Our starting point: the compact mode of loading

The code that we can more easily find in functions.php is more or less like this.

<?php
// in case of back-end WordPress environment
function admin_environment () {
    wp_register_style( 'adm-theme-stylename', get_template_directory_uri() . '/css/adm-styles.css', array ({dependencies list}), 'version#', all );
    wp_enqueue_style( 'adm-theme-stylename');
    wp_register_script( 'adm-theme-scriptname', get_template_directory_uri() . '/js/adm-scripts.js', array ({dependencies list}), 'version#', true );
    wp_enqueue_script( 'adm-theme-scriptname' );
}
add_action ( 'admin_enqueue_scripts', 'admin_environment', 10, 0 );

// in case of front-end WordPress environment
function public_environment () {
    wp_register_style( 'theme-stylename', get_template_directory_uri() . '/css/styles.css', array ({dependencies list}), 'version#', all );
    wp_enqueue_style( 'theme-stylename');
    wp_register_script( 'theme-scriptname', get_template_directory_uri() . '/js/scripts.js', array ({dependencies list}), 'version#', true );
    wp_enqueue_script( 'theme-scriptname' );
}
add_action ( 'wp_enqueue_scripts', 'public_environment', 10, 0 );
?>

With these two little functions we load four different files, two for the WordPress back end, and two for the WordPress front end. It’s a simple good solution that need not another checking control like is_admin() or whatever because the loading is executed by two separated actions admin_enqueue_scripts and wp_enqueue_scripts respectively that are only executed in their adequate environments. The first one is not called in the front end, and the second one is not called in the back end.

Advantages and disadvantages of this solution

In most of the WordPress themes, two functions like the former ones are more than enough for a successful behaviour working notwithstanding, the fact of loading just one style and one script for each environment forces us to include all the code (for all the exceptions, for all the cases, for all the templates, for all the modules…) inside just two unique files –in each environment– And then, for example, while we are editing a post, the code for taxonomies –and users, and media, etc.– will be also loaded, or while we are showing on the screen the list of our recipes through archive.php, we will have also loaded the scripts (and styles) for our forms, calendars, or whatever not present inside the current webpage… Just two files? Ok, but then you always load all the code, all the time.

This solution is the most common and, in the cases of little websites, with a tiny and simple WP theme, a reduced number of plugins and just a few ad hoc developement, it works. But, if you have simply got a little bigger website, with a more complicated WP theme, you load a few more plugins and/or you have written some more of ad hoc code then, this solution does stink. Sorry, I wanted to say “it doesn’t work properly”.

The advantages of this solution are basically

  • it works properly in little websites. Ok, ok… It does work properly in little websites.
  • it has got an incredible deployment time.
  • and from a technical point of view, remember you that it is just a dozen lines of code.

but on the other hand, the disadvantages of this solution are

  • it significantly increases the load time.
  • it propitiates interference with functions designed for other WordPress contexts (taxonomies vs. post, media vs. links, single.php vs. category.php).
  • it produces code that quickly becomes obsolete.
  • it does not encourage to a modular design.
  • it hinders interaction with modules designed by third parties developers.
  • and above all, it difficults the future maintenance of the code.

In summary, as I said, this compact; loading mode works properly with little websites, but it is completely not recommended in the case of larger ones… Then, what can we do?

A better solution for a selective loading of WordPress scripts and styles

For a selective loading of the scripts and styles of a WordPress themes and plugins there are a lot of solutions, in fact, I encourage you to search on the web the point of view of other authors, but I had to choose one among all of them so, this is the proposal that is divided in two parts, one for the WordPress back end and the other one for the front end.

The proposal for WordPress Back End

The proposed solution for the WordPress admin environment is based on loading the scripts, instead of directly through the action admin_register_scripts, via the WordPress action current_screen. The reason is simple, while this second action receives a parameter, the first one doesn’t receives any parameter, and in addition, the action current_screen is loaded earlier, so, it allows us a better control of the behaviour of our developements.

Then, in this first step, the former example for admin environment will be splitted in two different functions:

<?php
function admin_environment () {
    wp_register_style( 'adm-theme-stylename', get_template_directory_uri() . '/css/adm-styles.css', array ({dependencies list}), 'version#', all );
    wp_enqueue_style( 'adm-theme-stylename');
    wp_register_script( 'adm-theme-scriptname', get_template_directory_uri() . '/js/adm-scripts.js', array ({dependencies list}), 'version#', true );
    wp_enqueue_script( 'adm-theme-scriptname' );
}

function loading_environment ( $screen ) {
    add_action ( 'admin_enqueue_scripts', 'admin_environment, 10, 0 );
}
add_action ( 'current_screen', 'loading_environment', 10, 1 );
?>

The function loading_environment receives an object $screen as a parameter and this object has got all information about the module name that is loaded, the current post type that is affected, even the action that is been executed (delete, add new, edit…) so, using this information, now, we can already introduce our selective loading of scripts and styles, for a concrete context (module/posttype/action) but, first, we’re taking a look to a several examples of the WP object $screen.

// This is an example of the object $screen in the module post.php for an existing post.
WP_Screen Object
(
    [action] => 
    [base] => post
    [columns:WP_Screen:private] => 0
    [id] => post
    [in_admin:protected] => site
    [is_network] => 
    [is_user] => 
    [parent_base] => 
    [parent_file] => 
    [post_type] => post
    [taxonomy] => 
    // ... the rest of the properties of this object
)
// In case of a new post
WP_Screen Object
(
    [action] => add
    [base] => post
    [columns:WP_Screen:private] => 0
    [id] => post
    [in_admin:protected] => site
    [is_network] => 
    [is_user] => 
    [parent_base] => 
    [parent_file] => 
    [post_type] => post
    [taxonomy] =>
    // ... the rest of the properties of this object
)
// Displaying the list of post (All Posts menu)
WP_Screen Object
(
    [action] => 
    [base] => edit
    [columns:WP_Screen:private] => 0
    [id] => edit-post
    [in_admin:protected] => site
    [is_network] => 
    [is_user] => 
    [parent_base] => 
    [parent_file] => 
    [post_type] => post
    // ... the rest of the properties of this object
)
// Listing Categories for the Post Type post
WP_Screen Object
(
    [action] => 
    [base] => edit-tags
    [columns:WP_Screen:private] => 0
    [id] => edit-category
    [in_admin:protected] => site
    [is_network] => 
    [is_user] => 
    [parent_base] => 
    [parent_file] => 
    [post_type] => post
    [taxonomy] => category
    // ... the rest of the properties of this object
)

As you saw, for each module, posttype/taxonomy, action, WordPress informs to the action current_screen about the parameters that define this context so, we can use them for introducing our selective loading system.

In this example, we’ll simply check two criteria

  • Are we editing a WordPress post item ?
  • Is this post a new post ?

But for doing this, in fact, we have to check three different properties of the object $screen. Take a look to the final function.

<?php
function common_admin_environment () {
    wp_register_style( 'adm-theme-stylename', get_template_directory_uri() . '/css/adm-styles.css', array ({dependencies list}), 'version#', all );
    wp_enqueue_style( 'adm-theme-stylename');
    wp_register_script( 'adm-theme-scriptname', get_template_directory_uri() . '/js/adm-scripts.js', array ({dependencies list}), 'version#', true );
    wp_enqueue_script( 'adm-theme-scriptname' );
}

function edit_new_post_environment () {
    wp_register_style( 'edit_post_new-stylename', get_template_directory_uri() . '/css/edit_post_new-styles.css', array ({dependencies list}), 'version#', all );
    wp_enqueue_style( 'edit_post_new-stylename');
    wp_register_script( 'edit_post_new-scriptname', get_template_directory_uri() . '/js/edit_post_new-scripts.js', array ({dependencies list}), 'version#', true );
    wp_enqueue_script( 'edit_post_new-scriptname' );
}

function loading_environment ( $screen ) {
    // Perhaps two tiny common scripts and styles files... Why not?
    add_action ( 'admin_enqueue_scripts', 'common_admin_environment', 10, 0 );
    // now the selective loading module
    if ( $screen->base === 'post' ) { // first, we check if we are editing
        if ( $screen->post_type === 'post' ) { // now, we check if the post type is 'post'
            if ( $screen->action === 'add' ) { // finally, we check if the post is a new one
                // Here, we call to a different function for loading the adequate scripts and styles
                // Priority will define the loading of the ad hoc scripts and styles after or before the common ones
                add_action ( 'admin_enqueue_scripts', 'edit_new_post_environment', 10, 0 );
            }
        }
    }
    // here, other (your own) conditions
}
add_action ( 'current_screen', 'loading_environment', 10, 1 );
?>

This former example is a simplified version but, using the four or five basic properties of the object $screen, for example, base, post_type, action…, you can desing a fantastic module for a rational and selective loading of our WordPress plugins and themes scripts and styles.

The proposal for WordPress Front End

In the case of the WordPress Front End environment, the strategy is quite similar because it is also based on checking a WP object however, in the Front End, we can’t check the object $screen but, we have to examine the object $query, ie, the result of the execution of the last WP_query user request.

The metodology is the same so, in fact, we can copy the previous function and we have simply to change the name of the object and to hook the functions in the adequate actions. Change object name, change hook names. That’s all.

A little example for distinguish between archives and categories could be this one:

<?php
function common_frontend_environment () {
    wp_register_style( 'front-end--stylename', get_template_directory_uri() . '/css/front-end-styles.css', array ({dependencies list}), 'version#', all );
    wp_enqueue_style( 'front-end-stylename');
    wp_register_script( 'front-end-scriptname', get_template_directory_uri() . '/js/front-end-scripts.js', array ({dependencies list}), 'version#', true );
    wp_enqueue_script( 'front-end-scriptname' );
}

function in_category_environment () {
    wp_register_style( 'front-end-category-stylename', get_template_directory_uri() . '/css/front-end-category-styles.css', array ({dependencies list}), 'version#', all );
    wp_enqueue_style( 'front-end-category-stylename');
    wp_register_script( 'front-end-category-scriptname', get_template_directory_uri() . '/js/front-end-category-scripts.js', array ({dependencies list}), 'version#', true );
    wp_enqueue_script( 'front-end-category-scriptname' );
}

function in_archive_environment () {
    wp_register_style( 'front-end-archive-stylename', get_template_directory_uri() . '/css/front-end-archive-styles.css', array ({dependencies list}), 'version#', all );
    wp_enqueue_style( 'front-end-archive-stylename');
    wp_register_script( 'front-end-archive-scriptname', get_template_directory_uri() . '/js/front-end-archive.js', array ({dependencies list}), 'version#', true );
    wp_enqueue_script( 'front-end-archive-scriptname' );
}

function frontend_environment () {
    global $query;
    // Perhaps two tiny common scripts and styles files... Why not?
    add_action ( 'wp_enqueue_scripts', 'common_frontend_environment', 10, 0 );
    // now the selective loading module
    if ( is_category() ) // we check firstly if this request is for a category WP_Query
        add_action ( 'wp_enqueue_scripts', 'in_category_environment', 11, 0 );
    else if ( is_archive() ) // then, we check if this request is for an achive WP_Query
        add_action ( 'wp_enqueue_scripts', 'in_archive_environment', 11, 0 );
    // here, other (your own) conditions
}
// we need check is_admin() because the action wp is alsp executed in the admin environment.
if ( !is_admin() )
    add_action ( 'wp', 'frontend_environment', 10, 1 );
?>

I hope that these two examples for both WordPress front and back end, will be usefull in your themes and plugins.

Have a nice WordPressing!

Leave a Comment

   Mandatory field
You can use these HTML tags inside the commment.
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>