WordPress.org

Ready to get started?Download WordPress

Forums

[resolved] Explanation and workaround for error 404 on category pagination (14 posts)

  1. Daniele Raimondi
    Member
    Posted 2 years ago #

    I've found many many wp users with this exact problem in the last 3(!) years and now I'm facing it on WP 3.2.1 also. I've also found so many fixes and workarounds but not a clear explanation of the bug and its reproducibility, nor a simple and elegant solution. So here are my thoughts about it.

    If you set a posts_per_page value in a template file, lower then the one specified in the backend, you get a 404 error on pagination. If I'm not wrong, the 404 error shows on the last page (the 2nd when you have only few posts).

    After some debugging, I think the problem is that the var posts_per_page get lost going to page 2 and so WP uses the default one to decide if there are posts to show or not.
    Some examples:
    ----------------------------------------------------------------
    SET A GREATER VALUE
    a) you have 9 posts in a particular category;
    b) you have "5" as posts_per_page setted in the backend;
    c) you specify "7" in your template file;

    First page:
    WP reads the template file, set the var with the new value (7) so it shows posts from 1 to 7

    Second Page:
    when you click on "next page", WP lost your new posts_per page value and thinks: "ok, I've got 9 posts in this category, I'm on page 2 and I have to show 5 post per page, so this page exists for sure and I must load posts from 6 to 9!"
    Then it loads the template file, your var is setted again to 7, page number is 2, so WP loads and shows (correctly) posts 8 and 9.
    No more post to show so you don't have a next page link to go further.

    SET A LOWER VALUE
    a) you have 9 posts in a particular category
    b) you have "5" as posts_per_page setted in the backend
    c) you specify "3" in your template file

    First page:
    wp reads the template file, set the var with the new value (3) so it shows posts from 1 to 3.

    Second Page:
    when you click on "next page", WP lost your new posts_per page value and thinks: "ok, I've got 9 posts in this category, I'm on page 2 and I have to show 5 post per page, so this page exists for sure and I must load posts from 6 to 9"
    Then it loads the template file, your var is setted again to 3, page number is 2, so WP loads and shows (correctly) posts from 4 to 6 and a link to the next page, cause not all posts has been showed.

    Third page:
    when you click on "next page", WP lost (again!) your new posts_per page value and thinks: "ok, I've got 9 posts in this category, I'm on page 3 and I have to show 5 post per page, so this page can't exist!!!"
    Then it loads the 404 template file, your are very angry ang go out for a walk!
    ----------------------------------------------------------------

    So, if you set a value greather then the one specified in the backend, even if the variable get lost and the default is used, WP calculates (mistaken for excess) that there are certainly some other posts to show. This is not problematic, as the code on template file corrects it and doesn't allow to go to next page if all posts are showed.
    If you specify a lower value, WP is "consuming" your remaining posts faster then your template file, which prints a link to next page and you get a 404 error.

    Ok. that's a funny story. And now? My workaround is:

    Set your default posts_per_page in the backend as you like, then

    function cure_wp_amnesia_on_query_string($query_string){
    	if ( !is_admin() ){
    		if ( isset( $query_string['category_name'] ) ) {
    			switch ($query_string['category_name']) {
    				case 'faq':
    				case 'corsi-di-formazione':
    					$query_string['posts_per_page'] = 5;
    					break;
    				case 'prestazioni':
    					$query_string['posts_per_page'] = 6;
    					break;
    				case 'smile-gallery':
    					$query_string['posts_per_page'] = 3;
    				//default:
    					break;
    			}
    		}
    		if ( isset( $query_string['s'] ) ){//case SEARCH
    			$query_string['posts_per_page'] = 5;
    		}
    	}
    	return $query_string;
    }
    
    add_filter('request', 'cure_wp_amnesia_on_query_string');

    Add this function in your functions.php and set here the number of posts you want per category. I've not tried it with CPT but I suppose that we can find a specific index in $query_string to test against as I do with 'category_name' and 's'.

    Hope this can help someone.

  2. demo tester
    Member
    Posted 2 years ago #

    This is AWESOME. your function also worked for me.

    I had tinkered with this for a while and had NO idea what the deal was, just figured I was not writing the custom TPL properly.
    What I started doing was simply setting the max posts per page under WP->settings->reading to simply be "1" and then controlling everything via my template. an unfortunate thing, but just dropping in a custom [homepage] [postpage] on the appropriate page and then building my own loop has worked well for me.

    Had no idea why, but now I know! :)

  3. Daniele Raimondi
    Member
    Posted 2 years ago #

    Happy to hear it has been useful to you!

    Setting the pagination to "1" in the reading settings is the simplest and most immediate working solution I've found to this problem, but then you have to set a value for pagination every time you create a new taxonomy/term/cpt etc, and then you have to "scatter" the pagination-setting on several template files.

    My function just groups those settings in one point and allow you to use the value defined in the backend as the default value for every new type of archive/listing.

    Aside from wondering why that problem has not been patched yet, I'd like to find the time to use the function above to create a plugin and so integrate the backend reading settings with a list all paginable items and their specific settings. Maybe in a near future...

  4. ch0usse
    Member
    Posted 2 years ago #

    Hi,
    now I know why my pagination doesn't work ... I tried your workaround, no more 404 error but it don't work correctly :(
    I have 3 categories with differents "posts_per_page" 6, 2 and 8
    Now I have this problem : I click on next news page (posts_per_page==2) => go category/news/page/2/ and it always display posts 1 to 2 and not 3 to 4
    the same with other categories
    <?php query_posts('cat=3&posts_per_page=2&paged=' . get_query_var('paged')); ?>
    I test on v3.3.1

  5. Daniele Raimondi
    Member
    Posted 2 years ago #

    @ch0usse
    If you are using my function "cure_wp_amnesia_on_query_string" (with your category slugs and values, of course), you no longer have to alter the query vars adding &post_per_page=x&paged=etc etc. They are automagically added every time WP needs to know their values.

    As I wrote above, with this function, you no longer have to "scatter" the pagination-settings on several template files.
    My function just groups those settings in one point and allow you to use the value defined in the backend as the default value for every new type of archive/listing.

    If it doesn't work, try to post here (or on pastebin.com) the code you are using in your theme function and templates.

    Bye

  6. ch0usse
    Member
    Posted 2 years ago #

    @mad_max
    finally it work ! special thanks but I modified a little bit :

    if ( isset( $query_string['cat'] ) ) {
    			switch ($query_string['cat']) {
    				case 1:
    				$query_string['posts_per_page'] = 2;
    					break;
    				case 5:
    				$query_string['posts_per_page'] = 8;
    					break;
    				case 3:
    				$query_string['posts_per_page'] = 6;
    				// default:
    					// $query_string['posts_per_page'] = 6;
    					break;
    			}
    		}

    because WP don't recognize 'category_name', maybe because I don't use permalinks with localhost.

    THX

  7. Daniele Raimondi
    Member
    Posted 2 years ago #

    You are right. I usually use permalinks so this problem has never come to my mind! I think it worths a rewrite of the function to take in account your use case.
    Taking out cat names/values from the function and grouping them in a "pagination settings" section of the function.php files (clearly a plugin with an admin page should be the best solution), we can rewrite the code like this:

    Permalinks enabled

    //POSTS PER PAGE (permalinks on)
    $my_ppp =array(
    	'category' => array(
    		'cat1_name' => X,
    		'cat2_name' => Y,
    		'cat3_name' => Z,
    	),
    	'search' => K,
    );

    Permalinks disabled

    //POSTS PER PAGE (permalinks OFF)
    $my_ppp =array(
    	'category' => array(
    		'cat1_ID' => X,
    		'cat2_ID' => Y,
    		'cat3_ID' => Z,
    	),
    	'search' => K,
    );

    And then the function:

    if ( isset( $my_ppp ) && is_array( $my_ppp ) && count( $my_ppp ) ) add_filter('request', 'cure_wp_amnesia_on_query_string');
    function cure_wp_amnesia_on_query_string($query_string){
    	global $my_ppp;
    	if ( !is_admin() ){
    		if ( isset( $my_ppp['category'] ) && is_array( $my_ppp['category'] ) )  {
    			if ( isset( $query_string['category_name'] ) ) {
    				foreach ( $my_ppp['category'] as $category_name => $ppp ) {
    					if ( $query_string['category_name'] == $category_name ) {
    						$query_string['posts_per_page'] = $ppp;
    						break;
    					}
    				}
    			}elseif ( isset( $query_string['cat'] ) ){
    				foreach ( $my_ppp['category'] as $cat_id => $ppp ) {
    					if ( $query_string['cat'] == $cat_id ) {
    						$query_string['posts_per_page'] = $ppp;
    						break;
    					}
    				}
    			}
    		}
    		if ( isset( $my_ppp['search'] ) && isset( $query_string['s'] ) )  {
    			$query_string['posts_per_page'] = $my_ppp['search'];
    		}
    	}
    	return $query_string;
    }
  8. replicante
    Member
    Posted 2 years ago #

    Works great!

    And if you need to modify your queries, you can do it adding parameters to the $query_string array in cure_wp_amnesia_on_query_string function, not in the posts templates.

  9. wmburke
    Member
    Posted 2 years ago #

    Brilliant, mate - thanks.

    My situation is somewhat less complicated so I used the info on the following page to just reset the main query to 10 posts per page after setting the back end to 1 post per page. This seems to have solved all of my problems (well, related to this specific issue of course ;).

    http://www.billerickson.net/customize-the-wordpress-query/

  10. wmburke
    Member
    Posted 2 years ago #

    My apologies, but my solution above did not fix my problem. Setting the main query to 10 posts per page in functions.php caused the same problem as setting it in the back end.

    Didn't want anyone else to be confused by this.

  11. cornhustlah
    Member
    Posted 2 years ago #

    AWSM.

  12. anggil
    Member
    Posted 2 years ago #

    @Daniele : Thank Bro... you are AWESOMEE.. that fix my problem..

  13. contiwp
    Member
    Posted 1 year ago #

    Man, i'll be forever in debt. What a silly mistake that was, i could've lost some precious hours in it without this. Thanks!!

  14. Daniele Raimondi
    Member
    Posted 1 year ago #

    Happy to hear that from all you guys! Hope to find some spare time to code this in a plugin, or better find that the last WP versione has resolved this issue (Hope springs eternal!).

Topic Closed

This topic has been closed to new replies.

About this Topic