wp_headers vs send_headers. When to use each?

I’ve seen wp_headers and send_headers both used before for the same thing and I’m wondering how you’re suppose to know which one to use and when…

On the send_headers codex page there’s an example of adding the X-UA-Compatible: IE=edge,chrome=1 for Internet Explorer backward compatibility since the meta tag often fails on intranet sites if loaded too late.

This is what the send_headers example looks like:

add_action( 'send_headers', 'add_header_xua' );
function add_header_xua() {
    header( 'X-UA-Compatible: IE=edge,chrome=1' );

However wp_headers can also do this:

apply_filters ( 'wp_headers', array $headers, WP $this )

add_filter( 'wp_headers', 'wpieeam_headers' );
function wpieeam_headers($headers) {
    if (!is_admin()) {
        $headers['X-UA-Compatible'] = 'IE=edge,chrome=1';    
    return $headers;

Update: I actually just noticed that a conversation on this more or less started on a similar question a couple years ago…

Also, does send_headers have to do with only the front end? I’ve seen wp_headers do checks like this:

if ( isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) )


if (!is_admin()) 

so I’m thinking that maybe send_headers doesn’t have to make those checks…


Ok so I think I figured it out…

Both of these work for the most part as you’d expect by sending http / php headers to the browser. wp_headers is actually a filter inside the send_headers() functions.You can use this to modify the headers before they’re sent to the browser with some exception. wp_headers won’t be able to do anything if it’s a static cached page were dealing with…

This is where the send_headers hook comes into play. After the wp_headers filter, the send_headers() function checks if Last-Modified has been sent with would tell us if the page was cached or not and then lets us hook into it after caching, content type, etc have all been sent.

So for my example using X-UA-Compatible, while they both work, I’m inclined to use send_headers. Why? For one if you were to add both of these, send_headers would win out every time and would ensure that it was loaded even if added after the page was cached.

While using a <meta> tag like many popular frameworks use would also work for x-ua-compatible, it will not work in many browsers unless loaded almost immediately after the opening head tag. This is caused by various reason like if the “intranet” setting is set network wide. For this reason using the php method is safer. However, if you were to add both, the meta tag would win (assuming it was including early enough.

In regards to X-UA-Compatible compatible, I’m hoping this will be irrelevant soon since Microsoft is dropping support for older versions of IE next week!

Also, I tested the wp_headers filter without using the is_admin() check and it won’t modify the admin_headers so that check is unnecessary.

If you did need to modify the admin headers for some reason, I know you can do it like this, but I’m not sure if it would work all the time…

function admin_add_my_header() {
    header('X-UA-Compatible: IE=edge,chrome=1');    
add_action( 'admin_init', 'admin_add_my_header', 1 );

Updated based on Toscho’s suggestion to check for admin:

is_admin() || add_action('send_headers', function(){ 
    header('X-UA-Compatible: IE=edge,chrome=1'); 
}, 1);

Leave a Comment