• Hi,

    So I have a custom loop for my front page that returns 11 posts on the first page with the first one carrying additional classes, and subsequent pages show 10 posts with the same classes. I have added pagination to this loop and while it changes page, the posts it returns are the same as the first page.

    This is my loop currently…

                     <?php
    
                            $first_page_post_count = 11;
                            $subsequent_pages_post_count = 10;
                            $paged = $paged ? $paged : 1;
    
                            if($paged > 1){
                            // not first page
                            $posts_per_page = $subsequent_pages_post_count;
    
                            if($paged == 2){
                            // second page
                            $offset = $first_page_post_count;
                            } else {
                            // subsequent pages
                            $offset = $first_page_post_count + ($subsequent_pages_post_count * ($paged - 2));
                            }
    
                            } else {
                            // first page
                            $offset = 0;
                            $posts_per_page = $first_page_post_count;
                            }
    
                            $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
                            $query_args = array(
                            'post_type' => array ('post' , 'reviews' , 'trailer' , 'feature'),
                            'posts_per_page' => $posts_per_page,
                            'offset' => $offset,
                            'paged' => $paged
                            );
    
                            $the_query = new WP_Query( $query_args );
                        ?>
    
                        <?php $counter = 0; if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
                        <div class="col <?php if(!is_paged() && ($counter==0)) { echo 'xsmall-12 featured-article'; $counter++; } else { echo 'xsmall-12 small-6 article-preview'; } ?> ">
                            //content
    
                        </div>      
    
                        <?php $counter++;
                            if ($counter % 2 == 0) {
                                //content
                            }
                        endwhile; ?>
    
                        <?php else: ?>
                            //content
                        <?php endif; ?>

    My pagination function looks like this…

    function pagination($pages = '', $range = 4)
    {  
         $showitems = ($range * 2)+1;  
     
         global $paged;
         if(empty($paged)) $paged = 1;
     
         if($pages == '')
         {
             global $wp_query;
             $pages = $wp_query->max_num_pages;
             if(!$pages)
             {
                 $pages = 1;
             }
         }   
     
         if(1 != $pages)
         {
             echo "<div class=\"nav-links\">";
             //if($paged > 2 && $paged > $range+1 && $showitems < $pages) echo "<a href='".get_pagenum_link(1)."'>&laquo; First</a>";
             echo "<a class='page-numbers prev' href='".get_pagenum_link($paged - 1)."'><i class='icon icon-angle-left'></i></a>";
     
             for ($i=1; $i <= $pages; $i++)
             {
                 if (1 != $pages &&( !($i >= $paged+$range+1 || $i <= $paged-$range-1) || $pages <= $showitems ))
                 {
                     echo ($paged == $i)? "<span class=\"current\">".$i."</span>":"<a href='".get_pagenum_link($i)."' class='page-numbers'>".$i."</a>";
                 }
             }
     
             if ($paged < $pages && $showitems < $pages) echo "<a class='page-numbers next' href=\"".get_pagenum_link($paged + 1)."\"><i class='icon icon-angle-right'></i></a>";  
             //if ($paged < $pages-1 &&  $paged+$range-1 < $pages && $showitems < $pages) echo "<a href='".get_pagenum_link($pages)."'>Last &raquo;</a>";
             echo "</div>\n";
         }
    }

    The pagination works on every other page and I have tried removing the counter, offset etc. from the front page but the pagination still does the same thing. Any guidance on this would be much appreciated.

    • This topic was modified 7 years, 9 months ago by a_mulg.
Viewing 13 replies - 1 through 13 (of 13 total)
  • Moderator bcworkz

    (@bcworkz)

    Greetings Mr. a_mulg ??

    The problem is you are commingling two different queries. The one for your front page, which has only one item, so pagination does not occur. And you custom query which has pages of posts. It seems like there should be a way to work this out. Many have tried, few have succeeded. I don’t even bother trying. Working out my own pagination is not that difficult and avoids confusion between the two queries. For more on pagination in custom queries, please review Making Custom Queries using Offset and Pagination.

    Thread Starter a_mulg

    (@a_mulg)

    Hey bcworkz!

    I’ve had a look at the article you linked and tried out the code in there. I stripped out what I had in my front page template too, other than the query that defines the post types.

    So after that, with the front page set to static page, it still returns the same posts on every page. If I set the front page to latest posts, it shows the first page correctly, but returns a 404 on any subsequent page.

    So my loop currently looks like…

    <?php
    
                            $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
                            $query_args = array(
                            'post_type' => array ('post' , 'reviews' , 'trailer' , 'feature'),
                            'posts_per_page' => 10,
                            'paged' => $paged
                            );
    
                            $the_query = new WP_Query( $query_args );
                        ?>
    
                        <?php if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
    
    //content 
    
    <?php if (function_exists("pagination")) {
      pagination($the_query->max_num_pages);
     } ?>
    
                        <?php wp_reset_postdata(); ?>

    And my function looks like pretty much like the article…

    add_filter('found_posts', 'myprefix_adjust_offset_pagination', 1, 2 );
    function myprefix_adjust_offset_pagination($found_posts, $query) {
    
        //Define our offset again...
        $offset = 1;
    
        //Ensure we're modifying the right query object...
        if ( $query->is_home() ) {
            //Reduce WordPress's found_posts count by the offset... 
            return $found_posts - $offset;
        }
        return $found_posts;
    }

    I’m not quite sure which parts of my own code I need to keep and which parts of this code to modify? The counter and offset I was using appear to work correctly but getting them to work in conjunction the pagination seems to be the hard part!

    Moderator bcworkz

    (@bcworkz)

    The found posts bit is only for determining the final page in pagination links, it does not affect you query in any way.

    You would keep most of your code, there’s only a few changes. What you need to do in your query is NOT use ‘paged’ as your query argument in your actual query, instead calculate the offset based on the value of get_query_var( 'paged' ) and posts per page. Then assign the result to the ‘offset’ query argument. The second example in the previously linked article that uses the pre_get_posts action is closer to what you need to do, but how the result is added to the query is completely different. You still need to affect the same query vars, except it’s done differently.

    Instead of using $query->set('offset', $page_offset ), you simply include it in your query arguments array: 'offset' => $page_offset, in place of 'paged' => $paged.

    In studying that second pre_get_posts example a bit more, none of it has much bearing on your query except where it calculates the offset. Anything besides that where $query methods are used does not apply to you. As it happens, this article is not as useful as I had thought. While the information you need is there, how it is applied is very different. It takes a major mental abstraction to apply what is presented to your situation.

    You do have a different situation when paged is not defined or equals 1 because of the 11 posts output. You’ve dealt with this in your original post’s code. It does not seem to be addressed in your latest version, unless it is done outside of the provided snippet. If not, your original version should work after making the same modification for offset. In that version you used both offset and paged arguments. You should now know that can never work, you can only use one or the other.

    Thread Starter a_mulg

    (@a_mulg)

    Ok, so I’ve reverted back to my original code and what I’m not quite understanding is what $page_offset is, particularly if I don’t include the previous code in my functions file?

    So at the moment I have the following query on my front page and have removed the function, but I’m receiving an Undefined variable error for page_offset…

    <?php
    
        $first_page_post_count = 11;
        $subsequent_pages_post_count = 10;
        $paged = $paged ? $paged : 1;
    
        if($paged > 1){
        // not first page
        $posts_per_page = $subsequent_pages_post_count;
    
        if($paged == 2){
        // second page
        $offset = $first_page_post_count;
        } else {
        // subsequent pages
        $offset = $first_page_post_count + ($subsequent_pages_post_count * ($paged - 2));
        }
    
        } else {
        // first page
        $offset = 0;
        $posts_per_page = $first_page_post_count;
        }
    
        $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
        $query_args = array(
        'post_type' => array ('post' , 'reviews' , 'trailer' , 'feature'),
        'posts_per_page' => $posts_per_page,
        'offset' => $page_offset,
        );
    
        $the_query = new WP_Query( $query_args );
    ?>

    So I guess what I’m wondering is where/how to define the page_offset variable? I tried something like this $offset = $first_page_post_count + ($subsequent_pages_post_count * ($query->query_vars['paged']-1)); but not sure if I’m even on the right track with that!

    Moderator bcworkz

    (@bcworkz)

    I think you have the right idea, though your offset might be off by a page’s worth of posts.

    First try simply 'offset' => $offset, That should at least stop PHP errors and return something for every page. Whether it’s the right posts for the page is another story. You’re probably off by 10 (or whatever posts per page) if anything at all, so the terminal -1 may need to be -2 or 0, depending on which way you’re off.

    Given 11 posts on page 1 and 10 posts on all subsequent pages, the offset for each page should come out to be 0 for page 1, 11 for page 2, 21 for page 3, 31 for page 4, etc. How you arrive at those offsets doesn’t matter too much, as long as you get there.

    Thread Starter a_mulg

    (@a_mulg)

    I think that’s what my current code is supposed to be doing, but could be wrong.

    $first_page_post_count = 11;
    $subsequent_pages_post_count = 10;
    $paged = $paged ? $paged : 1;
    
    if($paged > 1){
    // not first page
    $posts_per_page = $subsequent_pages_post_count;
    
    if($paged == 2){
    // second page
    $offset = $first_page_post_count;
    } else {
    // subsequent pages
    $offset = $first_page_post_count + ($subsequent_pages_post_count * ($paged - 2));
    }
    
    } else {
    // first page
    $offset = 0;
    $posts_per_page = $first_page_post_count;
    }

    I think this is saying the second page should be offset by the first page post count (11), but this part I’m not entirely clear on…

    $offset = $first_page_post_count + ($subsequent_pages_post_count * ($paged - 2));

    Obviously the first part is saying the offset should be 11 + 10, but I’m not sure what the rest of that equation is supposed to do? I feel like that is the part that’s preventing the offset from working correctly, as the rest of it looks like it should work?

    Moderator bcworkz

    (@bcworkz)

    Yeah, it looks OK, I think the only problem is the need for 'offset' => $offset, instead of 'offset' => $page_offset,

    I mentioned the offset results we want just in case the above fix was not enough. I didn’t attempt to parse the code to determine the offset because doing so by eye is error prone. But since you’re not clear on this, let’s look closer.
    $paged == 1 or undefined: We end up at //first page where $offset = 0 ∴ Good
    $paged == 2 : We end up at //second page where $offset = 11 ∴ Good
    $paged == 3 : $offset = 11 + (10 * (3 – 2)) = 21 ∴ Good
    $paged == 4 : $offset = 11 + (10 * (4 – 2)) = 31 ∴ Good
    $paged == 5 : $offset = 11 + (10 * (5 – 2)) = 41 ∴ Good

    It all looks good! Can you now see how the -2 is a multiplier adjustment to account for the fact we already have two pages worth of posts in just 11+10. We cannot use $paged directly as a multiplier of 10 posts per page, yet we do need $paged in some manner, so we adjust it.

    We just need to be sure $offset is associated with the query’s ‘offset’ argument. $page_offset is invalid because it’s undefined. Even if it was defined, the formula used is for a different situation that’s inapplicable here. $offset is what you want to use.

    Thread Starter a_mulg

    (@a_mulg)

    Yeah, I’ve been using $offset and removed $paged from my query, so it now just looks like this…

    $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
      $query_args = array(
       'post_type' => array ('post' , 'reviews' , 'trailer' , 'feature'),
       'posts_per_page' => $posts_per_page,
       'offset' => $offset
      );
    
     $the_query = new WP_Query( $query_args );

    But unfortunately it’s still returning the same posts! That’s currently with no offset function in my functions file, just the pagination code from my original post.

    Moderator bcworkz

    (@bcworkz)

    What happened to all the code establishing the value of $offset? That value is dependent on the value of $paged, which I see you are getting from the query var. That is fine, except it is happening after $offset was determined. How can $offset be properly determined if $paged is determined afterwards?

    Thread Starter a_mulg

    (@a_mulg)

    Ah apologies, that code is still there, I just didn’t paste it in. So having moved $paged above offset, it now looks like this, though the end result hasn’t changed…

    $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
    
    $first_page_post_count = 11;
    $subsequent_pages_post_count = 10;
    $paged = $paged ? $paged : 1;
    
    if($paged > 1){
    // not first page
    $posts_per_page = $subsequent_pages_post_count;
    
    if($paged == 2){
    // second page
    $offset = $first_page_post_count;
    } else {
    // subsequent pages
    $offset = $first_page_post_count + ($subsequent_pages_post_count * ($paged - 2));
    }
    
    } else {
    // first page
    $offset = 0;
    $posts_per_page = $first_page_post_count;
    }
    
    $query_args = array(
        'post_type' => array ('post' , 'reviews' , 'trailer' , 'feature'),
        'posts_per_page' => $posts_per_page,
        'offset' => $offset
    );
    
    $the_query = new WP_Query( $query_args );

    I wonder if the problem is something to do with my pagination code, which of course also uses the $paged variable. It doesn’t seem to be causing problems on the other pages that use it though.

    I also have this code in my loop, not sure if any of this could confuse things…

    <?php $counter = 0; if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
    <div class="col push--bottom <?php if(!is_paged() && ($counter==0)) { echo 'xsmall-12 featured-article'; $counter++; } else { echo 'xsmall-12 small-6 article-preview'; } ?> ">
    Moderator bcworkz

    (@bcworkz)

    OK, thanks. That looks good now. The loop code would not be affecting the query. We’re peeling away issues one by one. Each one of them has been a real issue, though clearly not the root cause. It’s frustrating when no progress seems to be made, but we are making progress. Even if we attacked the root cause first, these others would still have prevented success. I think I know what the root cause is, but I couldn’t be sure with those other issues in the way.

    The problem now is that the ‘paged’ query var actually belongs to the main query, which is a very different query than your custom query. When we request any page number > 1, WP internally knows anything > 1 is invalid for the main query since the request is for the single home page, so the ‘paged’ query var is unset before our code is able to make use of it. Being unset, our code assigns 1 to $paged. So of course you only get page 1 no matter the request.

    This can be quickly confirmed by adding something like $paged = 2; right below where the query var is assigned to $paged, overriding whatever the original $paged is. You should find page 2 posts are output as expected. Same with page 3, 4, etc. until you run out of posts. I’ve confirmed this on my own site using your code, but you might want to still check for yourself. Your site is very different than mine.

    BTW, you don’t need $paged = $paged ? $paged : 1; because the same logic is established when the query var is assigned. It doesn’t hurt to have it, but it doesn’t serve any purpose. Just FYI in case you do write something like this in the future, it should be $paged = isset( $paged ) ? $paged : 1; $paged alone as the boolean of the ternary construct, if unassigned, throws a PHP warning.

    Anyway, the query var ‘paged’ in this context is not reliable. We are left with 2 alternate approaches. Either extract the page number directly from the request in $_SERVER[‘REQUEST_URI’], or supply our own URL parameter in the pagination link to pass along the desired page number. I usually prefer the latter because it’s more “honest”, but it would mean making a custom pagination function just for this page.

    To extract the page requested and assign it to $paged, replace the line that assigns the query var to $paged with this:

    preg_match('%/page/([0-9]+)%', $_SERVER['REQUEST_URI'], $matches );
    $paged = isset( $matches[1] ) ? $matches[1] : 1;
    Thread Starter a_mulg

    (@a_mulg)

    I believe that’s working perfectly now! Thanks again for all your help on this, hopefully it’s the last issue I’ll have trouble with!

    Moderator bcworkz

    (@bcworkz)

    Awesome! You’re very welcome. I hope you remain trouble free, but we’re always available to help if not. No one with legitimate issues is ever a bother.

Viewing 13 replies - 1 through 13 (of 13 total)
  • The topic ‘Pagination returning same posts on each page’ is closed to new replies.