I need to force a 404 on some posts based on conditions. I managed to do it ( although I don’t know if I did it the right way) and I’m a getting my 404.php template to load as expected.
My code:
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
include( get_query_template( '404' ) );
exit; # so that the normal page isn't loaded after the 404 page
}
}
add_action( 'template_redirect', 'rr_404_my_event', 1 );
Code 2 from this related question – same problem:
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
global $wp_query;
$wp_query->set_404();
}
}
add_action( 'wp', 'rr_404_my_event' );
My Issue:
Although it looks good, I get a status 200 OK if I check the network tab. Since it’s a status 200, I am afraid that search engines might index those pages too.
Expected Behaviour:
I want a status 404 Not Found to be sent.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You could try the WordPress function status_header() to add the HTTP/1.1 404 Not Found header;
So your Code 2 example would be:
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
global $wp_query;
$wp_query->set_404();
status_header(404);
}
}
add_action( 'wp', 'rr_404_my_event' );
This function is for example used in this part:
function handle_404() {
...cut...
// Guess it's time to 404.
$wp_query->set_404();
status_header( 404 );
nocache_headers();
...cut...
}
from the wp class in /wp-includes/class-wp.php.
So try using this modified Code 2 example in addition to your template_include code.
Method 2
This code worked for me:
add_action( 'wp', 'force_404' );
function force_404() {
global $wp_query; //$posts (if required)
if(is_page()){ // your condition
status_header( 404 );
nocache_headers();
include( get_query_template( '404' ) );
die();
}
}
Method 3
I wouldn’t recommend forcing a 404.
If you’re worried about search engines why not just do a “no-index,no-follow” meta on those pages and block it with robots.txt?
This may be a better way to block the content from being viewed
add_filter( 'template_include', 'nifty_block_content', 99 );
function nifty_block_content( $template ) {
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
$template = locate_template( array( 'nifty-block-content.php' ) );
}
return $template;
}
You could probably also use this method to load 404.php but I feel that using a page template might be a better option.
Method 4
My solution:
add_action( 'wp', 'my_404' );
function my_404()
{
if ( is_404() )
{
header("Status: 404 Not Found");
$GLOBALS['wp_query']->set_404();
status_header(404);
nocache_headers();
//var_dump(getallheaders()); var_dump(headers_list()); die();
}
}
Method 5
Status codes are sent in the headers of HTTP requests. Your current function is hooked into a hook that will be called too late.
You should try to hook your function rr_404_my_event() into action send_headers.
I’m not sure if at that point in time it’s even possible to check the Post ID, but give this a go:
add_action( 'send_headers', 'rr_404_my_event' );
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
include( get_query_template( '404' ) );
header('HTTP/1.0 404 Not Found');
exit;
}
}
Method 6
I wanted to share the way I used the marked solution
function fail_safe_for_authors() {
if ((is_user_logged_in()) && (is_author()) && ($_COOKIE["user_role"] !== "administrator")) {
global $wp_query;
$wp_query->set_404();
status_header(404);
}
}
add_action("wp", "fail_safe_for_authors");
I did this to separate all user types from the administrator, in this project, Only the admin can see the author.php page.
I hope it could help somebody else.
Method 7
The most robust way I’ve found of achieving this is to do it in the template_include filter, like so:
function wpse91900_force_404(string $template): string {
if ($some_condition) {
global $wp_query;
$wp_query->set_404();
status_header(404);
nocache_headers();
$template = get_404_template();
}
return $template;
}
add_filter("template_include", "wpse91900_force_404");
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0