Bug: 404 response status for pagination
The essence of the problem is that the main WP request (which is not needed in this case) is still being made and interferes with the normal operation of the sitemap.
The bug is tested on WP 5.6.1
Ticket for this bug: https://core.trac.wordpress.org/ticket/51912
Modeling the problem
To do this, create 5 posts with page
posts type, 1 post with post
post type and limit the max number of links up to 1 on sitemap page, use this code:
add_filter( 'wp_sitemaps_max_urls', function(){ return 1; } );
Now if we visit sitemap page /wp-sitemap-posts-page-4.xml
we will see 4 sitemap pagination pages. Everything seems to be OK, but if we look at the response status code, we will see 404 (this status is not suitable for search engines).
Why is this happening?
When we visit the /wp-sitemap-posts-page-4.xml
page, the main WP request occurs WP::main():
public function main( $query_args = '' ) { $this->init(); $this->parse_request( $query_args ); $this->send_headers(); $this->query_posts(); //> — makes query $this->handle_404(); //> — checks whether there is data, if not, sets the status 404 $this->register_globals(); do_action_ref_array( 'wp', array( &$this ) ); }
In this case, the main request looks like 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
As we can see, this request is not related to the sitemap and the current request parameters at all. This request will return an empty result, because we don't have so many posts of post
post type.
Next, the method WP::handle_404() is triggered. It sets status_header( 404 )
because of $wp_query->posts = array()
- the request did not receive any data.
Next, the template_redirect hook is triggered, on which runs all sitemap logic. But 404 status is already set!
The Temporary solution (before the bug will be solved in WP core)
Variant 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 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(); }
Variant 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(); } }
Variant 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; }