Skip to content

Properly Add Custom JavaScripts and Styles to Pages in WordPress

This article covers how to include custom JavaScript and CSS files in WordPress. It’s a chapter from our outstanding WordPress course, Up and Running. If you want to become a knowledgeable WordPress developer, Up and Running is your best, clearest route to getting there.

The Best Way to Learn WordPress Development

Get Up and Running Today!

Up and Running is our complete "learn WordPress development" course. Now in its updated and expanded Third Edition, it's helped hundreds of happy buyers learn WordPress development the fast, smart, and thorough way.

Here's what one of them had to say:

"I think anyone interested in learning WordPress development NEEDS this course. Watching the videos was like a bunch of lights being turned on." -Jason, WordPress developer

Now, read on. 🙂

Key Takeaways:

  • The proper method to include JavaScript files and CSS stylesheets to WordPress is by enqueueing them. This allows for flexibility and customizability that adding these files directly to your site’s header does not.
  • The function to enqueue a stylesheet is called wp_enqueue_style(). The function to enqueue a JavaScript file is called wp_enqueue_script(). Both functions most commonly hook into a WordPress action hook called wp_enqueue_scripts.
  • Properly enqueueing scripts and styles—and linking to theme and plugin resources in general—requires proper knowledge of WordPress’s URL linking functions, which this chapter covers.

In this chapter, we’ll cover one of the most commonly used sets of WordPress functions: the functions that enqueue files for inclusion into a WordPress site.

There are two types of enqueue-able files worth discussing:

  1. JavaScript files: These add custom functionality to the WordPress site once it’s delivered to the user’s browser. JavaScript is very commonly used to create dynamic visual effects like interactive image sliders, flexible Pinterest-style grid or “masonry” layouts, and so on. It has many, many other uses as well.
  2. CSS stylesheets: CSS stylesheets tell a website how to look. Every WordPress theme has a style.css, and many have additional stylesheets as well. Many plugins also have one or more of their own CSS stylesheets which style the specific elements that the plugins add into the site.

CSS files are absolutely crucial to any decent website, and JS files often are as well. This chapter covers adding custom JS or CSS into your WordPress site.

Don’t Add CSS and JavaScript Directly to Your Header

First things first: Don’t add CSS and JavaScript directly to your theme’s header.php file—or other template files, for that matter. We’re about to cover the right way to add scripts to the WordPress head (and stylesheets too), and it’s not to put them directly into those files.

<!--Environment: We're in header.php.-->

<!--This is very bad! Avoid doing it in WordPress.-->
<link rel="stylesheet" media="screen" href=""  />
<script type="text/javascript' src='"></script>

Why not? Because adding JavaScripts and styles to WordPress pages in the “WordPress way” lets you do lots of helpful things down the road. For example, let’s say you want to add a new stylesheet, only on Pages. That’s pretty easy to do in WordPress, with the wp_enqueue_() functions we’ll be covering in this chapter plus a bit of conditional magic.

However, if you’re in the habit of just dumping your stylesheets directly into your theme’s header, WordPress can’t “talk to” those stylesheets at all. They’re completely outside the WordPress “factory” process—they just sit there inert. So there’s no good way to communicate the logic “Load this stylesheet only for Pages,” and your goal of a conditional stylesheet gets a whole lot harder.

There are many other ways to discuss why pasting JS and CSS files directly into header.php is a bad idea, but the real takeaway is just: don’t do it.

Don’t assume anything about file paths in WordPress—don’t hardcode URLs.

Let’s say we’ve got a special stylesheet, new.css, saved in the root directory of our theme. How do we link to it? In other words, how do we tell WordPress precisely where in the directory structure that stylesheet lives? This question comes up most immediately in using wp_enqueue_() functions, but knowing the answer is very useful in other situations as well.

The first thing to know is: Don’t assume anything about file paths in WordPress. In other words, don’t hardcode URLs. Never manually write out directories like—whether or not you’re correctly using wp_enqueue_() functions.

The reason is that everything could change. Your site might someday no longer be at—or someone else might someday use your theme on her site with a different domain name. Similarly, the wp-content, themes, and my-theme directory names are all subject to change—and if anything does, your hard-coded links will break.

Use WordPress Functions

WordPress has magical functions for every URL element but the filename.

In the URL above, only the filename itself, new.css, is relatively stable. Fortunately, WordPress has magical functions to use for every other piece of the URLs you write. Master these, and you’ll never even want to write URLs out by hand again.

