WordPress offers multiple methods to add styles and scripts for frontend and admin, both for adding files and straight out outputting variables/output. This post goes into detail with code examples of how to add scripts and styles to WordPress the correct way.

Scripts and styles can be registered and enqueued by defining unique handles (slug-like IDs), making it possible for WordPress to eliminate duplicates, such as multiple jQuery libraries, and to handle dependencies (which style or script to load before this and that).

If there is no specific need for registering styles or scripts, you can just enqueue them right away, skipping the registering. It is also possible to deregister or dequeue styles and scripts (wp_dequeue_script and wp_dequeue_style) by referring to the handle. It usually helps adding a higher number in the hook’s priority (making it run after the hook where the items were enqueued).

PS: Adding styles and scripts to Gutenberg (both admin and frontend blocks), is explained in my post Gutenberg: The Basics.

Adding scripts and styles to frontend

For adding styles and scripts to frontend only, use the hook wp_enqueue_scripts. Despite the hook’s name, it is used for both scripts and styles. Here is an example of enqueuing a stylesheet and a javascript file in a theme:

add_action('wp_enqueue_scripts', function() {
	// Styles
	wp_enqueue_style('main-style', get_stylesheet_directory_uri().'/style.css', [], '1.0');

	// Scripts
	wp_enqueue_script('main-script', get_stylesheet_directory_uri().'/assets/js/main.js', ['jquery'], '', true);
});

The third argument to both styles and scripts is an array with dependencies. E.g. for scripts you may want to load the jQuery library before your script file. Note: WordPress installations come with a bunch of common script libraries included (for example jQuery, jQuery UI, Backbone and Underscore). As long as you add any of these handles as dependency in your enqueue_script, WordPress will enqueue these, so you don’t have to add your own files for these libraries.

The fifth argument for scripts is whether or not the script should be loaded in the end of <body> (in footer), instead of inside the <head> tag.

For use in a plugin you need to use other methods to get the URL to a local file, for example plugin_dir_url(__FILE__).

Adding scripts and styles to admin

WordPress offers another hook, admin_enqueue_scripts, for adding styles and scripts only to admin. Use the same methods as above for registering, enqueuing and localizing scripts and styles:

add_action('admin_enqueue_scripts', function() {
	global $pagenow, $post_type;
	// Example: $hook == 'edit.php'
	// Example: $post_type == 'post'
	
	// wp_enqueue_style or wp_enqueue_script
});

Adding scripts and styles to login page

Because neither of the hooks above appears in the admin login screen, WordPress offers a separate hook for this purpose, login_enqueue_scripts.

add_action('login_enqueue_scripts', function() {
	// wp_enqueue_style or wp_enqueue_script
});

Ouputting Javascript variables

For outputting Javascript variables (e.g. getting paths, translated strings or other variables, you can use wp_localize_script. This function requires a enqueued script handle. Second parameter would be the variable name, and third its value. The value can be an array, like so:

add_action('wp_enqueue_scripts', function() {
	// wp_enqueue_script('main-script');  // Must exist!
	$variable_to_js = [
		'ajax_url' => admin_url('admin-ajax.php')
	];
	wp_localize_script('main-script', 'Theme_Variables', $variable_to_js);
});

Inside your script you have access to the variables passed, like so:

jQuery(document).ready(function($) { 
	console.log(Theme_Variables.ajax_url);
});

In this hook you can access global variables $pagenow and $post_type to further specify where you want to enqueue your styles and scripts.

Outputting inline styles

If you need to output inline styles, for example for theme variables you have set up in Customizer (e.g. using get_theme_mod), you can output these by using the wp_add_inline_style function. It works pretty similar to outputting Javascript variables, in which you need to provide an enqueued style handle:

add_action('wp_enqueue_scripts', function() {
	// wp_enqueue_style('main-style');  // Must exist!

	$color = get_theme_mod('my-custom-color');  // e.g. #FF0000
	$custom_css = "
		body {
			background: {$color};
		}";
        wp_add_inline_style('main-style', $custom_css);
});

Adding async tags to scripts

Unfortunately there’s no direct function or filter to add async to your script tags, but we can achieve this by manipulating the string WordPress uses to output the script tags for all enqueued scripts, like so (remember to specify your script by its handle):

add_filter('script_loader_tag', function($tag, $handle, $src) {
	if ('main-script' != $handle) {
		return $tag;
	}
	return str_replace('<script', '<script async', $tag);
}, 11, 3);

Useful documentation links