By

Close-up: wp_head Action Hook

I recently needed to add some code just before the closing header tag on my theme pages, via a WordPress Plugin.

Of course, I made use of the wp_head action hook which is perfect for this task. However, my requirement was a little more specific than this. What I actually needed was to make sure the code was guaranteed to be the LAST code added right before the closing head tag.

This is a little tricky because there are probably lot’s of functions registering with the wp_head hook every time one of your theme pages loads. To see this let’s use a slightly modified version of the excellent list_hooked_functions() function which can be found on WpRecipies (authored by Rarst) here.

Our modified version of this function just changes the formatting slightly. The code for this is below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function list_hooked_functions($tag=false){
	global $wp_filter;
	if ($tag) {
		$hook[$tag]=$wp_filter[$tag];
		if (!is_array($hook[$tag])) {
			trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
			return;
		}
	}
	else {
		$hook=$wp_filter;
		ksort($hook);
	}
 
	echo '<div style="color: black;font-family: Courier New;">';
	foreach($hook as $tag => $priority){
		echo "Hook Name: <strong>$tag</strong><br /><br />";
		ksort($priority);
		foreach($priority as $priority => $function){
			$comma_flag = 0;
			echo $priority.": ";
			foreach($function as $name => $properties){
				if($comma_flag > 0) { echo ", "; }
				echo "$name";
				$comma_flag++;
			}
			echo "<br />";
		}
	}
	echo '</div>';
	return;
}

Adding our modified version of this function to the Plugin (and adding a call to it) gives us the output below.

It is important to add the call to list_hooked_functions() function from the plugins_loaded hook, as follows:

1
2
3
4
function wpsym_pluginsloaded() {
	list_hooked_functions('wp_head');
}
add_action( 'plugins_loaded', 'wpsym_pluginsloaded' );

This ensures that all Plugins have loaded and registered their hooks, before we attempt to access the list of callback functions.

As you can see, there are many callback functions already defined for the wp_head hook, and that’s without any callback functions we wish to add ourselves! The functions called for the wp_head hook are listed by priority number, and this is the order in which they will be called during a normal page load (i.e. highest number = lowest priority, and will be called last. This is easy to get confused so watch out!).

Each callback function is assigned a priority number (a default number of 10 is assigned if you don’t explicitly define one). The most common priority number, as you can see, is 10 which is no surprise seeing as this is the default number. Most callback functions do not specify a priority number and will leave it to be assigned the default value.

So, as a solution to our problem I could simply add my callback function for the wp_head hook and assign it a very high value (i.e. very LOW priority). Well, this would work in most cases but is not very elegant, and is certainly not guaranteed to work.

What we need is something a little more elegant that will ensure it has the highest hook priority number. So, how do we do this? The list_hooked_functions() function makes use of the $wp_filter global variable. This holds information about all hooks that have callback functions registered.

What we want to do is to find the highest hook priority number (i.e. the hook with the lowest output priority), and define a NEW callback function for wp_head and give it a priority value of one more than the highest number. The following code will take care of this:

1
2
3
4
5
6
7
8
// Return the lowest priority number from all the functions that hook into wp_head
global $wp_filter;
$lowest_priority = max(array_keys($wp_filter['wp_head']));
 
echo "&lt;pre&gt;";
echo "Lowest priority: ".$lowest_priority."<br />";
echo "Set the priority of your wp_head hook callback function to: ".($lowest_priority + 1)."<br />";
echo "&lt;/pre&gt;";

Here, we are assigning the $lowest_priority variable the value of the highest hook priority number, from the array of all priority numbers (for the wp_head hook).

This will ensure that our new callback function always has the lowest priority and the HTML code we echo from this callback function will always be the last HTML added to the head tag.

Let’s see a proper example of this. To test, we are going to now register several callback functions for the wp_head hook from our Plugin. We will then analyse all callback functions registered to the wp_head hook, and then see if we can automatically add a new callback function that we can guarantee will be the very last one added to the head tag.

