pre_handle_404хук-фильтрWP 4.5.0

Позволяет установить запросу произвольные header заголовки после того, как был сделан основной запрос.

Во время хука, можно проверить основной запрос, который находится в глобальной переменной $wp_query. И если надо, отправить на 404 страницу, когда по умолчанию это не 404 страница. Или наоборот не отправлять на 404 страницу, когда по умолчанию должна быть 404 страница.

Если фильтр вернет что угодно кроме false, то все проверки, который идут после этого хука будут прерваны.

Что проверяется после этого хука?

  • Ничего если is_404() уже сработал.
  • Если есть записи в $wp_query->posts, но это запрос пагинации отдельной записи (<!--nextpage-->) и на указанной странице пагинации уже нет контента. Тогда выведет 404 страницу.
  • Если это страница автора, у которого нет записей, то не выводить 404 страницу.
  • Не выводить 404 для определившегося запроса архива.
  • Не выводить 404, если сработал хоть один тег: is_home() || is_search() || is_feed()

Использование

add_filter( 'pre_handle_404', 'wp_kama_pre_handle_404_filter', 10, 2 );

/**
 * Function for `pre_handle_404` filter-hook.
 * 
 * @param bool     $preempt  Whether to short-circuit default header status handling.
 * @param WP_Query $wp_query WordPress Query object.
 *
 * @return bool
 */
function wp_kama_pre_handle_404_filter( $preempt, $wp_query ){

	// filter...
	return $preempt;
}
$preempt(логический)
Если вернуть что угодно кроме false, то работа метода WP::handle_404() будет прервана.
По умолчанию: false
$wp_query(объект)

Глобальный объект $wp_query.

Его также можно получить в обрабатываемой функции, указав в начале global $wp_query;

Примеры

0

#1 Страница 404 для архива автора

Предположим, нам не нужна страница архива автора. Это может быть нужно, когда на сайте всего 1 автор публикует статьи. И если указать URL /author/логин, то мы попадаем на страницу записей этого автора и одновременно может понять какой логин используется у автора. Для защиты от подбора паролей, лучше, чтобы нельзя было определить логин.

Этот пример, показывает как скрыть страницу архива автора. Пример разбирался в вопросе.

// Ставим 404 статус
add_filter( 'pre_handle_404', 'remove_author_pages_page' );
function remove_author_pages_page( $false ) {
	if ( is_author() ) {
		global $wp_query;
		$wp_query->set_404();
		status_header( 404 );
		nocache_headers();

		return 'stop'; // для обрыва хука 
	}

	return $false;
}

// удаляем ссылку
add_filter( 'author_link', 'remove_author_pages_link' );
function remove_author_pages_link( $content ) {
	return home_url();
}
0

#2 Установим 404 страницу для записи произвольно типа

У нас есть нестандартный URL типа записи realty, в котором присутствуют таксономии. Но чтобы получить страницу записи достаточно знать её ярлык. Пусть URL выглядит так: /realty/таксономия_type_deal/ярлык_записи. Теперь, если указать в имени таксономии (термина) любое значение, страница записи будет работать. А нам нужно, чтобы работала только одна ссылка, с правильным названием таксономии. А если название неправильное, то нужно отдавать 404 страницу.

## 404 страница если в URL указаны неправильные называния таксономий.
## По факту, WP затем 301 редиректит на правильный URL...
add_filter( 'pre_handle_404', 'realty_404_test', 10, 2 );
function realty_404_test( $false, $wp_query ){

	$set_404 = false;

	// отдельная запись объявления
	if( is_singular('realty') ){
		$post = get_queried_object();

		$term_name = get_query_var('type_deal');
		if( $term_name && ! has_term( $term_name, 'type_deal', $post ) ){
			$set_404 = 1;
		}

	}

	if( $set_404 ){
		$wp_query->set_404();
		status_header( 404 );
		nocache_headers();

		return 'stop'; // обрываем следующие проверки
	}

	return $false; // ничего не делает...
}
0

