WordPress Theme Development: The best way to enqueue scripts and styles (2023)

Hire a WordPress Expert on Codeable
Updated On: October 14th, 2023 3 Comments

This is Part 2 of the 9 part Course about developing a WordPress theme from scratch.

Here is the access to the other parts of the Course in the sequential order:

  1. Developing a WordPress Theme From Scratch
  2. WordPress Theme Development: The best way to enqueue scripts and styles (Current Part)
  3. WordPress Theme Development: Creating the header and making our theme translation ready
  4. WordPress Theme Development: Site footer with social navigation, dynamic copyright statement
  5. WordPress Theme Development: The Loop, the main content, Google Fonts, and the Custom Fields
  6. Building a WordPress Theme From Scratch: Internal Pages
  7. WordPress Theme Development: Building the Blog
  8. WordPress Theme Development: Search page, 404 error template, Custom Queries, and custom post types
  9. WordPress Theme Development: WordPress Customizer and it’s API

In Part 1: Developing a WordPress theme from scratch, we have learned about the foundations of the WordPress Theme Development.

In this part, We will learn how to load scripts and styles to our WordPress site.

Now before we add our scripts and styles to the <head> element, let’s clean up the functions.php file by removing everything that we added in the last part.

I made you add them just for the sake of demonstrating action hooks. Real code that goes inside the functions.php file starts from this module.

This is my current functions.php file after removing everything from it except the opening PHP tag.

WordPress Theme Development

Yeah! Right now, the file only contains an opening PHP tag. 

WordPress Theme Development:
Let’s deal with the scripts and stylesheets.

After the favicon, the next big thing that we have to deal with is our website stylesheets and scripts. These are generally divided into two categories.

  1. Your own main stylesheet and script files that you write as a ninja frontend Developer. In the case of WordPress, we usually put all our custom styles inside the style.css file and our main Javascript code inside the  main.js file
  2. Third Party Stylesheets and Scripts Like
    1. normalize.css for resetting browser-based styles
    2. bootstrap.css to save our time when dealing with layouts, tabs, accordions
    3. superfish.js and superfish.css for creating accessible drop-down menus
    4. modernizr.js for detecting features of the browser like flexbox,grid, etc.
    5. The list goes on and on…

For the purposes of this project, We will be using quite a lot of third-party stylesheets and scripts. 

And to house these scripts and stylesheets, let’s create a new directory inside our nd-dosth theme and let’s name it assets .

In other words, its a directory for housing publicly accessible assets like scripts, stylesheets, images and custom fonts like FontAwesome.

So, let’s create four more directories under assets. And let’s call them:

  • css
  • js
  • images
  • fonts

Here is how assets directory looks inside Visual Studio Code Editor:

Assets Directory

Now that the directory structure in place, let’s go ahead and download the initial stylesheets and scripts we need to proceed forward with this project

1) style.css

We already created this file at the initial stages of our theme development.

2) jquery.js file

 WordPress ships with the latest version of jQuery plugin by default. You don’t have to worry about downloading and including this file manually.

2) main.js file for housing all our custom javascript code.

Let’s create this file and put it inside  assets/js directory. Also, it is not mandatory to name this file main.js .You can name it whatever you want, for example, custom.js

3) normalize.css stylesheet file.

Go ahead and download the latest normalize.css file from the Necolas’s Github website:

https://necolas.github.io/normalize.css/

And, let’s put it inside assets/css directory.

4) bootstrap stylesheet and script file.

Visit https://getbootstrap.com/ and download the latest bootstrap zip file. Extract it so that you can copy the necessary files to our theme.

copy the bootstrap.min.cssfile to the assets/css directory

Also, copy the bootstrap.min.jsfile to the assets/js directory

And here is the updated version of the assets directory inside visual code editor

Alright, now that we have our initial scripts and stylesheets in place, it is time to use them.

When it comes to WordPress, although there are a number of ways for linking our scripts and stylesheets to a webpage, WordPress strongly recommends using its enqueue system to manage our scripts and stylesheets.

Simply put, WordPress Enqueue System will help us manage the loading of our scripts and stylesheets, to just about any webpage on our site, only from the functions.php file, with ease.  

You never have to write or copy-paste the <link> tags or the <scripttags on every HTML file like we normally do in our HTML/CSS projects. WordPress Enqueue system generates them on every page of your site by taking some basic instructions from you.

Now, the word “Enqueue” is not specific to WordPress. It is just another word in the English Dictionary. 