Here is the code for this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
function wpsym_pluginsloaded() {
	// Return the lowest priority number from all the functions that hook into wp_head
	global $wp_filter;
	$lowest_priority = max(array_keys($wp_filter['wp_head']));
 
	echo "&lt;pre&gt;";
	echo "Lowest priority: ".$lowest_priority."<br />";
	echo "Set the priority of your wp_head hook callback function to: ".($lowest_priority + 1)."<br />";
	echo "&lt;/pre&gt;";
 
	add_action('wp_head', 'wpsym_head7', $lowest_priority + 1);
 
	$arr = $wp_filter['wp_head'];
 
	list_hooked_functions('wp_head');
}
add_action( 'plugins_loaded', 'wpsym_pluginsloaded' );
 
// Add several wp_head hooks
add_action('wp_head', 'wpsym_head', 5);
add_action('wp_head', 'wpsym_head1', 19);
add_action('wp_head', 'wpsym_head2', 23);
add_action('wp_head', 'wpsym_head3', 2);
add_action('wp_head', 'wpsym_head4');		// default priority (10)
add_action('wp_head', 'wpsym_head5', 229);
add_action('wp_head', 'wpsym_head6', 73);
 
// wp_head callback functions
function wpsym_head() {
	echo "<style type=\"text/css\">#content {color:red}</style>";
}
function wpsym_head1() {
	echo "<style type=\"text/css\">#content {color:blue}</style>";
}
function wpsym_head2() {
	echo "<style type=\"text/css\">#content {color:yellow}</style>";
}
function wpsym_head3() {
	echo "<style type=\"text/css\">#content {color:lime}</style>";
}
function wpsym_head4() {
	echo "<style type=\"text/css\">#content {color:#8A2BE2}</style>";
}
function wpsym_head5() {
	echo "<style type=\"text/css\">#content {color:#FF8C00}</style>";
}
function wpsym_head6() {
	echo "<style type=\"text/css\">#content {color:#808080}</style>";
}
function wpsym_head7() {
	echo "<style type=\"text/css\">#content {color:green}</style>";
}

Adding this to our Plugin code and activating it we get the following output:

We can see the callback function for the wp_head hook with the lowest priority has a value of 229. Therefore, we know that adding one to this number and making it the priority value for a new callback function will guarantee it is called after EVERY other callback function (for the wp_head hook).

We know that our callback function IS the last one called as it turns the text green, and this style is defined in the wpsym_head7() function (the last callback function we added after all the currently registered hooks were analysed).

Finally let’s take a peek at the page source to verify our findings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<head>
<meta charset="UTF-8" />
<title>wp3.01 | Just another WordPress site</title>
<link rel="profile" href="http://gmpg.org/xfn/11" />
<link rel="stylesheet" type="text/css" media="all" href="http://localhost/wordpress-3.01/wp-content/themes/twentyten/style.css" />
<link rel="pingback" href="http://localhost/wordpress-3.01/xmlrpc.php" />
<link rel="alternate" type="application/rss+xml" title="wp3.01 &raquo; Feed" href="http://localhost/wordpress-3.01/feed/" />
<link rel="alternate" type="application/rss+xml" title="wp3.01 &raquo; Comments Feed" href="http://localhost/wordpress-3.01/comments/feed/" />
<style type="text/css">#content {color:lime}</style><style type="text/css">#content {color:red}</style><link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://localhost/wordpress-3.01/xmlrpc.php?rsd" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://localhost/wordpress-3.01/wp-includes/wlwmanifest.xml" /> 
<link rel='index' title='wp3.01' href='http://localhost/wordpress-3.01/' />
<meta name="generator" content="WordPress 3.0.1" />
<style type="text/css">#content {color:#8A2BE2}</style>
<style type="text/css">#content {color:blue}</style>
<style type="text/css">#content {color:yellow}</style>
<style type="text/css">#content {color:#808080}</style>
<style type="text/css">#content {color:#FF8C00}</style>
<style type="text/css">#content {color:green}</style>
</head>

I should point out that the only caveat to this method, as it stands, is that it can’t take into account any other Plugins that are using the plugins_loaded hook to add html to the head tag (as we ourselves are doing). The only thing you can do in this case is to add a suitably high priority number to your plugins_loaded callback function.

I can post a fully working Plugin of this example if there is enough demand. So let me know.

Have fun!

2 Responses to Close-up: wp_head Action Hook

  1. Pingback: Bookmarks for June 23rd < fugaz

  2. Jordan says:

    I am interested in seeing the fully working plugin if you have it.