1

I'm developing a theme that has a featured posts section before the main loop of posts. Cool and fresh, right?:) All sticky posts with a featured image in place must be displayed in that section and excluded from the main loop. Easy peasy. Doing my research, I stumbled upon a pretty old article on the matter that I found very useful. It advocates not to use query_posts, which I did before, and offers a more elegant approach instead:

    /**
    * Filter the home page posts, and remove any featured post ID's from it. Hooked
    * onto the 'pre_get_posts' action, this changes the parameters of the query
    * before it gets any posts.
    *
    * @global array $featured_post_id
    * @param WP_Query $query
    * @return WP_Query Possibly modified WP_query
    */
    function itheme2_home_posts( $query = false ) {

      // Bail if not home, not a query, not main query, or no featured posts
      if ( ! is_home() || ! is_a( $query, 'WP_Query' ) || ! $query->is_main_query() || ! itheme2_featuring_posts() )
      return;

      // Exclude featured posts from the main query
      $query->set( 'post__not_in', itheme2_featuring_posts() );

      // Note the we aren't returning anything.
      // 'pre_get_posts' is a byref action; we're modifying the query directly.
    }
    add_action( 'pre_get_posts', 'itheme2_home_posts' );

    /**
    * Test to see if any posts meet our conditions for featuring posts.
    * Current conditions are:
    *
    * - sticky posts
    * - with featured thumbnails
    *
    * We store the results of the loop in a transient, to prevent running this
    * extra query on every page load. The results are an array of post ID's that
    * match the result above. This gives us a quick way to loop through featured
    * posts again later without needing to query additional times later.
    */
    function itheme2_featuring_posts() {
      if ( false === ( $featured_post_ids = get_transient( 'featured_post_ids' ) ) ) {

        // Proceed only if sticky posts exist.
        if ( get_option( 'sticky_posts' ) ) {

          $featured_args = array(
            'post__in'      => get_option( 'sticky_posts' ),
            'post_status'   => 'publish',
            'no_found_rows' => true
          );

          // The Featured Posts query.
          $featured = new WP_Query( $featured_args );

          // Proceed only if published posts with thumbnails exist
          if ( $featured->have_posts() ) {
            while ( $featured->have_posts() ) {
              $featured->the_post();
              if ( has_post_thumbnail( $featured->post->ID ) ) {
                $featured_post_ids[] = $featured->post->ID;
              }
            }

            set_transient( 'featured_post_ids', $featured_post_ids );
          }
        }
      }

      // Return the post ID's, either from the cache, or from the loop
      return $featured_post_ids;
    }

Everything works great except the transients. I can't figure out how to reset the transient if sticky_posts has been updated. Probably use the updated_option hook? Would appreciate any help.

1

You can try:

add_action('update_option_sticky_posts', function( $old_value, $value ) {
         $featured_args = array(
            'post__in'      => $value,
            'post_status'   => 'publish',
            'no_found_rows' => true
          );

          // The Featured Posts query.
          $featured = new WP_Query( $featured_args );

          // Proceed only if published posts with thumbnails exist
          if ( $featured->have_posts() ) {
            while ( $featured->have_posts() ) {
              $featured->the_post();
              if ( has_post_thumbnail( $featured->post->ID ) ) {
                $featured_post_ids[] = $featured->post->ID;
              }
            }

            set_transient( 'featured_post_ids', $featured_post_ids );
          }
}, 10, 2);

I suppose you have the post IDs on the sticky_posts option that's why you are querying with that in the WP_Query

  • I'm not sure how I can integrate your solution in my existing code. Could you explain, please? – Nikita Dec 8 '17 at 18:19
  • 1
    @Baltar Ofcource If I understand correctly the sticky_posts options has the sticky post you want with one of the following formats (array(1,2,3) or "1,2,3"). This is why I monitoring the changes on this options by hooking the action update_option_{sticky_posts} You can now have the new values every time you update the option in the $value parameter of the action. The only now step was to loop and update the transient the same way you did it. Tell me if I understand it wrong. – Drupalizeme Dec 8 '17 at 18:25
  • You got it right, your solution makes sense and works. Thanks! – Nikita Dec 8 '17 at 18:55
  • There is, however, one scenario in which it will not work as expected. When you go from n sticky posts (with a transient in place) to zero, the transient will still have some posts in it, strangely even not the ones you've just un-sticked. I found that deleting the transient if $value is empty in your answer fixes the issue. If you confirm and agree with the solution, I'd appreciate if you edit your answer. @Drupalizeme – Nikita Dec 8 '17 at 20:25
  • @Baltar This will have the same effect as if you initialize the ‘$featured_post_ids’ as an empty array. – Drupalizeme Dec 8 '17 at 22:53
0

The WP_Query class offers a parameter to include/exclude sticky posts. There's no need to store their IDs anywhere. Just create a new query, and output the sticky posts that have a featured image:

$sticky = get_option( 'sticky_posts' );
$query = new WP_Query( array( 'p' => $sticky ) );

Now, you can create another loop and exclude the sticky posts:

$query = new WP_Query( array( 'post__not_in' => get_option( 'sticky_posts' ) ) );

You can also set the 'ignore_sticky_posts' => 1 to ignore the sticky posts in your loop.

That's all you need.

  • I'm excluding sticky posts from the main loop, so new WP_Query is not an option here. – Nikita Dec 8 '17 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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