3

I have an array of ids in a specific order. I use post__in in my query to get posts from this array. I have some duplicate post IDs that I need to show twice in the page but the query seems to ignore them. Let's say the array is as follows

array values  = 1,2,3,4,2,5

When I pass this array to post__in, it doesn't take value '2' twice as i specified in the array. Is there a workaround for this?

3
  • Are you using this with WP_Query?
    – kaiser
    Mar 20, 2013 at 11:02
  • Kaiser: i am using query_posts and post__in is in my $args
    – KT.
    Mar 20, 2013 at 14:53
  • See my answer below...
    – kaiser
    Mar 20, 2013 at 15:07

2 Answers 2

2

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.

8
  • kaiser, great solution. but the array i am giving comes from a wpdb that queries the database for certain posts. So i don't always know when there will be a repeating ID.
    – KT.
    Mar 21, 2013 at 5:12
  • @KT. That's no problem. Just use $GLOBALS['wp_query']->found_posts and use basic Math functions to calculate your way through it (how many steps do I have to jump back-/forward?).
    – kaiser
    Mar 21, 2013 at 12:17
  • im not quite sure i understand what you mean. please elaborate. Thanks!
    – KT.
    Apr 2, 2013 at 13:13
  • @KT. Just use $GLOBALS['wp_query']->found_posts to get the maximum limit. Then use $GLOBALS['wp_query']->current_post with math operators like ++ or -- to switch forward or backward inside the $wp_query object get the desired posts. You can as well use $GLOBALS['wp_query']->next_post() and similar to switch your posts around. Align that with your array and you're fine.
    – kaiser
    Apr 2, 2013 at 13:45
  • @KT. If this is too much for you, then you might consider looking for a solution on StackOverflow that lets you sort an array like $wp_query posts object by the numerical keys of another array. This would work as well.
    – kaiser
    Apr 2, 2013 at 13:49
1

You can loop your ids and call get_post and setup_postdata :

global $post;
foreach ($ids as $id) :
    $post = get_post($id);
    setup_postdata( $post );
    the_title();
endforeach;

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.