Как принудительно вызвать ошибку 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() — это как раз то, чего не хватало.
RRikesh
@birgire вы упоминаете set_header() для добавления HTTP/1.1 404 Not Found, но в своём коде использовали status_header()?
henrywright
Удобно. Я проверяю пользовательские параметры запроса, поэтому не использую action, но это делает метод очень полезным в классе моего плагина.
John Reid
Наиболее надежный способ, который я нашел для достижения этого, — использовать фильтр 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 добавит лишних хлопот.
RRikesh
Хочу поделиться способом, которым я реализовал отмеченное решение:
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. В результате поисковые системы проиндексируют эту страницу как валидную, хотя автор вопроса четко указал, что этого не хочет.
mopsyd
Коды состояния отправляются в заголовках 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 с этим.
RRikesh
Возможно, в вашем файле 404.php можно загрузить другой header.php, например <?php get_header('404'); ?>, чтобы загрузить header-404.php. В этом заголовке вы должны добавить header('HTTP/1.0 404 Not Found'); в разделе <head>.
Marc Dingena