wp_query for the first sticky, then display the rest of the posts excluding the first sticky

I’ve been reading this by @nacin and getting to grips with wp_query over query_posts that I used to use.

What I want is:

Read More
  1. to put this in a template file

  2. to query all posts of this category, in this case ‘3’

  3. to display, if available, the first result on the page the latest sticky post

  4. after the first sticky, if one is set, display the rest of the posts excluding that sticky if it was set

Problems I have seen are:
– if I do posts_per_page = 1 on the sticky loop, I can not do posts_per_page = -1 on the rest of the posts loop. To workaround this I’ve just set the number to 999.

I should say now that the code I have works. However this is for a very high traffic site, and I want to make sure this is the best way of doing it, and I’m not sure I’m using wp_query right to do this since the original query’s are essentially the same as one another just with and without sticky posts.

global $wp_query;
$wp_query = new WP_Query(array(
    'post_type' => 'post',
    'posts_per_page' => 1,
    'category__in' => 3,
    'post__in'  => get_option( 'sticky_posts' )
));
while ($wp_query->have_posts()) : $wp_query->the_post();
    $exclude_featured = $post->ID;
    echo the_title();
    echo '<br />';
endwhile; 

echo '<br />';
echo '<br />';

global $wp_query;
$args = array_merge(
    $wp_query->query_vars,
    array(
        'post__in' => null,
        'posts_per_page' => 999,
        'ignore_sticky_posts' => 1,
        'post__not_in' => array($exclude_featured)
    )
);
query_posts( $args );
while ($wp_query->have_posts()) : $wp_query->the_post(); 
    if ( $exclude_featured == get_the_ID() )
        continue;
        echo the_title();
        echo '<br />';
endwhile; 

Thanks for any help guys.

Related posts

Leave a Reply

3 comments

  1. you could use wp_list_pluck();

    if ( $exclude_featured )
        $args['post__not_in'] = wp_list_pluck( $exclude_featured->posts, 'ID' );
        $args['posts_per_page'] = 999;
        query_posts( $args );
    endif;
    while ( have_posts() ) : the_post();
    ...
    
  2. Here is the really simple way to do it.

    $args = array(
              'posts_per_page' => -1,
              'category__in' => 3,
              'ignore_sticky_posts' => 0
           );
    
    $my_custom_query = new WP_Query( $args );
    
    while ( $my_custom_query->have_posts() ) :$my_custom_query->the_post();
    
    <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    //Your Stuff
    
    endwhile;
    
    // Reset Post Data
    wp_reset_postdata();
    
    • No need to use global $wp_query; especially 2x.
    • No need to echo br tags…several times if your using the <?php post_class(); Use CSS, that way you will automatically get a class called .sticky !
    • Use a better name for your query.

    Here is an update using 2 queries to address the details I missed, since it will be somewhat safe.

    // **Loop 1** get the first sticky only 
    
    $sticky = get_option( 'sticky_posts' );
    
    $the_query = new WP_Query( 'p=' . $sticky[0]);
    
    while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
    
    <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    
    // your content
    
    <?php endwhile; wp_reset_postdata(); ?>
    
    //////////////
    //**Loop 2** exclude the sticky from the Loop 1
    
    $args = array(
            'posts_per_page' => -1,
            'ignore_sticky_posts' => 1,
            'post__not_in' => array($sticky[0])
    
    );
    
    $super_query = new WP_Query($args);
    
    while ( $super_query->have_posts() ) : $super_query->the_post(); ?>
    
    <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    
    // your content
    
    <?php endwhile; wp_reset_postdata(); ?>
    
  3. I see 2 major problems. a) You shouldn’t modify a global variable directly & b) You shouldn’t use query_posts. Here’s a reworked example

    functions.php

    add_action('pre_get_posts', 'customize_query');
    function customize_query($query) {
        if(!$query->is_main_query() || !is_page_template('template-file-name.php'))
            return;
    
        $wp_query = new WP_Query(array(
            'post_type' => 'post',
            'posts_per_page' => 1,
            'category__in' => 3,
            'post__in'  => get_option( 'sticky_posts' )
        ));
    
        $query->set('posts_per_page', -1);
        $query->set('ignore_sticky_posts', 1);
        if(!empty($wp_query->posts))
            $query->set('post__not_in', array($wp_query->posts[0]->ID));
    
    }
    

    in the template file

    $query = new WP_Query(array(
        'post_type' => 'post',
        'posts_per_page' => 1,
        'category__in' => 3,
        'post__in'  => get_option( 'sticky_posts' )
    ));
    while ($query->have_posts()) : $query->the_post();
        echo the_title();
        echo '<br />';
    endwhile; 
    
    echo '<br />';
    echo '<br />';
    
    while (have_posts()) : the_post(); 
            echo the_title();
            echo '<br />';
    endwhile;