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.
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.
7 Answers
Reset to default 77 +150You 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.
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(); } }
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");
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.
source
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.
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();
}
}
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;
}
}
200
with that. – RRikesh Commented Mar 22, 2013 at 9:40