Here is what Google says about the word:

Google definition for Enqueue

Google says “Add an item to a queue of such items”.

Google hits the bulls-eye with that definition of enqueueing. When we translate that definition to the world of WordPress, enqueuing just means management of our stylesheets and scripts, both on frontend and admin side of a WordPress website. 

To be precise, management of our stylesheets and scripts involves:

1) Queueing them one after another so that we can manage their dependencies and generate the markup for them

We need enqueuing because the order in which stylesheets and scripts appear has a huge impact on the functioning of a webpage. 

From the perspective of a stylesheet, In our custom stylesheet, it is a common practice to override some styles of third-party CSS stylesheets like Bootstrap. So we must place the Bootstrap CSS stylesheet first in the queue.

And, From the perspective of a script, In our custom script, it is a common practice to initialize some third-party Javascript libraries like Bootstrap, Superfish, Isotope. So we must place all these script files one after another in the queue and we must place our custom script last in the queue so that we can initialize all those third-party libraries.

If you are good with CSS and Javascript you what I mean. If you don’t, worry not, you can grasp it as we progress through this WordPress Theme Development course.

Conceptual illustration of WordPress Enqueue System

2) Deciding whether to enqueue an individual script or stylesheet on a particular webpage on our website.

We need this because not every webpage needs every script or stylesheet to render or function properly.

So, with the help of the WordPress enqueue system, we can conditionally enqueue a script or stylesheet on a particular page. 

For example, Let’s just say our client wants a Masonry layout only for his Website’s Homepage and not for any other page on his site. WordPress Enqueue System counters this problem with ease. You’ll see the how” in the next section.

When it comes to the frontend, WordPress Enqueue system internally depends on the  wp_head and wp_footer action hooks. 

Also, WordPress uses the enqueue system internally. So does every well-written plugin. And, for the following reasons, we ( the theme developers ) have to use it too.

  1. Long-term maintenance benefits
  2. For better control over the dependencies
  3. Easy to create version numbers to deal with caching while making modifications once the site goes live on production server like Godaddy, Mediatemple etc.
  4. If we have to include a new stylesheet or a script, we can enqueue it from functions.php file without having to modify multiple files.
  5. Playing along with a plugin’s scripts and stylesheets.

So, How do we make use of WordPress Enqueue System? 

Introducing The Four pillars of WordPress Enqueue System 

WordPress allows us to make use of the Enqueue system by providing us with two action hooks and two handy functions for generating the proper <script> and <link> tags. 

WordPress Theme Development

1) wp_enqueue_scripts action hook allows us to enqueue both stylesheets and scripts to a front end webpage of our WordPress website.  For example, Homepage, Features page, Blog Archive, Blog Post, etc.

2) admin_enqueue_scripts action hook allows us to enqueue both stylesheets and scripts to a backend webpage. For example, our Admin Dashboard, Page’s Panel, Theme’s Panel, etc.

3) wp_enqueue_style() function to register and enqueue our stylesheets. This function also generates a proper stylesheet <link> tag, for example:


<link rel="stylesheet" id="normalize-css" href="http://localhost:8888/dosth/wp-content/themes/nd-dosth/assets/css/normalize.css?ver=4.9.9" type="text/css" media="all">

4) wp_enqueue_script() function to register and enqueue our scripts. This function also generates a proper <script> tag, for example:


<script type="text/javascript" src="http://localhost:8888/dosth/wp-content/themes/nd-dosth/assets/js/main.js?ver=1.0.0"></script>

Now, don’t get confused. wp_enqueue_scripts action hook just allows us to enqueue scripts and stylesheets. Actual enqueueing is done by the wp_enqueue_style() and wp_enqueue_script()functions.

And for the purposes of this WordPress Theme Development guide, we will be just focusing on the wp_enqueue_scripts action hook for enqueuing stylesheets to a frontend web page.

You are not going to see any usage of admin_enqueue_scripts action hook in this WordPress Theme Development guide.

We usually use admin_enqueue_scripts action hook if our client demands customizations to the Admin side of WordPress.

Also, the plugin developers use this action hook quite extensively.

Anyway, if you can master the concept of action hooks correctly, you should be able to use admin_enqueue_scripts action hook quite easily by yourself.

With that being said, let’s learn how to use wp_enqueue_scripts action hook.

wp_enqueue_scripts action hook allows you to enqueuing stylesheets and scripts on the frontend

