There has been a lot of talk over the last two days about loading scripts, particularly jQuery, correctly in WordPress themes and plugins, and anyone who follows me on Twitter probably knows that this is an issue I bring up a lot. When providing support for my plugins, I discover themes (and plugins) that are loading jQuery incorrectly and thus causing a conflict with my plugin all the time. It is, unfortunately, a very common issue, so now I’m going to show you how NOT to load scripts in the WordPress admin, and also walk you through the correct way of doing it.
A lot of WordPress plugins use jQuery scripts in their settings or other admin pages, and a lot of them do it incorrectly. While I don’t often see this, here is an example of how you absolutely should never do it:
1 2 3 4 | function pw_loading_scripts_wrong() { echo '<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>'; } add_action('admin_head', 'pw_loading_scripts_wrong'); |
Using a function like this will cause a second version of jQuery to be loaded into the head section of every single page in the WordPress admin. Not only will this place the extra jQuery library everywhere it is not needed, it will also most likely break most WordPress interfaces that rely on jQuery.
What about if you want to load a custom jQuery script, but not jQuery itself? You could do this:
1 2 3 4 | function pw_loading_scripts_wrong() { echo '<script type="text/javascript" src="https://yoursite.com/path/to/custom.js"></script>'; } add_action('admin_head', 'pw_loading_scripts_wrong'); |
However, if you do this, you will mostly likely be ensuing the wrath of plugin developers when they find you are breaking their correctly coded systems.
These two examples are not, however, the only incorrect ways to load jQuery and custom JS scripts. Here is another:
1 2 3 4 | function pw_loading_scripts_wrong_again() { wp_enqueue_script('custom-js', 'wp-content/my-plugin-dir/js/custom.js'); } add_action('admin_init', 'pw_loading_scripts_wrong_again'); |
You may ask why this is wrong, especially as it might look like the function does everything in an okay manner, but it doesn’t.
The first reason it is incorrect is that it is using the “admin_init” hook to load the scripts, which is not the correct hook to use. Instead the admin_enqueue_scripts hook should be used in order to ensure that the scripts are loaded at the right time.
The second reason it is incorrect is that, just like in the first two examples, the custom.js file is loaded into every single admin page in WordPress. You should never, ever do this. Always do your best to make sure your plugin is as efficient as possible and is only loading resources when those resources are needed.
And the third reason it is incorrect is because it is using a relative path for the custom.js file. It might load the file correctly in some WP installs, but it will fail in others. You should always load scripts through a complete path.
How do we fix the three problems with this example? Well, let’s start by using the correct hook:
1 2 3 4 | function pw_load_scripts() { wp_enqueue_script('custom-js', 'wp-content/my-plugin-dir/js/custom.js'); } add_action('admin_enqueue_scripts', 'pw_load_scripts'); |
That’s a little better, but not quite. Let’s now fix the problem of the script being loaded through a relative path. To do this, we should use a function that outputs the exact URL to the directory the file is stored in. When writing plugins, the best function to use for this is plugins_url(). Assuming our custom.js file exists inside of a folder called js that is in our plugin’s main folder, the exact function will look like this:
plugins_url( 'js/custom.js' , dirname(__FILE__) ) |
Add this into our function and we have this:
1 2 3 4 | function pw_load_scripts() { wp_enqueue_script( 'custom-js', plugins_url( 'js/custom.js' , dirname(__FILE__) ) ); } add_action('admin_enqueue_scripts', 'pw_load_scripts'); |
This is getting much closer to being correct, but we still have the problem of our script being loaded on all pages. How do we take care of that?
Luckily, the admin_enqueue_scripts hooks allows us to pass a variable called $hook to our pw_load_scripts() function. This $hook will contain the name, or hook, of the current admin page, which we can then use to conditionally load our scripts.
For this first example, let’s assume that we want to load some extra JS into the edit.php page, which is the primary page/file loaded when viewing a list of any post type, such as the Posts or Pages page.
1 2 3 4 5 6 7 8 | function pw_load_scripts($hook) { if( $hook != 'edit.php' ) return; wp_enqueue_script( 'custom-js', plugins_url( 'js/custom.js' , dirname(__FILE__) ) ); } add_action('admin_enqueue_scripts', 'pw_load_scripts'); |
This says the following: “if we are NOT on the edit.php page, get out of here and do not continue this function”, which means that our “custom.js” file will only be loaded if we ARE on the edit.php page. Pretty cool right?
What about some of the other pages? Perhaps you want to load scripts anytime a post list, a new post, or an edit post page are displayed? Then we can do this:
1 2 3 4 5 6 7 8 | function pw_load_scripts($hook) { if( $hook != 'edit.php' && $hook != 'post.php' && $hook != 'post-new.php' ) return; wp_enqueue_script( 'custom-js', plugins_url( 'js/custom.js' , dirname(__FILE__) ) ); } add_action('admin_enqueue_scripts', 'pw_load_scripts'); |
You can do the same thing for any page in the WordPress admin, and here is a list of some of the other pages:
- index.php – the Dashboard
- upload.php – the Media library
- link-manager.php – the Links page
- edit-comments.php – the Comments list page
- comment.php – editing a specific comment
- themes.php – Appearance
- widgets.php – Appearance > Widgets
- nav-menus.php – Appearance > Menus
- plugins.php – Plugins
- users.php – Users
- options-general.php – Settings > General
- options-writing.php – Settings > Writing
Most pages are named pretty straight forward, so it’s easy to figure out which files display which pages, but what about custom admin pages? Many (if not most) plugins create custom settings pages in the WordPress admin. How do we go about only loading JS files on those pages? It’s actually quite easy. There are multiple ways to do it actually, but the way I want to show you also assumes you have created your settings page correctly.
Settings pages are created like this:
1 2 3 4 5 | function pw_create_settings_page() { global $pw_settings_page; $pw_settings_page = add_options_page(__('My Plugin Settings', 'my-domain'), __('Plugin Settings', 'my-domain'), 'manage_options', 'my-page-slug', 'pw_callback_function'); } add_action('admin_menu', 'pw_create_settings_page'); |
The settings page is stored in a global variable called $pw_settings_pages (yours will be named differently). This variable will then be equal to the $hook variable in our admin_enqueue_scripts function, and since it is a global variable, we can access it, like so:
1 2 3 4 5 6 7 8 9 10 | function pw_load_scripts($hook) { global $pw_settings_page; if( $hook != $pw_settings_page ) return; wp_enqueue_script( 'custom-js', plugins_url( 'js/custom.js' , dirname(__FILE__) ) ); } add_action('admin_enqueue_scripts', 'pw_load_scripts'); |
We have now successfully loaded our custom script into our plugin’s settings page AND avoided loading it anywhere else within the WordPress admin. Awesome.
The process itself is quite simple and there is not a single reason you shouldn’t be doing it this way.

