1

I have two Loops using WP_Query.

The first loop shows X posts. No pagination.
(loop A)

The second loop shows Y posts. With custom pagination.
(loop B)

It kinda works; but you can see the second loop repeating X posts from the first loop. First thing that comes to mind is to set an offset (equal to X), but it breaks pagination and there is a whole page on Codex dedicated to this issue. It also has a workaround, but the problem is I have two loops so this workaround applies to both of them.

So the question is
How do I make this work as intended?
A possible solution would be making the code from Codex "target" the second Loop, but I'm not a programmer and I don't know how to do this. Maybe there is even a better way to achieve what I'm trying to do, but I can't think of any other options.

Additional info
1) I can't use only one Loop because of how complicated my markup is.
2) All the code was found on the Net
3) Both loops are not restricted by authors or categories or whatever. It is always the same content with two different layouts "combined" to look like single "feed".

and since I can't post more than 2 links, here is the pagination code

function custom_pagination($numpages = '', $pagerange = '', $paged='') {
    if (empty($pagerange)) {
        $pagerange = 2;
    }

/**
    This first part of our function is a fallback
    for custom pagination inside a regular loop that
    uses the global $paged and global $wp_query variables.

    It's good because we can now override default pagination
    in our theme, and use this function in default quries
    and custom queries.
**/

global $paged;
if (empty($paged)) {
    $paged = 1;
}
if ($numpages == '') {
    global $wp_query;
    $numpages = $wp_query->max_num_pages;
    if(!$numpages) {
        $numpages = 1;
    }
}

/** 
    We construct the pagination arguments to enter into our paginate_links
    function. 
**/

$pagination_args = array(
    'base'            => get_pagenum_link(1) . '%_%',
    'format'          => 'page/%#%',
    'total'           => $numpages,
    'current'         => $paged,
    'show_all'        => False,
    'end_size'        => 1,
    'mid_size'        => $pagerange,
    'prev_next'       => True,
    'prev_text'       => __('«'),
    'next_text'       => __('»'),
    'type'            => 'plain',
    'add_args'        => false,
    'add_fragment'    => ''
);

$paginate_links = paginate_links($pagination_args);

if ($paginate_links) {
    echo "<nav class='custom-pagination'>";
        echo "<span class='page-numbers page-num'>Page " . $paged . " of " . $numpages . "</span> ";
        echo $paginate_links;
    echo "</nav>";
}
}

solution from Codex

add_action('pre_get_posts', 'myprefix_query_offset', 1 );
function myprefix_query_offset(&$query) {

//Before anything else, make sure this is the right query...
if ( ! $query->is_home() ) {
    return;
}

//First, define your desired offset...
$offset = 1;

//Next, determine how many posts per page you want (we'll use WordPress's settings)
$ppp = get_option('posts_per_page');

//Next, detect and handle pagination...
if ( $query->is_paged ) {

    //Manually determine page query offset (offset + current page (minus one) x posts per page)
    $page_offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );

    //Apply adjust page offset
    $query->set('offset', $page_offset );

}
else {

    //This is the first page. Just use the offset...
    $query->set('offset',$offset);

}
}


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;
}

1 Answer 1

3

I can't use only one Loop because of how complicated my markup is.

Markup, no matter how complicated, should never ever be a valid basis when coming to deciding to run multiple loops. Multiple loops should only ever be used if there is absolutely no other means to achieve a certain result, and that is almost always just when different results are needed per query argument, like different posts per page per post type.

Both loops are not restricted by authors or categories or whatever

The above statement also does not validate the use of a second loop. Just based on this statement, we would only need one loop regardless of how complicated your markup is

How the results are displayed from a specific query can always be manipulated by the following

  • rewind_posts() which lets you rerun the loop a second, third or a hundredth time depending on your needs

  • custom counters or the build in loop counter which counts posts and let you do something different if the loop counter/custom counter hits a specific number

  • conditional tags/statements which let target specific posts according to specific conditions, for example post type or category

  • filters like the the_posts which lets you alter the array of returned posts which include adding/removing and/or rearranging posts

  • normal PHP functions like usort() which can be used to sort the returned array of posts before outputting them to screen

  • we can always manipulate the main query with pre_get_posts to display what we want

These are just a few options which you can use instead of running multiple loops. The issue with multiple loops are

  • they are allows problematic when it comes to pagination

  • causes unnecessary database queries which slows page load times and waste resources

One important thing you should always remember is, you must never replace the main loop which displays results from the main query with a custom query. They always lead to more issues than solving them. You should take your time and read the following post:

To solve your issue, you can remove your pre_get_posts action and the found_posts filter as you do not need to set any offsets or recalculate pagination.

You will need to adjust your loop on the desired page according to your needs

EXAMPLE 1

Styling the first post different and display more info that other posts

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();

            if ( 0 === $wp_query->current_post ) { // Target the first post only
                // Do what you need to do for the first post only
            } else {
                // Display all the other posts as needed   
            }
    }
}

OR

if ( have_posts() ) {
    // Start our custom counter
    $counter = 0;
    while ( have_posts() ) {
        the_post();

            if ( 0 === $counter ) { // Target the first post only
                // Do what you need to do for the first post only
            } else {
                // Display all the other posts as needed   
            }
        // Update the counter 
       $counter++;
    }
}

You can apply this method to any complex markup. You can set custom counters to open and close custom divs, apply different styling to post position or even create post grids. I have done quite a few posts on this, so be sure to search through my answers

EXAMPLE 2

If you need to display posts grouped by post type with post types post and page. Here we will run the loop to display posts from the post post type, rewind the loop and rerun it, but this time display only page post type posts

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();

            if ( 'post' === get_post_type() ) { // Only display posts from post post type
                // Do what you need to do post post type posts
            } 
    }

    rewind_posts(); // Rewind the loop so we can run it again

    while ( have_posts() ) {
        the_post();

            if ( 'page' === get_post_type() ) { // Only display posts from page post type
                // Do what you need to do page post type posts
            } 
    }
}

CONCLUSION

So as you see, no matter how complex you might feel your mark up is, it always does not validate the need for multiple loops, one loop will always be enough, we just need to use the loop, PHP and filters cleverly to our advantage

1
  • You made a good point here. after looking at this from a different perspective, I've made a few changes and your solution works great. thank you!
    – Colton
    Feb 15, 2016 at 12:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.