In response to the question asked here I find myself and this other user needing a solution to set a last modified header that contains the date and time of the most reicent post. Since we both in many themes have the home page set to a static page and then coding our dynamic content into the static files we are missing that important header to make sure cached homepages update when there are new posts.

So, how can we set a last modified HTTP header on a page that it set to the most recent Post?

4 Answers 4


Last-Modified header for visitors on the front-page

It's useful to see how the Last-Modified header is added to the feeds, in the wp::send_header() method.

If we want to be able to use is_front_page(), then the filters wp_headers or send_header are probably applied to early.

We could instead use the template_redirect hook to target the front-page, before the headers are sent and after is_front_page() is ready.

Here's an example:

 * Set the Last-Modified header for visitors on the front-page 
 * based on when a post was last modified.

add_action( 'template_redirect', function() use ( &$wp )
    // Only visitors (not logged in)
    if( is_user_logged_in() )

    // Target front-page
    if( ! is_front_page() )

    // Don't add it if there's e.g. 404 error (similar as the error check for feeds)
    if( ! empty( $wp->query_vars['error'] ) )

    // Don't override the last-modified header if it's already set
    $headers = headers_list();
    if( ! empty( $headers['last-modified'] ) )  

    // Get last modified post
    $last_modified = mysql2date( 'D, d M Y H:i:s', get_lastpostmodified( 'GMT' ), false );

    // Add last modified header
    if( $last_modified && ! headers_sent() )
        header( "Last-Modified: " . $last_modified . ' GMT' );

}, 1 );

Here we used the core PHP functions header(), headers_list() and headers_sent() and the WordPress core function get_lastpostmodified()

The Etag header could be added here too as the md5 of the last modified date.

We can then test it from the command line with e.g.:

# curl --head https://example.tld

or just use the shorthand parameter -I to only fetch the HTTP headers.

  • Looks like a good solution, I am thinking it might be better to check the set header against the discovered last modified date just to be sure it is correct. if( $headers['last-modified'] <= $Last-Modified ). Remove the !empty statement and wrap the add header in this?
    – JpaytonWPD
    Commented Feb 22, 2017 at 13:06
  • yes that might be a good suggestion, if you want to override that header, added by another plugin. Just check if it's set before using it. Feel free to edit the answer. PS missing curly brackets for single IF lines is valid PHP . @JpaytonWPD
    – birgire
    Commented Feb 22, 2017 at 13:15
  • It provides better consistency and reduces potential errors in the future. Especially on a site like this where inexperienced users are likely to add lines and then ask a question because it stopped working. There is no negative effect with their presence. But you are correct, it is totally valid.
    – JpaytonWPD
    Commented Feb 23, 2017 at 0:07
  • Can you explain this part to me? Or send me a reference to it? function() use ( &$wp ) How does this differ from building a function and adding it by name with the add_action?
    – JpaytonWPD
    Commented Feb 23, 2017 at 0:10
  • Sure: We can't change what input arguments are defined in the do_action parts. The use keyword makes it possible, with anonymous functions, to bring in the variable(s) from the parent scope (by reference & here). See e.g. here. @JpaytonWPD
    – birgire
    Commented Feb 23, 2017 at 8:46

Untested, but it should work:

$query = "SELECT MAX(post_modified) AS modified FROM {$wpdb->prefix}posts";
$results = $wpdb->get_results($query);

if (isset($results[0]->modified) {
    header("Last-Modified: ".$results[0]->modified);
add_action('template_redirect', 'theme_add_last_modified_header');

function theme_add_last_modified_header($headers) {
    global $post;
    if(isset($post) && isset($post->post_modified)){
        $post_mod_date=date("D, d M Y H:i:s",strtotime($post->post_modified));
        header('Last-Modified: '.$post_mod_date.' GMT');

This worked for me on posts and pages :)


This sets it for both posts (directly) and homepage or taxonomy pages (indirectly, by checking the latest included post):

add_action('template_redirect', 'last_modified_header');
function last_modified_header($headers) {
    global $post;
    if(isset($post) && isset($post->post_modified)){
        $lastmod=gmdate("D, d M Y H:i:s",strtotime($post->post_modified));
        header('Last-Modified: '.$lastmod.' GMT');

If you use sticky posts, you may want to ignore them by default so their date won't come on top, like this:

add_action('pre_get_posts', 'ignore_sticky');
function ignore_sticky($query) {
    $query->set('ignore_sticky_posts', true);

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.