Created
October 13, 2017 20:11
-
-
Save MikeNGarrett/f252e16e407f6eecbe0139be71f67223 to your computer and use it in GitHub Desktop.
Set cache headers on WordPress 404 pages.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Force cache headers on 404 pages and prevent WordPress from handling 404s. | |
* | |
* @param bool $preempt determines who handles 404s. | |
* @param obj $wp_query global query object. | |
*/ | |
function change_404_headers( $preempt, $wp_query ) { | |
if ( ! is_admin() && ! is_robots() && count( $wp_query->posts ) < 1 ) { | |
header( 'Cache-Control: max-age=30000, must-revalidate' ); | |
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', strtotime( '+5000 minutes' ) ) . ' GMT' ); | |
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', strtotime( '-5000 minutes' ) ) . ' GMT' ); | |
$wp_query->set_404(); | |
status_header( 404 ); | |
// prevents the default 404 from firing. | |
return true; | |
} | |
return $preempt; | |
} | |
add_filter( 'pre_handle_404', 'change_404_headers', 2, 99 ); |
The issue discovered is when the site is using a permalink structure where the first variable is one of: postname, category, tag, or author. This throws WP_Rewrite into 'use_verbose_page_rules' mode. This means that WP_Query is always in a state of error because no rewrite rule matches but the query still runs and performs a standard blog query where the most recent posts are returned but the query still calls $wp_query->set_404
. This causes the count( $wp_query->posts ) < 1
check to fail.
Also, the action and argument count arguments are inverted.
Is there any update on the issue? @MikeNGarrett @kshaner
@slim16165 Here's something that I've been trying out today and seems to work so far:
add_action('nocache_headers', function($headers){
if (is_404() ) {
/// Unset the WordPress "nocache" headers
unset( $headers['Expires'] );
unset( $headers['Cache-Control'] );
// Alternatively set new headers
$headers['Cache-Control'] = 'max-age=300';
}
return $headers;
});
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Please note, this has uncovered some unexpected behavior in 4.9 and should not be used. A bug has been filed to get to the bottom of things. I'll update this gist as the ticket progresses.