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

The question:

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:

  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.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 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();
...

Method 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(); ?>

Method 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;


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment