2

I've been using the following query to try to output only posts that are marked as stickies:

<?php
    $args = array(
        'post_type' => 'post',
        'posts_per_page' => 2,
        'post__in' => get_option('sticky_posts')
    );
?>

<?php query_posts($args); ?>
<?php if(have_posts()) : ?>

    <?php get_template_part('loop', 'feed-top-stories' ); ?>

<?php endif; ?>
<?php wp_reset_query(); ?>

I currently have no posts set as stickies on the website. Which tells me that nothing should show up in the loop. However, I found that it was pulling in 2 posts anyway (even though they weren't stickies)

So then I switched to a WP_Query object (as I was advised to avoid query_posts() in the past)

<?php

    $args = array(
            'post_type' => 'post',
            'post__in' => get_option( 'sticky_posts' ),
            'posts_per_page' => 2
    );

    $the_query = new WP_Query($args);

    if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post();

        get_template_part('loop', 'feed-top-stories' );

    endwhile; endif;

    wp_reset_postdata();

?>

But now it doesn't appear to be working at all, the loop seems to be outputting 2 posts, however both of them are the page that is being viewed, despite me setting the post_type parameter

  • @PieterGoosen that doesn't appear to fix my problem... although I don't see how ignoring the sticky posts would? – pealo86 Sep 16 '15 at 21:13
  • 2
    Sticky posts are automatically appended to the query, so I could see why Pieter would suggest ignoring them, since you're also explicitly querying sticky posts. I suggest looking at $the_query->request after it is run to see the SQL being generated, it's possible you have some incorrectly targeted filter interfering. – Milo Sep 16 '15 at 21:33
  • @Milo ah I see! Thanks. I've tried that and, although I'm no SQL expert, I'd say the request doesn't bear much resemblance to the query that I'm trying to make? (I'll post below this comment) – pealo86 Sep 17 '15 at 13:45
  • SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 2 – pealo86 Sep 17 '15 at 13:45
6

I currently have no posts set as stickies on the website. Which tells me that nothing should show up in the loop.

Exactly where you are wrong when passing an empty array to post__in. WordPress has some silly bugs which has no proper workaround and will most probably stay active bugs for a very long time. This is one of them.

When we pass a valid array of posts ID's to post__in, we get the following resultant SQL WHERE clause (NOTE: All test are done on a page)

AND wp_posts.ID IN (59,45) 
AND wp_posts.post_type = \'post\' 
AND (wp_posts.post_status = \'publish\' OR wp_posts.post_status = \'private\')

Now, if we have no stickies, thus passing an empty array to post__in, the following SQL is wrongly generated because the post__in parameter as seen as not set.

AND wp_posts.ID IN (59) 
AND wp_posts.post_type = \'post\' 
AND (wp_posts.post_status = \'publish\' OR wp_posts.post_status = \'private\')

This is an epic fail with unexpected output. Depending on the parameters you passed you get totally unrelated posts or no posts at all.

That is why you should always validate what you are passing to post__in if the passed values are a dynamic array to avoid this epic failure.

Just another note which might not make any sense at all, if you just need to query sticky posts, always set ignore_sticky_posts to 1 (true). The reason for this is, should you require to not query all the sticky posts or just stickies from a certain category, you get just the ones you need. If you do not ignore stickies, all stickies will be returned regardless of what you have queried (yet another silly bug in my opinion).

You can rewrite your code as follow

$stickies = get_option( 'sticky_posts' );
// Make sure we have stickies to avoid unexpected output
if ( $stickies ) {
    $args = [
        'post_type'           => 'post',
        'post__in'            => $stickies,
        'posts_per_page'      => 2,
        'ignore_sticky_posts' => 1
    ];
    $the_query = new WP_Query($args);

    if ( $the_query->have_posts() ) { 
        while ( $the_query->have_posts() ) { 
            $the_query->the_post();

            get_template_part('loop', 'feed-top-stories' );

        }    
        wp_reset_postdata();    
    }
}
  • 1
    "Just another note which might not make any sense at all, if you just need to query sticky posts, always set ignore_sticky_posts to 1 (true). The reason for this is, should you require to not query all the sticky posts or just stickies from a certain category, you get just the ones you need. If you do not ignore stickies, all stickies will be returned regardless of what you have queried (yet another silly bug in my opinion)." And even if you do this, the post__not_in becomes useless nevertheless. – Lucian Davidescu Aug 14 '16 at 11:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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