Hi Pippin, I’m curious if this theme, http://www.rootstheme.com/ which I use frequently is subject to this jQuery loading issue. It looks like there is something going on in regards to sniffing out the admin pages… But I figured you’d be able to tell quickly!
After exploring the source code on Github, I don’t see anything. Doesn’t actually look like it loads a single script in the admin
how do you load the script only on a specific post type edit/new screen?
Inside of your function hooked to “admin_enqueue_scripts”, use something like this:
That will make it so only the scripts below that line will get loaded if you are on the post type “YOUR POST TYPE”.
Tried the code below Pippin but it didn’t work. I removed the extraneous opening bracket “(” after the if, but still didn’t work. But when I called the global $post it worked fine.
global $post;
if ( !isset($post) || 'product' != $post->post_type )
return;
Doesn’t work in what way? Can you elaborate?
Maybe I was doing something wrong, but I added it to my plugin’s main file as a conditional to load my JS scripts, however the scripts failed to load. But then, by adding the call to the global $post variable first, your code worked, and my scripts loaded just fine. So I’m not sure if everyone has to call the global first, or if it’s just something peculiar to my own set up, but that’s the only way it would work for me.
My full script is this:
// check if in Admin section AND on Edit-Post page (post.php).
if( !is_admin() || $hook != 'post.php' )
return;
// now check to see if the $post type is 'product'
global $post;
if ( !isset($post) || 'product' != $post->post_type )
return;
wp_enqueue_script(........
Anytime you reference $post (except inside of a loop), you must set the global.
Cheers Pippin – and my apologies if my comment was too ‘obvious’, I’m not that far up the learning curve yet! Thanks again for all you do!
Thanks for this Pippin. The method I was using before was not nearly as clean and straight forward as using the $hook variable. This is great!
excellent scripts, I hope I serve to my projects
Just out of curiosity, what was wrong with admin_print_styles-$page? The only difference between the old way of enqueing and admin_enqueue_scripts is using global variables for custom options and theme pages, which is, pure evil I guess?
Oh, I’ve also checked wp_print_styles() and looks like it got replaced with wp_enqueue_scripts() too! Naming is a bit confusing, but it’s still better to have one action, than two separate ones for js and css.
Cheers!
great post, Im just wondering one thing. The examples show how to not load pages on optional admin pages, but what about random posts and pages that are not admin which use the shortcode or a widget call to the plugin.
I would like to only load the scripts and css on certain non admin pages.
I understand this is not what the post is about, but I cant seem to find the answer and this is the most thorough post I have seen on this issue.
Saw your comment over here: http://pippinsplugins.com/load-scripts-if-post-has-short-code/comment-page-1/#comment-57401
I have a question.
Suppose I have plugin which make some changes to the frontend of my blog using javascript and my javascript code requires jquery. How should I load properly the javascript code. Some themes enque them but not all, so whats the best method do do it it from a plugin.
The only proper way to do it is with wp_enqueue_script().
Hey Pippin – first of all thanks for this great site, I just found it last week and it’s awesome.
I’m glad I found this post, but I can’t for the life of me get the last part to work on my Submenu page. It either works on all pages in the admin menu or none. It might be because of my design, but I don’t know.
From my base plug-in page I install my table in the db and then call an adminmenu.php page.
On the adminmenu.php page I create my main menu page (caling add_menu_page) then I create my submenu pages (calling add_submenu_page). Each of these calls a function that simply has an include of the PHP file with the page content.
Here is some code if it helps -
===========================================================
My base plugin page contains the following:
if (is_admin () ){
require_once( plugin_dir_path( __FILE__ ) . ‘includes/adminmenu.php’);
}
===========================================================
adminmenu.php page:
//Create the Admin Menus system and content
function bl_recp_admin_menu () {
global $bl_recp_manageOptions_page;
global $bl_recp_clientManager_page;
//CREATE MAIN MENU
$bl_recp_manageOptions_page = add_menu_page( ‘RE Client Portal Settings’, ‘RE Client Portal’, ‘manage_options’, __FILE__, ‘bl_recp_settings_content’, plugins_url(‘/images/icon_arrow.gif’,plugin_dir_path( __FILE__ )) );
//Create “Manage Clients” Sub Menu
$bl_recp_clientManager_page = add_submenu_page( __FILE__, ‘RE Client Portal – Client Manager’, ‘Manage Clients’, ‘manage_options’, __FILE__.’_client_manager’, bl_recp_manageclients_page);
}
//Call the General Setting Page HTML
function bl_recp_settings_content () {
//Add the HTML
include( plugin_dir_path( __FILE__ ) . ‘general_settings.php’);
}
//Call the Manage Clients Page HTML
function bl_recp_manageclients_page () {
//Add the HTML
include( plugin_dir_path( __FILE__ ) . ‘client_manager.php’);
}
add_action(‘admin_menu’, ‘bl_recp_admin_menu’);
===========================================================
client_manager.php has all the form data and other html. I need the script to run on the file, so using this tutorial this is what I have done:
I added the following to the adminmenu.php file:
function bl_recp_load_scripts() {
global $bl_recp_clientManager_page;
if( $hook != $bl_recp_clientManager_page )
return;
wp_enqueue_script(‘recp-client-insert-js’, ‘/wp-content/plugins/js/test_client_insert.js’, ”, ’0.0.1a’);
}
add_action(‘admin_enqueue_scripts’, ‘bl_recp_load_scripts’);
===========================================================
As is it doesn’t load the script on ANY page , but if I comment out the global line, the if($hook line and the return line the script loads…it just loads on every page.
Any ideas? I want to do this write, but I need to move on and I’ve spent 2 days trying to figure this out.
Thanks again, being brand new to WP Plugin development, your site has already helped me a tone.
Can you post the code to snippi.com and share the link? That way the formatting remains.
Of course. Here is the link: http://snippi.com/s/0naubgv
I see the problem. Change
function bl_recp_load_scripts() {to
function bl_recp_load_scripts( $hook ) {That was it. Thanks!
Great!