• In the current code below, the WP_Query, in the theme’s index.php, is supposed to display the posts from one category and put the sticky posts at the top. The results are the posts are sorted by date and the sticky posts aren’t at the top. How do I get this criteria to work in the code?

    I also tried with two WP_Query loops, one for the sticky posts and one for the other posts but that was very confusing and was giving me a headache.

    Here is the current code:

    <?php
    
      $paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
    
      $args_posts = new WP_Query(array(
          'post_type' => 'post',
          'post_status' => 'publish',
          'cat' => '1',
          'posts_per_page' => 5,
          'paged' => $paged
      ));
    
      if ($args_posts->have_posts()):
          while ($args_posts->have_posts()) : $args_posts->the_post();
    
              $titleLink = get_post_meta($post->ID, '_mcf_title_link', true); ?>
    
              <div id="post-<?php $this_page_id = get_the_ID(); echo $this_page_id; ?>" class="post">
    
                  <div class="entry">
    
                      <?php if (!empty($titleLink)) : ?>
    
                          <h3>
                              <a href="<?php echo $titleLink; ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a>
                          </h3>
    
                          <?php $path = $_SERVER['SCRIPT_NAME']; elseif ($path == "/ecotourism/") : ?>
    
                          <div id="ecotitle">
                              <h1>
                                  <a href="<?php echo $titleLink; ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a>
                              </h1>
                          </div>
    
                      <?php else : ?>
    
                          <h3>
                              <a href="<?php the_permalink() ?>" title="<?php the_title(); ?>"> <?php the_title(); ?></a>
                          </h3>
    
                      <?php endif;
    
                      the_content();
    
                      edit_post_link('edit', '<p class="postmetadata">', '</p>'); ?>
    
                  </div>
                  <div style="clear:both;"></div>
              </div>
          <?php endwhile;
      endif;
    
    ?>
Viewing 9 replies - 1 through 9 (of 9 total)
  • According to the WP_Query documentation, sticky posts should come first in the output – without you having to do anything about it. Look here https://developer.wordpress.org/reference/classes/wp_query/ at “ignore_sticky_posts”.

    Thread Starter Amelia Rose

    (@shawnrisk)

    Thanks! Are you saying that my code would work to put sticky posts first without any changes? If yes, confusing as this isn’t. Maybe something else not mentioned here is causing this problem.

    I’ve used ignore_sticky_posts before with 1 or false and both didn’t do anything differently.

    Moderator bcworkz

    (@bcworkz)

    When you use the “cat” or similar query args, it causes WP_Query::is_home to be false, which then suppresses sticky behavior regardless of the ignore_sticky_posts value. (refer to line 3259 of WP_Query::get_posts() source code to see where this property is checked to determine sticky behavior) When you make a regular posts query without “cat” or similar, is_home becomes true, even if not actually a home page query. I’ve no idea why, but it is what it is.

    You can regain sticky behavior by setting is_home property to true in the query’s “pre_get_posts” action. This could cause other unintentional behavior, I’ve not thoroughly investigated this little hack. I recommend adding the action callback just before you instantiate WP_Query. Have your callback remove itself from the action call stack after it sets the is_home value so this change does not impact any other queries. This should minimize any unintentional behavior.

    The sticky behavior will list sticky posts even if they are not in the category you are requesting.

    It doesn’t look like you’ve implemented pagination yet. If you intend to, be advised that the “paged” query var you are getting relates to the main query, not your custom category query. “paged” will not be greater than the max. pages of the main query, which in some cases will always be 1 and only 1, so you cannot get additional pages beyond the 5 posts you initially queried. I recommend implementing your own unique pagination query var so it’s not confused with the main query’s pagination.

    When you wish to output pagination links for a custom non-main query, you need to use paginate_links(). All other pagination functions assume you want to paginate the main query.

    ETA: FYI, elseif ($path == "/ecotourism/") will throw an undefined var warning if the if (!empty($titleLink)) condition is false because the $path assignment is within that conditional. I suggest moving the assignment ($path = $_SERVER['SCRIPT_NAME']) outside of the conditional.

    • This reply was modified 1 year, 10 months ago by bcworkz.
    Thread Starter Amelia Rose

    (@shawnrisk)

    Thanks! All the advice is really good and very helpful in moving forward. I will look into everything and implement what I can.

    Do you think this issue needs to go in the WordPress core trac?

    I put this code in functions.php and this is working to put sticky posts first and the other posts second. If anyone tells me that there are issues with the code when they visit the website, I will make sure to make changes.

    function posts_modifications_20220531($query) {
    
    	if(is_admin()) {
    		return;
    	}
    
    	if($query->is_main_query() && $query->is_home()) {
    		$query->set('posts_per_page', 5);
    		$query->set('cat', 1);
    	}
    
    }
    add_action('pre_get_posts', 'posts_modifications_20220531');
    Moderator bcworkz

    (@bcworkz)

    I thought the behavior was intentional since sticky posts might not be in the requested category. But the WP_Query doc page on pagination implies “ignore_sticky_posts” setting should still apply, even with category requests. There are situations where applying sticky posts would be illogical, but letting the lack of is_home() override explicit “ignore_sticky_posts” is illogical to me. So yes, I think a Trac ticket would be warranted. Just make sure there isn’t a similar one already.

    Thread Starter Amelia Rose

    (@shawnrisk)

    @bcworkz You have much more knowledge about this issue. Would you be able to create the Trac ticket if there isn’t a similar one already?

    Moderator bcworkz

    (@bcworkz)

    Looks like this has been hashed over already.
    https://core.trac.wordpress.org/ticket/25815
    The suggested workaround in the last comment is a better solution than the one I came up with.

    Thread Starter Amelia Rose

    (@shawnrisk)

    Thanks. The ticket you linked was closed 8 years ago. Is there no way to get something in the core that will make this easier for everyone?

    Moderator bcworkz

    (@bcworkz)

    You can re-open the ticket and plead your case why stickies are important in non-home situations and that an explicit “ignore_sticky_posts” query var should take precedence over a is_home check. If you add appropriate workflow tags, the ticket will appear in related reports that core devs use. If you are able to provide a patch file that implements a solution, the issue is more likely to gain traction.

    You could instead start a new ticket, but it’s likely to be closed as a duplicate unless it’s clear how your situation is unique from existing tickets.

Viewing 9 replies - 1 through 9 (of 9 total)
  • The topic ‘Create a WP_Query with Category and Sticky Posts’ is closed to new replies.