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...

  • 1
    Generically speaking, one is an action and the other is a filter. Actions are for doing something when an event occurs, and a filter is for modifying something before it is used.
    – Milo
    Jan 7, 2016 at 19:20

1 Answer 1


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 Answer 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);
  • 2
    You should still use is_admin() || add_action( … ), because there is no need to pollute the list of registered callbacks if you don't need it.
    – fuxia
    Jan 8, 2016 at 5:05
  • Interesting point toscho... I've been making wordpress sites for about ten years now and I've never seen that format before using the or symbol. I actually asked a question about how to properly format conditions a couple years ago if you feel like adding that approach. Jan 8, 2016 at 5:55
  • Toscho I updated my answer based on your suggestion. Is that what you meant? Jan 8, 2016 at 6:13
  • Yep, looks right. :)
    – fuxia
    Jan 8, 2016 at 6:21
  • send_headers would win out every time and would ensure that it was loaded even if added after the page was cached” — Just to note that send_headers does not work to beat page caching used by plugins such as W3 Total Cache in my tests, or any static caching that effectively bypasses WordPress at the server level.
    – Nick
    Apr 9, 2018 at 7:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.