To link to a resource that’s part of a theme, the crucial thing is to get to the theme’s root folder, or root directory:

To do this, you’ll use a WordPress function called get_stylesheet_directory_uri(), which returns the absolute URL correct for the active WordPress environment and running theme.

<!-- Environment: functions.php or a theme template file -->

<!-- Points to the active theme's root directory, then /photo.jpg -->
<img src="<?php echo get_stylesheet_directory_uri(); ?>/photo.jpg">

<!-- Points to the active theme's root directory, then /images/photo.jpg -->
<img src="<?php echo get_stylesheet_directory_uri(); ?>/images/photo.jpg">

The two resulting image links from the code above will look like:

  1. <img src="">
  2. <img src="">

get_stylesheet_directory_uri() will point to the active theme no matter what. That means it’ll point to the running (“parent”) theme if there’s no child theme, and to the running child theme if there is one. This is usually what you want, since if you’re working in a child theme that’s usually the thing you want to change.

However, on the occasion that you want to reference theme files in the parent theme specifically, you can use a function called get_template_directory_uri(). It behaves almost exactly like get_stylesheet_directory_uri(), but always links to the root of the parent theme, whether or not there’s a running child theme.

Since WordPress 4.7, get_theme_file_uri() has made letting child themes override parent-theme assets substantially simpler.

Since WordPress 4.7, there’s been a new function that makes it substantially simpler to let child themes override the parent-theme version of any theme asset: get_theme_file_uri(). Here’s an example use:

<img src="<?php echo get_theme_file_uri( 'images/photo.jpg' ); ?>">

And here’s how it behaves:

  1. It first searches the child theme for the referenced resource. In this example, it would search within the images folder of the child theme for photo.jpg. If it finds what it’s looking for, that’s the URI it returns back.
  2. If it doesn’t find what it’s looking for, it then checks the parent theme for the same resource, looking in the parent theme’s images folder for photo.jpg.

get_theme_file_uri() is awesome for parent themes! It means: “I’m putting this here, but it’s going to be easy for my child to override”—which is precisely the point of child themes.

Using this function liberally can save people who extend your theme with a child theme tons of work doing things like dequeueing CSS and JS resources they need to change and can’t overwrite by default. We’ll be using this very handy function a few times in the coming chapter.

Just to keep it clear, here’s a quick recap of the three functions we’ve named for linking to theme resources, and how they behave:

  1. get_stylesheet_directory_uri(): Always returns the root URL of the child theme if there’s one running. (Returns the root URL of the parent theme if there’s no child theme.) Useful for pointing to child theme resources.
  2. get_template_directory_uri(): Always returns the root URL of the parent theme, whether or not there’s a child theme running. Useful for building pieces of a parent theme that you don’t want to be easily overridden by the child theme.
  3. get_theme_file_uri( ): Links to the parent theme file, and if there’s an identically named file in the child theme, automatically links to that instead. Introduced in WordPress 4.7. Very useful for creating easy inheritance by child themes.

All of these are useful for when you want to add CSS or add JavaScript to WordPress functions.php or other ways of creating linkages. But I’m jumping the gun a bit.

If you’re writing a plugin and want to link to something inside it, you’ll use a WordPress function called plugin_dir_url(). This function returns the root directory of the plugin from which it’s called. The syntax is a little unusual, but you’ll get used to it:

<!-- Environment: a PHP file inside a plugin -->

<!-- Points to the current plugin's root directory, then photo.jpg -->
<img src="<?php echo plugin_dir_url( __FILE__ ) . 'photo.jpg'; ?>">

<!-- Points to the current plugin's root directory, then images/photo.jpg -->
<img src="<?php echo plugin_dir_url( __FILE__ ) . 'images/photo.jpg'; ?>">

The two resulting image links from the code above will look like:

  1. <img src="">
  2. <img src="">

You can use this syntax as written out above anytime you want to link to another resource inside the same plugin you’re writing.

How to Load Stylesheets and Script Files in WordPress: Introducing the wp_enqueue_() Functions

Now that we know how to link to theme and plugin resources, we’re going to tackle adding scripts and styles the correct way. Adding these scripts and styles is called enqueueing them. It works as follows:

  1. Each process of enqueueing scripts or styles uses the wp_enqueue_scripts action hook.
  2. The function to enqueue a JavaScript file is called wp_enqueue_script().
  3. The function to enqueue a CSS stylesheet is called wp_enqueue_style().

