1

What I'm trying to achive, is to set 2 loops on one page. First one takes 11 latest posts and sort them in rand order. Second show the rest of posts ordered by date.

FIRST LOOP

$args = array('posts_per_page' => 11,'orderby' => 'rand' , 'order' => 'ASC');
$loop = new WP_Query($args);
$do_not_duplicate[] = $post->ID;

while ($loop-> have_posts()) : $loop->the_post();
$do_not_duplicate[] = $post->ID;

SECOND LOOP

$args2 = array('posts_per_page' => 22, 'paged' => $paged, 'post__not_in' => $do_not_duplicate, 'orderby' => 'date', 'order' => 'ASC', 'max_num_pages' => 5);
$loop2 = new WP_Query($args2);

while ($loop2-> have_posts()) : $loop2->the_post();

My problem is that the second loop should show the same posts in same order after every refresh, unfortunately it's not. Any advice?

4 Answers 4

2

Yes, don't forget the <?php wp_reset_postdata(); ?> between loops. I remember getting stumped on that the first time I ran multiple queries on a page.

1
  • 1
    wp_reset_query() should be wp_reset_postdata(). wp_reset_query() is used with query_posts which you must never use Commented Feb 29, 2016 at 16:49
2

Getting posts randomly is quite expensive and should be avoided where needed. I think we can do this in a better way.

  • Lets query all posts at once, regardless, sorted by date. WE will only query ID's which should be extremely quick

  • Store the query results (post ID's) in two variables

  • Shuffle the one array of ID's to randomize them and then get the first 11 ID's

  • We will then remove those 11 ID's from the second array and get 22 ID's

  • Merge the two arrays and run our final query

Lets try the following code

$args = [ // ADJUST THESE AS NEEDED
    'posts_per_page' => -1,
    'order'          => 'ASC',
    'fields'         => 'ids' // Only get post ID's, this also bypass object caches
];
$array_1 = $array_2 = get_posts( $args );
// Make sure we have posts and we have more than 11 posts
if (    $array_1
     && 11 < count( $array_1 )
) {  
    // Shuffle the first array
    shuffle( $array_1 );
    // Get the first 11 entries sorted randomly
    $array_1_random = array_slice( $array_1, 0, 11 ); 
    // Remove the entries from $array_1_random from $array_2
    $difference     = array_diff( $array_2, $array_1_random );
    // Get the first 22 entries from $difference
    $diff_22_IDs    = array_slice( $difference, 0, 22 ); 
    // Merge the two arrays, $array_1_random and $diff_22_IDs
    $ids = array_merge( $array_1_random, $diff_22_IDs );

    // Now that we have our ID's sorted to suite our needs, query the posts
    $last_args = [ // DO NOT ADJUST THESE, SHOULD BE FINE
        'post__in'       => $ids,
        'orderby'        => 'post__in',
        'order'          => 'ASC',
        'posts_per_page' => count( $ids )
    ];
    $q = new WP_Query( $last_args );

    // Output your loop
    while ( $q->have_posts() ) {
        $q->the_post();

        the_title();

    }
    wp_reset_postdata(); // VERY VERY IMPORTANT
}

A FEW NOTES

  • Adjust the code as needed. You should have to change anything in $last_args though

  • You said you needed one page, so there is no need to set the paged parameter as we will not paginate. If you require pagination, you would need to adjust my code slightly

  • 'max_num_pages' is not a valid parameter

3
  • thanks for your comprehensive answer. Unfortunately I need to keep two seperate loops because of pagination. However, I found some clues in your in your solution Commented Mar 6, 2016 at 18:24
  • You should post your final code with explanation as an answer and accrpt your own answer ;-) Commented Mar 6, 2016 at 18:29
  • I did. Below. wordpress.stackexchange.com/a/219885/89711 Commented Mar 6, 2016 at 20:58
1

The second query will not always show the same posts, as it is dependend on the first query, which is random.

For example, you got 50 posts (ID 1 to 50, ordered by date).

First run:

First query takes 1,2,3,4,5,6,7,8,9,10,11 and passes those IDs to the second query, so the second query will show 12,13,14,...

Second run:

The first query randomly selects IDs 39,40,41,42,43,44,45,46,47,48,49,50, and the second query will return IDs 1-22.

Please be also sure to call wp_reset_postdata() to ensure the correct behaviour of all queries. (thanks @PieterGoosen :) )

1
  • 1
    wp_reset_query() should be wp_reset_postdata() Commented Feb 29, 2016 at 16:50
0

With some clues from @PieterGoosen I've found working solution.

First loop

$argsR = array(
      'numberposts' => 11,
      'fields'         => 'ids'
    );

$latest_posts =  get_posts( $argsR );
shuffle( $latest_posts );


$args = array('posts_per_page' => 11,
              'post__in' => $latest_posts , 
              'orderby' => 'post__in', 
              'order' => 'ASC');

$loop = new WP_Query($args);
$do_not_duplicate[] = $post->ID;

while ($loop-> have_posts()) : $loop->the_post();
    $do_not_duplicate[] = $post->ID;

So, first loop shows 11 most recent posts in random order and pushes each post ID to $do_not_duplicate[]array which I use to exclude most recent posts from second loop.

Second loop

$args2 = array(
    'posts_per_page' =>-1, 
    'post__not_in' => $do_not_duplicate, 
    'orderby' => 'date', 
    'order' => 'ASC');

$loop2 = new WP_Query($args2);
$num_of_posts = $loop->post_count;
while ($loop2-> have_posts()) : $loop2->the_post();

Having two seperate loops lets me paginate second posts list as I needed.

1

Your Answer

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

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