Баг: 404 статус відповіді для пагінації

Суть проблеми в тому, що основний запит WP (який не потрібен у цьому випадку) все ж таки робиться і заважає нормальній роботі картки сайту.

Баг перевірено на WP 5.6.1

Тикет цього бага: https://core.trac.wordpress.org/ticket/51912

Змоделюємо проблему

Для цього створимо 5 записів типу page, 1 запис типу post і обмежимо кількість посилань на сторінці карти до 1, таким кодом:

add_filter( 'wp_sitemaps_max_urls', function(){
	return 1;
} );

Тепер зайшовши на сторінку карти сайту /wp-sitemap-posts-page-4.xml, ми побачимо 4 сторінку пагінації карти сайту, все начебто ОК, але якщо подивитися на статус відповіді, то ми побачимо 404 (такий статус не підходить для пошукових систем).

Чому так відбувається

Коли ми заходимо на сторінку , /wp-sitemap-posts-page-4.xmlспочатку робиться основний WP запит WP::main() :

    public function main( $query_args = '' ) {
		$this->init();

		$this->parse_request( $query_args );
		$this->send_headers();
		$this->query_posts(); //> - робить запит
		$this->handle_404(); //> - перевіряє чи є дані, якщо ні ставить статус 404
		$this->register_globals();

		do_action_ref_array( 'wp', array( &$this ) );
	}

У цьому випадку основний запит має такий вигляд:

SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts
	WHERE 1=1 AND wp_posts.post_type = 'post'
		AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
	ORDER BY wp_posts.post_date DESC
	LIMIT 30, 10

Як ми бачимо, цей запит взагалі не пов’язаний з картою сайту та поточними параметрами запиту. Цей запит поверне порожній результат, тому що записів на кшталт postу нас стільки немає.

Далі спрацює метод WP::handle_404() який виставить status_header( 404 );тому що $wp_query->posts = array()запит не отримав жодних даних.

Далі спрацьовує хук template_redirect, на якому запускається вся логіка карти сайту. Але 404 статус уже встановлено!

Рішення (у вигляді милиці)

Варіант 3:

// Fix for sitemaps pagination bug. Additionally improve performance a little.
// @see https://core.trac.wordpress.org/ticket/51912
// TODO: check necessity and maybe delete this code
add_action( 'parse_request', 'fix_sitemaps_pagination_wp_bug');
function fix_sitemaps_pagination_wp_bug( $wp ){

	if( empty( $wp->query_vars['sitemap'] ) && empty( $wp->query_vars['sitemap-stylesheet'] ) )
		return;

	$GLOBALS['wp_query']->query_vars = $wp->query_vars;

	wp_sitemaps_get_server()->render_sitemaps();
}

Варіант 2:

// Fix sitemaps pagination bug. Additionally improve performance a little.
// @see https://core.trac.wordpress.org/ticket/51912
// TODO: check necessity and maybe delete
add_action( 'parse_query', 'fix_sitemaps_pagination_wp_bug');
function fix_sitemaps_pagination_wp_bug( $wp_query ){

	// change render_sitemaps() call to run it before main query but after query vars are set.
	if(
		isset( $wp_query->query['sitemap'] ) &&
		$wp_query->is_main_query() &&
		remove_action( 'template_redirect', [ wp_sitemaps_get_server(), 'render_sitemaps' ] )
	) {
		wp_sitemaps_get_server()->render_sitemaps();
	}

}

Варіант 1:

// Fix for sitemaps pagination bug. Additionally improve performance a little.
// @see https://core.trac.wordpress.org/ticket/51912
// TODO: check necessity and maybe delete
add_filter( 'posts_request', 'fix_sitemaps_pagination_wp_bug', 10, 2);
function fix_sitemaps_pagination_wp_bug( $request, $wp_query ){
	Global $wpdb;

	if( isset( $wp_query->query['sitemap'] ) && $wp_query->is_main_query() ){
		return "SELECT * FROM $wpdb->posts LIMIT 1";
	}

	return $request;
}

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *