Баг: 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;
}