using post__in allow duplicate post id

The situation

An array like array( 1,2,3,4,2,5 ) will be read like the following:

Array(
     0 => 1
    ,1 => 2
    ,2 => 3
    ,3 => 4
    ,4 => 2
    ,5 => 5
) [length = 6 ]

which seems ok. But when you look at the WP_Query object, you’ll see the following part added to the query string:

" AND {$wpdb->posts}.ID IN ($post__in)"

This means that each post will be fetched once.

Conclusion

So unless you don’t modify the query to include the post multiple times, you’ll be left with only an option to do this on runtime.

Runtime configuration possibilities and x-raying the internals

Every basic loop looks like this:

if ( have_posts() )
{
    while( have_posts )
    {
        the_post();
        // do stuff
    }
}

Now the global $post refers to what gets setup via the_post(). It basically is a wrapper for $GLOBALS['wp_query']->the_post();. And when you take a look at the WP_Query::the_post() method, you’ll find quite interesting things:

function the_post() {
    global $post;
    $this->in_the_loop = true;

    if ( $this->current_post == -1 ) // loop has just started
        do_action_ref_array('loop_start', array(&$this));

    $post = $this->next_post();
    setup_postdata($post);
}

There you see $this->next_post(); called. And this one looks from the inside like the following:

function next_post() {

    $this->current_post++;

    $this->post = $this->posts[$this->current_post];
    return $this->post;
}

Solution

So you see that the main thing the loop relies on, is the current_post counter. This one is as well accessible from the front end/a template. Simply use

$GLOBALS['wp_query']->current_post

to “jump” between posts. So if you need to repeat a post after post X, then just check against it, switch for one round and then skip back.

Leave a Comment