It is just another action hook that allows you to echo some data or HTML markup to a front end webpage. That’s all. 

And Just like any other action hook, It has a single and straightforward purpose.

When WordPress is building the final webpage, it fires this action hook to allow us to enqueue our own theme related scripts and stylesheets to the frontend webpage, more precisely to the <head> element.

Let’s try it out. Go ahead and put the following code inside the functions.php file.


function nd_dosth_enqueue_styles() {
   echo '<link rel="stylesheet" href="http://localhost:8888/dosth/wp-content/themes/nd-dosth/assets/css/normalize.css" type="text/css" media="all">';

}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_styles' );

Let’s break it down.

Nothing special going on in here. 

We defined a custom action called nd_dosth_enqueue_styles and hooked it to the wp_enqueue_scripts action hook. And inside our custom action, we are just echoing out the hard-coded stylesheet <link> tag. That’s all.

“Hey! You said WordPress will generate that <link> tag for us? Right?”

Don’t worry! We will replace the hard-coded stylesheet <link> tag with the wp_enqueue_style() function in a moment.

For the time being, if we switch back to the Homepage in the Browser, refresh it and view its page source, we can indeed find our stylesheet <link> tag inside the <head> element.

It is working

See that? 

But, how does the wp_enqueue_scripts action hook work?  How does it magically echoes our stylesheet exactly to the <head> element of our Homepage and not anywhere else on a Homepage, for example, the footer portion? 

As usual, everything happens for a reason in WordPress, there is no magic!

The wp_enqueue_scripts action hook relies on the wp_head action hook. To be precise, wp_head action hook triggers the wp_enqueue_scripts action hook. 

As I previously mentioned, WordPress internally attaches it’s own core actions to the 'wp_head' action hook. And one of those core actions is wp_enqueue_scripts . You can see this if you take a peek into the  default-filters.php file from the WordPress core.

You also know that an action is nothing but a custom PHP function with a single purpose. So, the purpose of the  wp_enqueue_scripts action is to trigger wp_enqueue_scripts action hook. Just like wp_head() function triggers the wp_head action hook. Here is source of wp_enqueue_scripts action.

Now don’t worry if you did not understand it. 

For now, all you have to remember is, If you remove the wp_head() function from the header.php file,  wp_enqueue_scripts action hook is not gonna work at all. And, if this action hook doesn’t work, you can not enqueue your stylesheets or scripts dynamically.

At the end of the day, it all tracks back to wp_head() function in the header.php file 😛

Anyway, that is all you need to know about wp_enqueue_scripts action hook. Now let’s replace the stylesheet <link> tag with wp_enqueue_style() function.

wp_enqueue_style() function to register and enqueue a stylesheet

Once again, The primary purpose ofwp_enqueue_style()function is to register and enqueue a stylesheet to the <headelement of a webpage. This function also generates a proper stylesheet <link> tag.

wp_enqueue_style()function also relies internally on the wp_head action hook. 

And, It accepts five parameters to give us some fine grain control over the management of the stylesheet.


wp_enqueue_style( $handle, $source, $dependencies, $version, $media );

let’s start with the $handle and $source parameters.

The $handle parameter

With this parameter, you are giving a handle to your stylesheet in a string format, for example:


wp_enqueue_style( 'normalize', $source, $dependencies, $version, $media );

You can use any text which is a valid PHP string. For example,  ‘main-style','foundation_grid_11' are totally valid strings in PHP. 

But, we usually name handles in such a way that they convey what a stylesheet is doing. We do this because it makes the life easy for the future developer or maintainer of this project. 

Also, Plugin developers use this $handle parameter quite extensively to conditionally enqueue or de-register stylesheets.

For example, you can conditionally de-register a stylesheet using its handle, for example:


if( is_page( 74 ) ){ 
   wp_deregister_style( $handle );
}

In the above example, we are de-registering a stylesheet only on a page whose id is 74 using the another predefined conditional function called  is_page(). In terms of WordPress Terminology, is_page()  is a conditional tag

Don’t worry, It is just a fancy name.  Anyway, WordPress provides us with a tons of conditional tags and we will learn how to use conditonal tags as we progress through the course.

Back to the topic at hand, From a theme developer’s standpoint,  the $handle parameter is used extensively to specify the dependencies of a particular stylesheet and we will practice this in a moment. 

I once had to totally remove the Woocommerce plugin’s stylesheet for an advanced Woocommerce theme and the $handle parameter of the stylesheet is the real saver of the day.

