Excluding Sticky Posts from The Loop and from WP_Query() in WordPress?

The following snippet is from a sidebar widget that lists “recent posts”. Since its on the home page and I feature my lastest sticky post prominently on that page, I want to skip over the sticky in this loop. However, the post_not_in=sticky_posts has no effect.

<?php
    $the_query = new WP_Query("showposts=$number&offset=1&order=ASC&post_not_in=sticky_posts");

    while ($the_query->have_posts()) : $the_query->the_post();
        $do_not_duplicate = $post->ID; ?>

Related posts

Leave a Reply

4 comments

  1. I took @tnorthcutt’s answer from WordPress’ Codex on query_posts() about Sticky Parameters and created a tandalone example you can drop as test.php into your website’s root and see it run by navigating to a URL like this, with your domain substituted:

    http://example.com/test.php

    Some notes on the code; I had to use an array equivalent of the query string you passed to WP_Query() because the post__no_in argument can’t be passed in as a comma delimited string (not sure why, probably an oversight?).

    Also I wanted to make sure you know that starting with an offset=1 (instead of offset=0) means you’ll be excluding the first post that otherwise would be returned by the query. Of course you’ll still get the number of posts specified by $number assuming you have that many applicable posts +1. So here’s the code:

    <?php
    header('Content-Type:text/plain');
    include "wp-load.php";
    
    $number = 5;
    
    $the_query = new WP_Query(array(
      'showposts' => $number,
      'offset' => 1,  // This will cause the query to skip over first post
      'order' => 'ASC',
      'post__not_in' => get_option("sticky_posts"),
      ));
    while ($the_query->have_posts()) : $the_query->the_post();
      the_title(); 
    endwhile;
    
  2. If you want to exclude all sticky posts from a query, use

    query_posts(array("post__not_in" =>get_option("sticky_posts")));

    (from the codex)

    Looks like that will only work on 3.0 or greater, though: http://wordpress.org/support/topic/excluding-sticky-posts-using-query_posts

    Edit: in response to your comment below, try this (I’m not sure this will work, but hopefully it will get you started):

    <?php 
    $args=array(
        'showposts'=>'$number',
        'offset'=>'1',
        'order'=>'ASC',
        'post__not_in'=>get_option("sticky_posts")
        );
    $the_query = new WP_Query($args);
    
        while ($the_query->have_posts()) : $the_query->the_post();
    
            $do_not_duplicate = $post->ID; ?>
    
  3. Travis’ answer is fine if you’re building your own query, for a secondary loop perhaps, but if you need to modify your main blog query, you can use pre_get_posts to filter out the sticky posts.

    In the example below, I’m only excluding the sticky posts if the query is the blog page, as I still want sticky posts to be returned on taxonomy and search pages etc (I’m displaying sticky posts as featured articles on the main news page).

    add_action( 'pre_get_posts', 'custom_post_archive_changes' );
    function custom_post_archive_changes( $query ) {
        if ( is_home() && $query->is_main_query() ) {
    
            // exclude sticky posts from main news page
            $stickies = get_option("sticky_posts");
            $query->set( 'post__not_in', $stickies );
    
        }
    }
    

    Just drop the snippet above in your functions.php file.

  4. Just adding a more contemporary answer here, according to the WordPress docs you can use ignore_sticky_posts as an argument to exclude sticky posts from a WP Query object. Here’s an example altering the main loop on the posts page:

    function wpstackexchange_exclude_sticky_posts( $query ) {
        if ( is_home() && $query->is_main_query() ) {
            $query->set( 'ignore_sticky_posts', true);
        }
    }
    add_action( 'pre_get_posts', 'wpstackexchange_exclude_sticky_posts' );