#3 404 для страниц в URL которых попал пробел

Если в URL постоянной станицы попадет пробел, то WordPress все равно покажет такую страницу, хотя должен бы показать 404 страницу. Т.е. такая страница с пробелом всё равно отдаёт ответ 200, а это дублирование контента. Например, реальный URL: /sample-page/, а в контенте его указали как /sample- page/, что равносильно в итоге /sample-%20page/.

add_filter( 'pre_handle_404', function ( $false, $wp_query ) {
	// именно из 'query' элемента надо брать!
	$pagename = isset($wp_query->query['pagename']) ? $wp_query->query['pagename'] : '';

	// если ярлык страницы содержит пробел...
	if( strpos( $pagename, '%20' ) !== false ) {

		$wp_query->set_404();
		status_header( 404 );
		nocache_headers();

		return 'stop';
	}

	return $false; // ничего не делает...
}, 10, 2 );
0

#4 404 для страниц в URL которых ноль

// Вариант с Записями
add_filter( 'pre_handle_404', 'fix_fake_page' );

function fix_fake_page( $false ) {
	global $wp_query;

	if ( is_singular()
		 && isset( $wp_query->query['page'] )
		 && $wp_query->query['page'] === '0'
	) {
		$wp_query->set_404();
		status_header( 404 );
		nocache_headers();
		return 'stop';
	}

	return $false;
}

// Вариант с Рубриками
add_filter( 'pre_handle_404', 'fix_fake_category_page' );

function fix_fake_category_page( $false ) {
	global $wp_query;

	if ( is_archive() && get_query_var('category_name') === '0' ) {
	// if ( is_archive() && ! term_exists( get_query_var( 'category_name' ) ) ) {
		$wp_query->set_404();
		status_header( 404 );
		nocache_headers();
		return 'stop';
	}

	return $false;
}
0

#5 404 для страниц пагинации постов

Контент постов можно делить тегом <!--nextpage-->, тогда каждая часть текста будет доступна под своим адресом.

К примеру, добавим по контенту 2 таких тега, тем самым разделим его на 3 части, которые будут доступны по следующим адресам:

  • 1 часть - https://site.com/test-post/
  • 2 часть - https://site.com/test-post/2/
  • 3 часть - https://site.com/test-post/3/

Если перейти по адресу https://site.com/test-post/1/, то перенаправит на https://site.com/test-post/, тут всё логично. Но если перейти на https://site.com/test-post/4/ или другую несуществующую часть контента - отобразится всё как обычно, но текста не будет (части 4 ведь нет). То есть страница есть, а контента нет. В таких случаях должна быть ошибка 404, но WP отдаёт ответ 200, что может плохо сказать на сео. Исправим это поведение.

Данный недочёт есть не на всех сайтах!

По умолчанию WP перенаправляет на основной УРЛ с несуществующей страницы пагинации записей (постов).

Вероятнее всего это связано с отключением функции redirect_canonical():

remove_action( 'template_redirect', 'redirect_canonical' );
// Вариант 1. Отменяем пагинацию для отдельных страниц
// (тенденция, что их никто и не использует)
add_filter( 'pre_handle_404', 'remove_single_post_pagination', 10, 2 );

function remove_single_post_pagination( $false, $wp_query ) {

	if ( is_singular() && get_query_var( 'page' ) ) {

		$wp_query->set_404();
		status_header( 404 );
		nocache_headers();

		return 'stop';
	}

	return $false;
}

Список изменений

С версии 4.5.0 Введена.

Где вызывается хук

WP::handle_404()
pre_handle_404
wp-includes/class-wp.php 730
if ( false !== apply_filters( 'pre_handle_404', false, $wp_query ) ) {

Где используется хук в WordPress

wp-includes/sitemaps/class-wp-sitemaps.php 78
add_filter( 'pre_handle_404', array( $this, 'redirect_sitemapxml' ), 10, 2 );