Simply put, it is rare, but this example tells the exact purpose of the $handle parameter.

The $source parameter

For the $source parameter, you need to provide a fully qualified URL of the stylesheet, for example:


wp_enqueue_style( 
   'normalize', 
   'http://domain-name.com/wp-content/themes/your-theme/path-to-css-file/normalize.css', 
   $dependencies, 
   $version, 
   $media 
);

Now, if you consider yourself as a responsible and standards following theme developer:

You shouldn’t hard-code the URL of the stylesheet like this:

http://domain-name.com/wp-content/themes/your-theme/path-to-css-file/normalize.css

or a relative path like this:

/wp-content/themes/your-theme/path-to-css-file/normalize.css

Both of these does work but increases the maintenance overhead in the long run. So, a big no-no.

To make our lives easier as a developer,  WordPress provides a handy function which helps you build the fully qualified URL for just about any publicly accessible asset like image, stylesheets, fonts, javascript plugins etc.

And, the function is:


get_stylesheet_directory_uri()

As the function name suggests, it just returns a fully qualified URL of the active theme directory, in our case, it is:

http://localhost:8888/dosth/wp-content/themes/nd-dosth

Notice that there is no forward-slash ( / ) at the end of the URL. You have to take care of it when you build the rest of the path to the file.

“So, what how we build the rest of the path to the file?”

Simple, we have to use the PHP concatenation technique to build the rest of the path ourselves, for example:


<?php get_stylesheet_directory_uri() . '/assets/css/normalize.css'; ?>

Notice, we are building the rest of the path starting with a forward slash at the beginning.

This tells us a really important thing. We can still use all the core PHP techniques and functions along with WordPress only functions.

WordPress is nothing but a big PHP project. You can still do everything that you usually do inside your custom PHP projects.

so, the WordPress translates the above code to:

http://localhost:8888/dosth/wp-content/themes/nd-dosth/assets/css/normalize.css/
WordPress get_styelsheet_directory_uri function demonstration

Really Sorry, I can’t stress this enough, please pay attention to the forward-slash ( / ) at the beginning of the blue colored box in the above image. 

This is a very common problem when we are getting started as a WordPress developer. 

If you notice the yellow boxes in the above image, The get_stylesheet_directory_uri()function only returns the fully qualified of the active theme directory without the trailing forward-slash.

So, it is our responsibility to put the forward-slash at the beginning of the rest of the URL we are concatenating.

If you can’t keep up with the forward-slashes every time you use the get_stylesheet_directory_uri()function, that is totally ok. 

WordPress provides us with another handy function to handle the forward-slashes for us and the function is


trailingslashit()

It is pronounced as, trailing-slash-it.

To use this function, All you have to do is provide a URL and it gives you back the same URL by attaching a forward-slash to the end of it.

And this is how we use it in the real-world WordPress projects.


<?php trailingslashit(get_stylesheet_directory_uri()) . 'assets/css/normalize.css'; ?>
WordPress trailingslash function demonstration

Get it?

Now, Let’s enqueue them on every front-end page of our website

I know I left out the explanation for the remaining three parameters and I did it on a purpose. They are better understood when you try them practically. 

Anyway, enough theory, let’s start with enqueuing the normalize stylesheet.

Enqueuing the normalize stylesheet

Open up the functions.php file inside our theme and replace the hard-coded echo with the following code in it to enqueue the normalize.css file


wp_enqueue_style( 
   'normalize',
   get_stylesheet_directory_uri() . '/assets/css/normalize.css', 
   array(), 
   false, 
   'all' 
);

Here is my full functions.php file after placing the above code:

And let’s break it down. 

If you look at the above wp_enqueue_style()function call,  we already know what is going on with the first two parameters. So, let’s take a look at the remaining parameters.

The third parameter is all about dependencies. We need normalize.css file to be loaded before any other stylesheet. It doesn’t really depend on any other stylesheet. So, we should leave out $dependencies parameter as an empty array. Now, I know this is a vague explanation, but bear with me, You’ll know the purpose of the $dependencies parameter when we enqueue our main style.css file.

The Fourth parameter is all about the version number of the stylesheet. If you specify, the version number will be added to the end of the final stylesheet URL as a query string for cache busting. A version number as a query string is particularly useful if you are planning to make a lot of changes to the stylesheet once the website goes live and the caching is enabled.

In a real-world scenario, a URL with a version number looks like this:

http://localhost:8888/dosth/wp-content/themes/nd-dosth/assets/css/normalize.css?ver=1.0

