1

I am encountering a 404 error on the last page of a category archive when using WP_Query for pagination in WordPress 6.8. I'm seeking insights into the cause of this issue and potential solutions.

Environment:

  • WordPress Version: 6.8

  • PHP Version: 8.4.6

  • MySQL Version: Ver 15.1 Distrib 10.11.11-MariaDB, for debian-linux-gnu (x86_64) using EditLine wrapper

  • Server Version: Apache/2.4.62 (Debian)

  • Issue occurs on both local and remote (shared hosting) server environments.

  • Themes Tested: Twenty Twenty-Five, Twenty Twenty-Four, Twenty Twenty-Three (all default themes)

  • No plugins are active during testing.

  • The issue has been tested while logged in and logged out.

Steps to Reproduce:

  1. Create a new database and perform a clean installation of WordPress 6.8.

  2. Log in to the WordPress admin dashboard.

  3. Create a new category (e.g., "food").

  4. Create 11 posts and assign them to the "food" category.

  5. Create a file named category-food.php in the active theme's directory.

  6. Navigate to "Settings" > "Reading" and leave the "Blog pages show at most" option set to 10.

  7. Save permalinks (even without changes) and verify the .htaccess file.

Expected Behavior:

  • Pagination should function correctly, allowing access to all pages of the category archive.

  • The last page should display the remaining posts based on the posts_per_page parameter in WP_Query without returning a 404 error.

  • /category/food/page/1/: Should display 4 posts.

  • /category/food/page/2/: Should display 4 posts.

  • /category/food/page/3/: Should display 3 posts (total of 11 posts).

Actual Behavior:

  • /category/food/page/1/: Displays 4 posts.

  • /category/food/page/2/: Displays 4 posts.

  • /category/food/page/3/: Returns a 404 error page.

  • The issue only occurs when accessing the last page of the pagination.

  • Modifying the arguments of WP_Query does not resolve the fundamental issue.

  • Setting the "Blog pages show at most" option in "Settings" > "Reading" to the same value as the posts_per_page argument in WP_Query prevents the error.

category-food.php Code:


<?php

get_header();

global $post;

$paged = get_query_var('paged') ? get_query_var('paged') : 1;

$args = array(

'post_type' => 'post',

'category_name' => 'food',

'no_found_rows' => false,

'post_status' => 'publish',

'posts_per_page' => 4,

'paged' => $paged,

);

echo '<pre>WP_Query Args (Before):</pre>';

echo '<pre>';

print_r($args);

echo '</pre>';

$the_query = new WP_Query($args);

print_r('paged:' . $paged . ', ' . $args['paged'] . '/' . $the_query->max_num_pages . ', found_posts:' . $the_query->found_posts);

if ($args['paged'] == $the_query->max_num_pages) {

// The last page is not reached when not logged in

// var_dump($the_query);

    echo '<p>' . $paged . ' page</p>';

}

$html = '<ul>';

if ($the_query->have_posts()) {

    $posts = $the_query->posts; // Get the array of retrieved post objects

foreach ($posts as $p) {

        $the_query->the_post(); // Set up the global $post variable

        $html .= '<li><h3>' . esc_html(get_the_title()) . '</h3></li>';

    }

    $html .= '</ul>';

} else {

return 'Recent shortcode: no posts matched your criteria.';

}

// Restore original Post Data.

wp_reset_postdata();

echo $html;

get_footer();

2 Answers 2

1

Yea, this is a strange issue.

It looks like WordPress is using his own "Settings" > "Reading" setting to determinate its pagination behaviour.

Let's say. You want to leave your "Settings" > "Reading" at 10. But you really need 4 pages to be shown at certain categories. For example "food", then you should consider overriding the option setting when you visit your food category. You can do this by using this code, i have create it by hand, and provided some comments to make it more clear.

With this code enabled. And with the steps of the tread starter above, the issue should be solved. And now the page /category/food/page/3/ is showing the correct results.

/*
 * Manipulate the posts per page setting from "Settings" > "Reading" 
 * because WordPress relies on the "Settings" > "Reading" for its pagination instead of the given "post_per_page" value...
 */
add_filter('option_posts_per_page', function ($value) {
    // Get queried object
    $queried_object = get_queried_object();

    // Check if we're on a category archive and it's the "food" category
    if (
        is_category() && 
        isset($queried_object->slug) && 
        $queried_object->slug === 'food'
    ) {
        // This need to be the same value as you give inside your "post_per_page" args
        $post_per_page = 4;

        // By returning this value. We override the "Settings" > "Reading" value
        return $post_per_page;
    }
    
    return $value;
});
1
  • Thank you so much! This code resolved an issue I had been struggling with for quite some time. I really appreciate your help. Thanks to you, my website is now working correctly. I am very grateful. The comments in the code were also very clear and easy to understand. Thank you so much again! Commented yesterday
0

Follow-up Report:

Thank you for providing the solution. While experimenting based on the code you offered, I unexpectedly discovered that adding the following code to functions.php enables the posts_per_page setting in WP_Query arguments.

Please note that this behavior has only been observed in my specific environment (WordPress 6.8, PHP 8.4.6, etc.), and the results may vary in other setups.

A significant side effect of this code has been identified. When this filter is active, if the 'posts_per_page' argument is not explicitly set in the WP_Query arguments, the number of posts displayed per page defaults to 1 across the entire site, instead of the default value from the "Settings" > "Reading" option. This can affect all post listing loops commonly used in themes (e.g., homepage, archive pages, related posts), leading to unintended display counts. Therefore, it is crucial to explicitly set the 'posts_per_page' argument in all WP_Query calls when using this code.

I would also appreciate any insights into the reason behind this behavior and any potential side effects.

/*
 * Enables the 'posts_per_page' setting in WP_Query args
 * Have side effects!
 */
add_filter('option_posts_per_page', function ($value) {
    // Get queried object
    get_queried_object();
    return null;
});

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.