Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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.

share|improve this question

3 Answers 3

up vote 0 down vote accepted

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();
...
share|improve this answer
    
Can you describe what wp_list_pluck does for users that might not know? :) –  Brian Fegter Oct 21 '12 at 2:51
1  
Here is the reference in the wordpress codex codex.wordpress.org/Function_Reference/wp_list_pluck It's a relative new function and I only learned of it because a premium theme I know is using it for this purpose ;) –  mirage Oct 21 '12 at 8:41

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(); ?>
share|improve this answer
    
You're missing a closing bracket from your array, otherwise this works. However not as required. This stacks all sticky posts at the top of the loop. What I want is max of 1 stickypost at the top of the loop (the latest by date) regardless of how many are stickied, and then for subsequent results it should fall back into its place by date regardless of being a sticky or not. You're close, but I already had similar before I posted the question. Do you think you could possibly still do it with one loop? Thanks. –  davebowker Oct 20 '12 at 23:11
    
I've actually just noticed that if you specifically set the category you want it no longer outputs sticky posts at the top. –  davebowker Oct 20 '12 at 23:56
    
Sticky posts do not work for archive pages, for instance a custom category template when you query for the category, sticky means semantically something in the front page. To highlight posts for archive pages and such just create a category or taxonomy. To answer the 1 sticky question I would look ar this wordpress.stackexchange.com/questions/6493/… or Mridul Aggarwal answer in this thread. Also the other answer using wp_list_pluck for 1 query, its hard to say which is the fastest. –  Wyck Oct 21 '12 at 1:56
    
I updated my answer with an example of how to do it using 2 query's. –  Wyck Oct 21 '12 at 2:53

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;
share|improve this answer
    
Trying this, but it's throwing an error: Fatal error: Call to a member function have_posts() on a non-object. I tried to debug but I'm not really familiar enough with pre_get_posts –  davebowker Oct 20 '12 at 23:12
    
Did you put the correct template filename here !is_page_template('template-file-name.php')? –  Mridul Aggarwal Oct 20 '12 at 23:22
    
Yes, and I saw you just made an edit so I tried your new code and it's still throwing the same error. –  davebowker Oct 20 '12 at 23:24
    
i removed the caching functions, can you see once again –  Mridul Aggarwal Oct 20 '12 at 23:30
    
Error fixed now, but the second while loop is picking up the default wp_query of the page. EG, it gets the sticky in the first loop, then the page title in the second, not the list of results in the same query that aren't stickied. –  davebowker Oct 20 '12 at 23:35

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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