One of the things that often frustrates plugin and theme developers is other plugins and themes not properly loading JavaScript in the WordPress admin. The majority of the plugins and themes (especially themes) that load JavaScript load it on every single page in the admin.
This is not good.
The problem with loading JavaScript like this is that it creates conflicts with other plugins and even WordPress itself. And, quite frankly, I’m tired of my number one support question response being, “Please deactivate all your plugins to see if this corrects the issue.”
In this tutorial, I will walk you through the steps of loading your JavaScript only on the pages that are specific to your plugin.
Do you need JavaScript?
Before moving on, you should ask yourself if you plugin/theme actually needs JavaScript in the admin. If you’re trying to create some fancy-schmancy tabbed interface that doesn’t use the WordPress standard UI, you’re doing it wrong.
The only time you need to load JavaScript in the WordPress admin is when it’s absolutely necessary for what your plugin or theme is doing. In most cases, you simply need to be using the standard functions already built for you in the Settings API. This requires no JavaScript whatsoever.
There are cases when additional JavaScript is necessary. That’s what this tutorial is about — appropriately loading JavaScript on your plugin pages when JavaScript is crucial to your plugin’s functionality.
The proper hooks
Forget every other bit of code you’ve seen that loads JavaScript in the admin. There’s two hooks that you can use:
admin_enqueue_scripts: For enqueuing JavaScript files.admin_head-$pagename: For printing code directly to the header.
Those are the only two hooks you need to worry yourself with. Under no circumstances should you use admin_init or admin_menu (as many plugins/themes do) to load JavaScript. You should also never load scripts without a hook, which is extremely common in themes.
Loading JavaScript files
First, let’s take a look at adding a standard options page for a plugin. Your code would look something like the following.
add_action( 'admin_menu', 'my_example_settings_page' );
function my_example_settings_page() {
add_options_page( 'DevPress Example', 'DevPress Example', 'manage_options', 'my-example-page-name', 'my_callback_function' );
}
This is fairly standard for most developers. The trick is to figure out how to load JavaScript only on that page.
Let’s assume you need to load a JavaScript file using the wp_enqueue_script() function. Your code would look like the following.
add_action( 'admin_menu', 'my_example_settings_page' );
function my_example_settings_page() {
global $my_settings_page;
$my_settings_page = add_options_page( 'DevPress Example', 'DevPress Example', 'manage_options', 'my-example-page-name', 'my_callback_function' );
add_action( 'admin_enqueue_scripts', 'my_admin_enqueue_scripts' );
}
function my_admin_enqueue_scripts( $hook_suffix ) {
global $my_settings_page;
if ( $my_settings_page == $hook_suffix )
wp_enqueue_script( 'my-example' );
}
When you add an action to the admin_enqueue_scripts hook, your action (function) gets passed the parameter of $hook_suffix. What this allows you to do is check if $hook_suffix matches the name of the plugin’s settings page. $hook_suffix will change depending on the page that’s currently being viewed in the admin. Therefore, your script will only load when it’s needed.
Printing JavaScript in the admin <head>
Let’s suppose you’re just adding an extremely small snippet of code to the admin <head> area. Again, you don’t want to load this on all pages in the admin, even if it’s just a couple of lines. It can still conflict with other plugins. So, let’s build off your original settings page function. Your code would look like the following.
add_action( 'admin_menu', 'my_example_settings_page' );
function my_example_settings_page() {
$my_settings_page = add_options_page( 'DevPress Example', 'DevPress Example', 'manage_options', 'my-example-page-name', 'my_callback_function' );
add_action( "admin_head-{$my_settings_page}", 'my_admin_head_script' );
}
function my_admin_head_script() { ?>
<script type="text/javascript"></script>
<?php }
What we’ve done here is use the admin_head-$pagename hook to load a custom script only in the header for the plugin’s settings page. $pagename is just the name of the page currently being viewed in the admin.
Not just for scripts
This isn’t too hard. I’m not asking that you learn how to program nuclear missiles for launch. If you’re knowledgeable enough to add a custom settings page and add JavaScript in the WordPress admin, it should take you all of 30 seconds to appropriately load your scripts so that they don’t load on other admin pages.
Don’t stop with JavaScript though. The exact same rules apply for custom stylesheets too. You should even use the same hooks.
Why admin_head-$hook_suffix rather than admin_print_styles-$hook_suffix and admin_print_scripts-$hook_suffix? It doesn’t matter much all of these next to each other, but latter seem more semantically fitting as for me.
I know there are instances of WordPress core using
admin_head-$hook_suffixto directly print JavaScript in the<head>, so I went with what core is using. Core may also use the other hooks for the same thing; I haven’t looked into it completely.It’s definitely something worth investigating further.
Now if everyone would just add-hear.
Well, this is great stuff, especially as you can apply it for custom stylesheets too.
Thanks very much for this tutorial Justin. This will really come handy and help us build better themes.
Absolutely love the tutorials in here.
Up until now, I was printing my scripts and stylesheets on every admin page. *turns his head towards the wall of shame*
Many developers forget to use the right function to add content in the head section of a wordpress theme. Your code is great, but i have doubts that many people would use it in the admin side of a WordPress blog…
What if you need a script to load for multiple admin pages, but still not all. For instance, if I am using a metabox option to upload images for use within a post-type, and I only want the javascript to load for that particular post type, what would the process be?
The script would need to be available in the “post-new.php?post_type=XXX” and also in the “post.php” for editing the post.
Would it be best to use multiple hooks such as :
$post_page = ‘post-new.php?post_type=XXXX’;
$post_edit_page = ‘post.php’;
Doesn’t seem to be a way to specify post type on edit pages…
Ah, nice! This was just what I was looking for! I want to include a small google-map in a custom post types editor-pages, and I’d prefer to do it the right way! Thanks Justin!
Is there anyway to editing an existing theme to remove the call from the Admin if it’s not needed at all? What files and what could would need to be commented out?