This will become clearer with examples, below.

First Example: Enqueuing a Theme’s style.css from its functions.php

The PHP script below enqueues a theme’s style.css. Without this code, a theme won’t have any styling at all!

/* Environment: We're in functions.php */

function wpshout_theme_script_and_style_includer( ) {
add_action( 'wp_enqueue_scripts', 'wpshout_theme_script_and_style_includer' );

Here’s what’s going on:

function wpshout_theme_script_and_style_includer( ) { }

We get to choose our function names, and this one we’re naming wpshout_theme_script_and_style_includer. It has no arguments, so the () are empty.

wp_enqueue_style( );

We’re going to break this line down into several pieces. First, just know that we’re calling the wp_enqueue_style() function, with two arguments.


This is the first of wp_enqueue_style()‘s two arguments. It’s a text slug—a nickname—that we choose for this stylesheet, which the rest of WordPress can use to refer to the stylesheet.


This is the second of wp_enqueue_style()‘s two arguments. It’s very important: it’s how we tell WordPress where to find the stylesheet we want to enqueue. For this situation, we’re using a very specialized WordPress function, get_stylesheet_uri(), whose only purpose is to return the URL for the style.css of the current theme.

add_action( 'wp_enqueue_scripts', 'wpshout_theme_script_and_style_includer' );

This section is our standard action hook syntax from WordPress Hooks, Actions, and Filters: What They Do and How They Work. Whenever wp_enqueue_scripts() runs (as the page’s header is building itself), wpshout_theme_script_and_style_includer() runs as well, and that’s how our style.css file gets enqueued and pulled into our HTML.

The End Result

See? On the WPShout homepage, our theme’s style.css comes through, because of the code above in functions.php.

This Example is Only Necessary for Parent Themes

This script isn’t necessary on child themes, whose style.css gets enqueued automatically. We’ll cover child themes later (in Understanding and Using WordPress Child Themes), but know that the above script is for parent themes only.

Second Example: Enqueueing Other Theme Scripts and Styles from functions.php

/* Environment: We're in functions.php */

function wpshout_theme_script_and_style_includer( ) {
		get_theme_file_uri( 'css/wpshout-other-style.css' ),
    	get_theme_file_uri( 'js/wpshout-needed-js.js' ),
    	array( 'jquery' )
add_action( 'wp_enqueue_scripts', 'wpshout_theme_script_and_style_includer' );

If you’ve understood the first example earlier, there are only a few things to learn in this one:

  1. This time, we used get_theme_file_uri() to get to the theme’s root. This will link to the file in our parent theme, or if there’s a file by the same name in the child theme it’ll automatically link to that instead, for very easy overriding by the child theme.
  2. This time, we’re also adding in a JS file, wpshout-needed-js.js. Notice how we can do enqueues of multiple scripts and styles all within one hooked function—we only need to make sure to remember when to call wp_enqueue_style() and when to call wp_enqueue_script().
  3. This time, both our script and style are in subdirectories inside our theme: our CSS stylesheet is inside a /css/ folder, and our JS file is inside a /js/ folder. Notice how easy it is to point to these subdirectories, by just adding them into the path we specify as the single argument of get_theme_file_uri().

Third Example: enqueueing Scripts and Styles From a Plugin File

Here’s what loading a single CSS stylesheet and two JavaScript files looks like, done from a PHP file in a plugin:

/* Environment: We're in a PHP file in a plugin */

function wpshout_plugin_script_and_style_includer( ) {
	/* Styles and scripts in the plugin root directory */
    	plugin_dir_url( __FILE__ ) . 'our-plugin-example-style.css'
    	plugin_dir_url( __FILE__ ) . 'our-plugin-example-js.js',
    	array( 'jquery' )
    /* A script in a subdirectory */
    	plugin_dir_url( __FILE__ ) . 'js/our-plugin-more-js.js',
    	array( 'jquery' )
add_action( 'wp_enqueue_scripts', 'wpshout_plugin_script_and_style_includer' );

The only new thing to learn here is the workings of the plugin_dir_url() function. If you don’t get PHP’s __FILE__ magic constant, we’d advise not thinking too hard about it, and just knowing that the above will work.

enqueueing with Dependencies

One thing we haven’t explained yet is the third argument in most of our JavaScript enqueues: array( 'jquery' ). What does this mean?

This means that we’re declaring jQuery as a dependency: something that our own JavaScript file must use in order to work properly itself. Dependencies matter in two situations:

  1. If you want a stylesheet to load after another stylesheet, since later styles override earlier ones.
  2. If your JavaScript file relies on another JS file to run properly—in particular, on jQuery.

This second case is the most common, and it’s the reason we bring up dependencies at all. If your JavaScript files use jQuery’s syntax, you’re best off declaring jQuery as a dependency, as follows:

	get_theme_file_uri( 'example-js.js' ),
	array( 'jquery' )

Here, we’ve filled in wp_enqueue_script()‘s third argument: its dependencies. This argument is required to be an array, and it’s an array of “slugs” (nicknames) of the JavaScript files our new file depends on.

In our case, the array only has one thing in it: 'jquery', the slug for the jQuery.js file that WordPress loads in automatically.

Again, you can also do the same thing for stylesheets in wp_enqueue_style(), with an array of CSS slugs as dependencies. The main reason to do this is to make sure your stylesheet loads later than (and so overrides) those other CSS files. Most times, though, you won’t need to bother with this, since child theme stylesheets generally override what they’re supposed to by default.

What We’ve Learned

The enqueue functions are among the most usable and useful in WordPress. With this knowledge locked in, you can confidently add JavaScript to WordPress page headers, modify and supplement CSS, and a whole lot more. Simply knowing to use these functions rather than pasting in scripts and styles into the WordPress header will improve the quality of your work in WordPress significantly.

Summary Limerick

If you actually know what you’re doing,
Then you’ll add scripts and styles by enqueueing.
They’ll be pulled, to the letter,
To the (footer or) header
Of each page your users are viewing.

Quiz Time!

  1. You shouldn’t add scripts and styles directly to your site’s header because:
    1. It removes those scripts and styles from the flexibility and customizability of WordPress’s “factory”
    2. It won’t work on older browsers
    3. It causes the page to load more slowly than wp_enqueue_()
  2. To access the file plugin-example-style.css in the root directory of a plugin, use:
    1. get_stylesheet_directory_uri() . '/plugin-example-style.css'
    2. plugin_dir_url( __FILE__ ) . 'plugin-example-style.css'
    3. plugin_dir_url( __FILE__ ) . '/plugin-example-style.css'
  3. To access wpshout-needed-js.js inside folder /js/ inside the active theme’s root directory, use:
    1. get_stylesheet_directory_uri() . '/js/wpshout-needed-js.js'
    2. get_template_directory_uri() . '/js/wpshout-needed-js.js'
    3. get_template_directory_uri() . 'js/wpshout-needed-js.js'

Answers and Explanations

  1. A. Manually pasting in scripts and styles prevents WordPress from, for example, dequeueing these scripts and styles, conditionally loading them, or programmatically moving scripts to the footer to reduce load times.
  2. B. plugin_dir_url is the correct function, and it doesn’t take a leading /.
  3. A. get_stylesheet_directory_uri() always points to the active theme directory, even if it’s a child theme; get_template_directory_uri() points to the parent theme directory if the current theme is a child theme. Note the need for a leading / before js.
Yay! πŸŽ‰ You made it to the end of the article!
David Hayes

Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Murray Chapman
June 13, 2019 7:21 pm

Thanks for the quick overview yet you nailed it and I really appreciate you sharing your insight.

David in Mississippi
May 21, 2019 2:17 pm

You are absolutely right in your earlier post that the WP Codex and Function Reference needs serious help. Your explanations are much better, but to improve them still more… When teaching a function, as in a function reference or in this article, the elements to include, so as to be most effective, are: * The Function Name with cleartext placeholder parameters * A summary version of what the function does. * A detailed explanation of what the function does, with full explanations of what each parameter is and does, parameter limits if any, and any explanation of consequences if you induce errors in calling the function, such as parameters out of spec * Two or more examples, covering the most common use cases of the function. These examples should include: ** INPUT – An explanation of the situation from which you need to call the function, including why you need to call this function and not some other. ** ACTION – The calling routine’s source code, including setting parameter variables and explaining where each setting comes from and why it is used this way. ** OUTPUT – show a clear illustration of what value is returned by the function, and… Read more »

Or start the conversation in our Facebook group for WordPress professionals. Find answers, share tips, and get help from other WordPress experts. Join now (it’s free)!

Would love your thoughts, please comment.x