Как принудительно вызвать ошибку 404 в WordPress
Мне нужно принудительно вызывать 404 ошибку для некоторых записей на основе условий. Мне удалось это сделать (хотя я не уверен, что сделал это правильно), и мой шаблон 404.php
загружается как ожидалось.
Мой код:
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
include( get_query_template( '404' ) );
exit; # чтобы обычная страница не загружалась после страницы 404
}
}
add_action( 'template_redirect', 'rr_404_my_event', 1 );
Код 2 из этого связанного вопроса - та же проблема:
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' );
Моя проблема:
Хотя всё выглядит хорошо, в сетевой вкладке я получаю статус 200 OK
. Поскольку это статус 200
, я боюсь, что поисковые системы могут проиндексировать эти страницы.
Ожидаемое поведение:
Мне нужно, чтобы отправлялся статус 404 Not Found
.

Вы можете попробовать использовать функцию WordPress status_header()
для добавления заголовка HTTP/1.1 404 Not Found
;
Таким образом, ваш пример Кода 2 будет выглядеть так:
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' );
Эта функция, например, используется в этой части:
function handle_404() {
...вырезано...
// Похоже, пришло время для 404.
$wp_query->set_404();
status_header( 404 );
nocache_headers();
...вырезано...
}
из класса wp
в файле /wp-includes/class-wp.php
.
Попробуйте использовать этот модифицированный пример Кода 2 вместе с вашим кодом template_include
.

Фрагмент кода Code 2
, который вы опубликовали, работает идеально. set_header()
— это как раз то, чего не хватало.

@birgire вы упоминаете set_header()
для добавления HTTP/1.1 404 Not Found
, но в своём коде использовали status_header()
?

Удобно. Я проверяю пользовательские параметры запроса, поэтому не использую action, но это делает метод очень полезным в классе моего плагина.

Наиболее надежный способ, который я нашел для достижения этого, — использовать фильтр template_include
, как показано ниже:
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");

Я бы не рекомендовал принудительно вызывать 404 ошибку.
Если вы беспокоитесь о поисковых системах, почему бы просто не добавить метатег "no-index,no-follow" на эти страницы и заблокировать их через robots.txt?
Вот более подходящий способ заблокировать контент от просмотра:
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;
}
Этим же методом можно загружать 404.php
, но я считаю, что использование шаблона страницы может быть лучшим вариантом.

Большое спасибо за ссылку, я переключусь на использование locate_template()
. Думаю, что robots.txt
не является гарантированным способом защиты от индексации. Некоторые поисковые системы всё равно могут проиндексировать страницу. Я хочу, чтобы страница выглядела как обычная 404. Кроме того, посты будут добавляться динамически, и редактирование файла robots.txt
добавит лишних хлопот.

Хочу поделиться способом, которым я реализовал отмеченное решение:
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");
Я сделал это, чтобы разделить все типы пользователей от администратора. В этом проекте только администратор может видеть страницу author.php
.
Надеюсь, это решение поможет кому-то ещё.

Перенаправление при ошибках крайне негативно сказывается на ранжировании страницы. Вместо этого лучше отображать шаблон по тому же адресу, где был получен некорректный запрос. Если вы сделаете перенаправление, вот что произойдет: сначала будет установлен статус 404, затем перенаправление изменит его на 301 или 302, которое перенаправит на страницу с кодом 200. В результате поисковые системы проиндексируют эту страницу как валидную, хотя автор вопроса четко указал, что этого не хочет.

Коды состояния отправляются в заголовках HTTP-запросов. Ваша текущая функция подключена к хуку, который будет вызываться слишком поздно.
Попробуйте подключить вашу функцию rr_404_my_event()
к действию send_headers
.
Я не уверен, возможно ли на этом этапе проверить ID записи, но попробуйте следующий вариант:
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;
}
}

Я исправил некоторые синтаксические ошибки в вашем коде. У меня даже не загружается шаблон 404 с этим.

Возможно, в вашем файле 404.php
можно загрузить другой header.php
, например <?php get_header('404'); ?>
, чтобы загрузить header-404.php
. В этом заголовке вы должны добавить header('HTTP/1.0 404 Not Found');
в разделе <head>
.
