So what is wp_head() anyway?

When you’re developing a Wordpress theme from scratch, you’ll put something like this into your header.php:

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>

That’s the beginning of a basic HTML5 file, including various little declarations that say we want modern (not ‘quirks’/compatibility) parsing, no character-set weirdness please, and we’re responsive (that is, mobile-friendly).

As this is a Wordpress theme, though, we need to give Wordpress a hook to add some more bits and pieces into <head>, including some of its own CSS stylesheets, the admin toolbar (when we’re logged in), and – if you’re doing things the easy way, as we’ll talk about below – a <title> tag.

It’s just a little addition – here:

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<?php wp_head(); ?>
</head>

What happens if you don’t use wp_head()?

This blog takes its name from the wp_head() function because it is, in a way, the ‘ABC’ of Wordpress theme development – yet it is also easy for someone who is ‘learning by doing’ to leave it out, whether by accident or design. (In my earlier days I was of the opinion that I don’t need all that extra junk Wordpress throws up into my code anyway. While there is some unnecessary cruft, though, there are better ways to remove it.)

Leaving out wp_head() is a road that leads to strange bugs later, from the non-appearance of the admin toolbar to plugins failing in unexpected ways. wp_head() is not just for Wordpress itself: it is a hook for anything else that needs to be put into the header without being ‘hard coded’ into your theme. And as your theme grows, you’ll find it useful to use that hook yourself too! Here are some examples.

Automatic <title> tags

Are you still putting <title> tags into your header by combining your site name and post titles with a mess of functions and | separators? There is a much easier way, and wp_head() is what makes it possible. Just add this line to your functions.php:

add_theme_support( 'title-tag' );

Despite the name, this actually declares that your theme does not include a <title> tag, meaning Wordpress can handle it for you instead. Wordpress then automatically adds a <title> as part of the wp_head() call – whether you’re showing a page, post, category, tag, or whatever, it will show the right thing in the title bar.

Adding CSS stylesheets, the Wordpress way

Another part of your <head> that can be fiddly is inserting the right <link> tags to add your CSS stylesheets, especially getting it to spit out the correct path to wp-content/themes/your-theme. Here’s another short snippet to add to functions.php:

add_action( 'wp_enqueue_scripts', function () {
    wp_enqueue_style( 'style', get_stylesheet_uri() );
});

Now wp-content/themes/your-theme/style.css is automatically inserted into the wp_head() section, with the correct <link> tag and path. (Note: the above uses an inline ‘anonymous function’, which I find shorter and clearer. Many other examples you’ll see will define a function first, then put that function’s name as the second parameter of add_action().)

What if you want to add more than one CSS file? No worries:

add_action( 'wp_enqueue_scripts', function () {
    wp_enqueue_style( 'style', get_stylesheet_uri() );
    wp_enqueue_style( 'extra', get_template_directory_uri() . '/extra.css' );
});

There is a similar function, wp_enqueue_script(), for Javascript includes. Read more in the Wordpress Theme Handbook.

…and remember wp_footer() too

There is another function, wp_footer(), that should be called from your footer.php. It serves much the same purpose as wp_head(), but this time for scripts and other bits that belong at the end of the HTML. In particular, wp_footer() is needed before the admin toolbar will appear. So don’t forget!