When it comes to the normalize.css file, this is a third-party library and I have no intentions of adding/modifying the styles inside it. So I specified false for this parameter. 

And when you specify false for this parameter, WordPress will still generate a version number at the end of the URL and it uses the current WordPress Software Version number. At the time of writing this lesson, it’s 4.9.9

Finally, the fifth parameter tells the browser what media ( or device ) the stylesheet is optimized for. I always choose to support all the media types including the print media.  Hence, I choose all for this parameter.

Anyway,It is time to test this. 

If we go back to the homepage in the browser and refresh it, the normalize.css file is indeed getting injected to the <head> element of our homepage.

This is Homepage

Fun fact: You are allowed to use wp_enqueue_style() function only inside the wp_enqueue_scripts, admin_enqueue_scripts, and login_enqueue_scripts action hooks. If you try to use it outside this action hook, WordPress will throw the following error.

Script Enqueue Error on the Homepage

Enqueuing the bootstrap stylesheet

To enqueue the Bootstrap stylesheet, you have to use the same technique. Place the following Bootstrap enqueue code right after the Normalize enqueue function. 

Here is my current functions.php file with Bootstrap enqueue code:


function nd_dosth_enqueue_styles() {
    wp_enqueue_style( 
        'normalize',
        get_stylesheet_directory_uri() . '/assets/css/normalize.css', 
        array(), 
        false, 
        'all' 
    );
    wp_enqueue_style( 
        'bootstrap',
        get_stylesheet_directory_uri() . '/assets/css/bootstrap.min.css', 
        array(), 
        false, 
        'all' 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_styles' );

If you notice, except for the $source URL and the handle parameters, every other parameter is similar to the enqueue function of normalize stylesheet.

This is because, just like the normalize stylesheet, the bootstrap stylesheet doesn’t depend on any other stylesheet and we are not going to edit the core styles inside the bootstrap.min.css file.

But those parameters do change when we enqueue our main stylesheet.

Enqueuing the main stylesheet a.k.a the style.css file

To enqueue our main stylesheet, put the following code after the bootstrap enqueue function.


wp_enqueue_style( 
   'main-stylesheet',
    get_stylesheet_uri(), 
    array('normalize','bootstrap'), 
    '1.0", 
    'all' 
);

Ah! We are finally using the full capabilities of the wp_enqueue_style() function. So, why late? let’s break it down.

As usual, the first parameter is the handle name.

And when it comes to the second parameter, we are using a different function to build the URL of the style.css file. And if you notice, we are not concatenating anything to the end of it.


get_stylesheet_uri()

Simply put, this function returns the fully qualified URL of the style.css file.

“Wait! But why this special function just for the style.css file?”

As you already know, WordPress expects a style.css file inside every active theme. And it also forces us to put this file at the root level of our theme directory.

So, WordPress knows where this file exists and hence provides the handy get_stylesheet_uri() function which returns the URL of the file.

This is why I love WordPress!

Anyway, for the third parameter, instead of an empty array, this time we are providing two dependencies by specifying the handle names of already registered stylesheets. 


array('normalize','bootstrap')

Does the above handles in the array ring any bell?

“Yep! Those are the handles of Normalize and Bootstrap stylesheets that we enqueued”

Correct! You are smart. So, technically, this is our way telling WordPress “Hey! Only load the style.css file after loading  the normalize.css and  bootstrap.min.css file”.

“Wait! Why and how our  style.css file is dependent on Bootstrap and Normalize stylesheets?”

Simple, as a CSS developer we might have to overwrite some of the Bootstrap framework’s style rules for better control over the layout of the website. And the best way to do it is overwriting them using the style.css file.

This way, we don’t have to edit the Bootstrap’s core stylesheet. 

If we edit the Bootstrap stylesheet directly, it’s going to bite us back when we have to migrate to a newly released version Bootstrap’s stylesheet. From the maintenance perspective, it is all about how much time you save in long run.

Now, I am not saying that you must add the Bootstrap stylesheet as a dependency. It varies from project to project.

I usually overwrite some of the layout rules of Bootstrap to code a Full-Width website.

And we’ll be coding a full-width page at a later point the course. So, for the purposes of this project, I mentioned it as a dependency for the main stylesheet.

Also, for the fourth parameter, we provided a version number of “1.0”.

Once we launch the website to a live/production server, we will be updating this version number every time we make edits to the style.css file.

And we do this to bust the cache in the browser. Specifying a different version number for any script or stylesheet will force the browser to re-download the file from the server. 

No client never ever said “Hey! Thanks for launching our website. We are done with you.”

Even after the site launch, the client will keep coming back with new changes to website styles. So always use a version number when enqueuing a stylesheet which might get some changes. 

Finally, for the fifth parameter, we are using the value “all” once again to tell the browser “Hey! You can use this stylesheet for that media/devices”.

Here is the current functions.php file.


<?php
function nd_dosth_enqueue_styles() {
    wp_enqueue_style( 
        'normalize',
        get_stylesheet_directory_uri() . '/assets/css/normalize.css', 
        array(), 
        false, 
        'all' 
    );
    wp_enqueue_style( 
        'bootstrap',
        get_stylesheet_directory_uri() . '/assets/css/bootstrap.min.css', 
        array(), 
        false, 
        'all' 
    );
    wp_enqueue_style( 
        'main-stylesheet',
        get_stylesheet_uri(), 
        array('normalize', 'bootstrap'), 
        "1.0", 
        'all' 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_styles' );

And if you take a look at the page source of the Homepage, You can see all the stylesheets getting loaded one after the another:

That’s it, we are done with enqueuing our initial stylesheets. As we progress towards the completion of the Dosth project, we will keep coming back to the functions.php file and the  nd_dosth_enqueue_styles() action function to enqueue more stylesheets as per the requirements of the project.

Now, let’s go ahead and enqueue our initial scripts.

wp_enqueue_script() function to register and enqueue a script

The primary purpose ofwp_enqueue_script()function is to register and enqueue a script to both <headelement and the footer portion of a webpage. This function also generates a proper <script> tag.


wp_enqueue_script( $handle, $source, $dependencies, $version, $in_footer );

First of all, enqueuing a script is totally similar to enqueuing a stylesheet with only one major difference. I highlighted this difference by making it bold in the above line of code.

Thisfunction also accepts five parameters. The first four parameters are exactly same when compared to wp_enqueue_style()function.

But, If you notice the last parameter, this function ships with an  $in_footer parameter instead of the $media parameter. 

If you are good with HTML, you know that script tag doesn’t support the  media attribute. The  media attribute only applies to the stylesheets.

And, Javascript is render blocking.

That means if we put a crappy script inside the <head> element and if it is taking too long to get executed, Browser waits until the crappy script is executed to paint our webpage on the computer screen.

So, for a webpage to be performant, and if you want your website visitor to see the webpage as soon as possible, most of the scripts must go just before the closing </body> tag instead of the <head> element. That means, in the footer portion of a web page.

And the $in_footer parameter help us achieve just that.

The $in_footer parameter controls where on a webpage you can place your script tag. WordPress allows you to place a script either inside the  <head> element or just before the closing </body> tag. 

The $in_footer parameter can be set to true or false. If you specify true, WordPress places the script tag in the footer and if you specify false, WordPress places the script tag inside the  <head> element.

You already know that the wp_enqueue_style()function relies on internally relies on the wp_head action hook.

But, When it comes to wp_enqueue_script()function, It relies on both the wp_head and wp_footer action hooks. 

The  wp_enqueue_script()function relies on wp_footer action hook to enqueue scripts to the footer portion of a webpage.

Enough said! Let’s start the enqueuing of our scripts.

Exercise: Enqueue the main.js file

I have a small exercise for you. You know that enqueuing a script is similar to that of enqueuing a stylesheet.

We also created h main.js file in the middle of this lesson. So, go ahead and enqueue the main.js file using the following four pieces of the puzzle:

  1. wp_enqueue_script() function
  2. wp_enqueue_scripts action hook
  3. nd_dosth_enqueue_scripts() action
  4. Enqueue the  main.js file to the footer of a webpage using the  $in_footer parameter

Did you?

Please take your time to finish this exercise and only proceed forward after you are done with it. 

“Yep! I am done with the exercise. Between why do we need a new action like nd_dosth_enqueue_scripts()? Can’t we just enqueue the script using the same nd_dosth_enqueue_styles()action?”

Do you mean like this:


<?php
function nd_dosth_enqueue_styles() {
    wp_enqueue_style( 
        'normalize',
        get_stylesheet_directory_uri() . '/assets/css/normalize.css', 
        array(), 
        false, 
        'all' 
    );
    wp_enqueue_style( 
        'bootstrap',
        get_stylesheet_directory_uri() . '/assets/css/bootstrap.min.css', 
        array(), 
        false, 
        'all' 
    );
    wp_enqueue_style( 
        'main-stylesheet',
        get_stylesheet_uri(), 
        array('normalize', 'bootstrap'), 
        "1.0", 
        'all' 
    );
    wp_enqueue_script( 
        'main-js', 
        get_stylesheet_directory_uri() . '/assets/js/main.js', 
        array(), 
        '1.0.0', 
        true // load this script in the footer 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_styles' );

“Exactly, Yes. And I guess it also works, right?”

Well, it is totally fine if you do that and yes, it works. But, I give more importance to code organization and code readability.

You should too. Especially, if we are building a Big WordPress project. Once we come out of the project, we never know who will work on top of our code next.

And, from the previous lesson, we also learned that we can attach any number of actions to the same action hook.

WordPress is built with code modularity and readability in mind and this is one of the primary reasons why WordPress allows us to hook different actions to a single action hook. Also, scripts and stylesheets are two different things.

The whole purpose of this exercise is to introduce you to the world of code modularity and readability.

Solution to the exercise

Anyway, here is my current verison of functions.php file with the main.js file enqueue code .


<?php
function nd_dosth_enqueue_styles() {
    wp_enqueue_style( 
        'normalize',
        get_stylesheet_directory_uri() . '/assets/css/normalize.css', 
        array(), 
        false, 
        'all' 
    );
    wp_enqueue_style( 
        'bootstrap',
        get_stylesheet_directory_uri() . '/assets/css/bootstrap.min.css', 
        array(), 
        false, 
        'all' 
    );
    wp_enqueue_style( 
        'main-stylesheet',
        get_stylesheet_uri(), 
        array('normalize', 'bootstrap'), 
        "1.0", 
        'all' 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_styles' );

function nd_dosth_enqueue_scripts() {
    wp_enqueue_script( 
        'main-js', 
        get_stylesheet_directory_uri() . '/assets/js/main.js', 
        array(), 
        '1.0.0', 
        true 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_scripts' );

You know what’s happening with every parameter. If the above code works, we will see a script tag with a link to the main.js file.

And since we specified true for the fifth parameter, WordPress should enqueue this script in the footer portion of the webpage and just before the closing </body> tag.

Also, we are not enqueuing the bootstrap.min.js file because I am not sure if I am going to use it for this project. But I just wanted to keep it ready for a future.

So, let’s test this code by visiting the Homepage in the browser and viewing its page source.

Oh! Something went wrong again. I can not see the main.js script tag in the footer portion of the webpage.

No script in the footer

“Oh common! What is it now?”

Well, Sorry! 

This is happening because we did not tell WordPress where to locate the footer portion of a webpage. 

If you remember, in the last lesson we had the same problem while enqueuing the stylesheets.

And, we countered the problem by telling WordPress where the header portion of a webpage is located and we did so by placing the wp_head() function right above the closing </head> tag inside header.php file.

Similarly, We should also tell WordPress where is footer portion of the webpage is located.

So, to fix this problem, all we have to do is put wp_footer() function inside the footer.php file. So, let’s go ahead and do just that.

Open up the footer.php file and put the following code in it.


<?php wp_footer(); ?>

“Thats it?”

Yep, That’s it. 

Just like wp_head() function fires wp_head action hook, wp_footer() function fires wp_footer action hook.

And, wp_enqueue_script function depends on both those action hooks to properly enqueue scripts to the header and footer portion of the webpage.

Get It?

This is our way of telling WordPress “Yo! WordPress! This right here is the footer portion of a Webpage. Feel free to enqueue scripts here”

Anyway, If we go back to the browser and refresh the Homepage’s source again, this time we will see the main.js script enqueued properly to the footer portion.

Script enqueued correctly

And Oh! We almost forgot, let’s enqueue the jQuery library.

Enqueuing the jQuery library

Our theme depends on jQuery. And as I mentioned previously, WordPress ships with latest version jQuery library. 

WordPress enqueues the jQuery script automatically to a frontend webpage if some other script depends on it.

For example, if we specify jQuery script as a dependency to our main.js script, WordPress automatically generates the jQuery script tag just before the main.js script tag.

“Hey! I don’t know the handle of jQuery script, How do I find it?”

Good Question! Its jquery

And you can find the handle of jQuery in the following page of WordPress Codex:
https://developer.wordpress.org/reference/functions/wp_enqueue_script/

As you can see, WordPress also ships with a ton of other scripts. And you can enqueue all of these scripts by using their handles. 

Anyway, now that you know the handle for jQuery, go ahead and specify it in the main-js enqueue call like this:


function nd_dosth_enqueue_scripts() {
    wp_enqueue_script( 
        'main-js', 
        get_stylesheet_directory_uri() . '/assets/js/main.js', 
        array('jquery'), 
        '1.0.0', 
        true 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_scripts' );

If we view the page source of our Homepage in the browser, WordPress is loading the jQuery library inside the <head> element.

Page source

Surprised? WordPress and so many other expert frontend developers agree that jQuery must go inside the <head> element rather than the footer portion.

So, WordPress enqueues the jQuery script to the <head> element.

“Hey! What if I want in the footer?”

Simple, download the jQuery script from the jQuery website and enqueue it just like any other script.

In fact, some clients demand to load jQuery in the footer and from a CDN. In this case, we can enqueue jQuery like this:


wp_deregister_script('jquery');

function nd_dosth_enqueue_scripts() {
    wp_enqueue_script( 
        'jquery',  
        'https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js', 
        array(), // no dependencies
        null, // you don't need to specify version number
        true, // load jquery in the footer 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_scripts' );

To avoid any accidental enqueuing of WordPress based jQuery, we must first deregister it. Then we can enqueue our CDN based jQuery just like any other script.

Important Note: The above technique only applies to all the scripts that WordPress ships with.

“I got one more question!”

Shoot!

“I just noticed that WordPress also ships with ImagesLoaded javascript plugin. I use it quite extensively. And none of my other scripts depend on it. How do I enqueue this?”

Simple, you have to use wp_enqueue_script() function along with the handle of the script, like this:


wp_enqueue_script('imagesloaded');

“That’s all? What about the remaining four parameters?”

WordPress will take care of the remaining parameters. You don’t have to worry about them. 

And if you try this out, WordPress enqueues this script inside the footer. 

Imagesloaded script

See? WordPress knows where to enqueue. WordPress always takes good decisions for us.

Anyway, I don’t usually use ImagesLoaded javascript plugin, so I am not going to enqueue it. If you want to do it, feel free to.

This is my final functions.php file for this lesson:


<?php
function nd_dosth_enqueue_styles() {
    wp_enqueue_style( 		
        'normalize',	
        get_stylesheet_directory_uri() . '/assets/css/normalize.css', 	
        array(), 		
        false, 		
        'all' 
    );
    wp_enqueue_style( 		
        'bootstrap',	
        get_stylesheet_directory_uri() . '/assets/css/bootstrap.min.css', 	
        array(), 		
        false, 		
        'all' 
    );
    wp_enqueue_style( 		
        'main-stylesheet',	
        get_stylesheet_uri(), 	
        array('normalize', 'bootstrap'), 		
        "1.0", 		
        'all' 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_styles' );

function nd_dosth_enqueue_scripts() {
    wp_enqueue_script( 
        'main-js', 
        get_stylesheet_directory_uri() . '/assets/js/main.js', 
        array('jquery'), 
        '1.0.0', 
        true 
    );
}
add_action( 'wp_enqueue_scripts', 'nd_dosth_enqueue_scripts' );

Uff… this marks the end of this lesson. You did a great job.

And trust me, If you are done up to this point in the course, You have learned 50% of the WordPress Theme Development already.

Anyway, now that we are done with the initial stylesheets and scripts that our project depends on, in the next lesson, we will deal with the rest of the header starting with the <title> tag.

3 Replies to “WordPress Theme Development: The best way to enqueue scripts and styles (2023)”

  1. Sir, you are very great person. I have seen many youtube vidios about theme development, but some doubts remain unchanged. After reading the your article my all doubts have gone, Because you teach us with very very good method. You have covered all points of enqueue funcitons such as why and when version should use and what is dependency etc. Thank you sir. I will read your all article now one by one.

  2. Ronny Drechsler

    Hi.
    Many thanks for this brilliant tutorial. I got it now even though I am writing a plugin using admin and front end area. But I was wondering why using this all enqueue-stuff at all. But with this tutorial I really got it now and it does really make sense to use it.
    So keep going on writing such brilliant tutorials by explaining also the common errors and mistakes and best practises.
    BR from Germany

    1. Naresh Devineni

      Thanks for the kind words, Ronny. I am glad it was helpful.

Leave a Reply

Your email address will not be published. Required fields are marked *