1

This code is part of a custom WordPress homepage that shows the 7 most recent posts using WP_Query, and the first post has a custom html structurer, while the rest has another html structure.

Then there is a second WP_Query that queries the 5 most recent posts for a specific tag while not showing any duplicate if a post has the same tag and it already appears the first WP_Query. Then the code also uses a custom html for the first post, and the rest are formatted differently.

For years, the code has been working OK, but recently it’s taking a long time (around 7 seconds) to load the page, and the WP_Query is shows as a very slow query using the Query Monitor plugin in WordPress.

So, how can optimize or rewrite the WP_Query and the "don’t duplicate code" to make it more efficient and faster so each block of the page show posts while filtering duplicate posts.

<section class="news-front">
</div>
      <div class="news-list-col-1">
          <?php $count = 0; //Count starts to edit each post ?>
        <?php $do_not_duplicate = array(); ?>

        <?php $query = new WP_Query(array (
                                    'posts_per_page' => 7,
                                    'no_found_rows' => true,
                                    )
                                  );?>

          <?php while ($query->have_posts()) : $query->the_post(); ?>
          <?php $do_not_duplicate[] = $post->ID; ?>
          <?php $count++; ?>
          <?php if ($count == 1) : ?>
              <article class="news-item-1" <?php post_class();?> >


                   <a href="<?php the_permalink() ?>" class="cover-link">

                  <?php if(has_post_thumbnail($post->ID)) :?><!-- .article_image -->

                    <div id="post-hero-image" style="background-image: url('<?php the_post_thumbnail_url('large'); ?>')" ></div><!-- .article_image -->
                    <?php else :?>

                          <!-- Nothing inside -->

                    <?php endif;?><!-- .article_image -->


                      <header class="news-item-data">

                         <h2 itemprop="headline" class="entry-title"><?php the_title(); ?></h2>

              <?php get_template_part( 'types/content', 'meta' ); ?><!-- .entry-meta -->

            <?php if( $post->post_excerpt ) : ?>
                              <div class="post-description" >
                                      <div class="post-descr-content" ><?php echo $post->post_excerpt; ?></div>
                              </div>
                          <?php else : ?>
                              <div class="post-description" >
                                      <div class="post-descr-content" ><?php custom_excerpt(154); ?></div>
                              </div>
                          <?php endif; ?>

                          </header>
                   </a>
              </article>


      </div>
      <div class="news-list-col">
          <?php else : ?>
          <article class="news-items-list" <?php post_class();?> >

                  <a href="<?php the_permalink() ?>" class="cover-link" >

          <?php if(has_post_thumbnail($post->ID)) :?><!-- .article_image -->

                <div id="post-hero-image" style="background-image: url('<?php the_post_thumbnail_url('medium_large'); ?>')" ></div><!-- .article_image -->
                    <?php else :?>

                          <!-- Nothing inside -->

                    <?php endif;?><!-- .article_image -->

                      <header class="news-item-data">
                          <h2 itemprop="headline" class="entry-title"><?php the_title(); ?></h2>
                          <?php get_template_part( 'types/content', 'meta' ); ?><!-- .entry-meta -->
                      </header>
                     <?php if ( !wp_is_mobile() ) :?>
                        <?php if( $post->post_excerpt ) : ?>
                          <div class="post-description" >
                              <div class="post-descr-content" ><?php echo $post->post_excerpt; ?></div>
                          </div>
                        <?php else : ?>
                          <div class="post-description" >
                              <div class="post-descr-content" ><?php custom_excerpt(154); ?></div>
                          </div>
                        <?php endif; ?>
                      <?php endif; ?>
                   </a>
          </article>
          <?php endif; ?>
          <?php   endwhile; wp_reset_postdata(); ?>
      </div>

  </section>

<section class="news-grid-5">
      <div class="news-list-col-1">

          <?php $count = 0; //Count starts to edit each post ?>
          <?php   $query = new WP_Query(array(
                                              'tag_slug__in' => array('how-to'),
                                              'posts_per_page' => 5,
                                              'order' => 'DESC',
                                              'no_found_rows' => true,
                                              'post__not_in' => $do_not_duplicate,
                                              )
                                            );?>
        <?php   while ($query->have_posts()) : $query->the_post(); ?>
          <?php   $do_not_duplicate[] = $post->ID; ?>
          <?php $count++; ?>
          <?php if ($count == 1) : ?>
          <article class="news-grid-5-item-1" >
              <a href="<?php the_permalink() ?>" class="cover-link" >
          <?php if(has_post_thumbnail($post->ID)) :?><!-- .article_image -->

                <div id="post-hero-image" style="background-image: url('<?php the_post_thumbnail_url('large'); ?>')" ></div><!-- .article_image -->
                    <?php else :?>

                          <!-- Nothing inside -->

                    <?php endif;?><!-- .article_image -->

          <header class="news-item-data">
                        <h2 itemprop="headline" class="entry-title"><?php the_title(); ?></h2>
                      <?php get_template_part( 'types/content', 'meta' ); ?><!-- .entry-meta -->
            <?php if( $post->post_excerpt ) : ?>
                              <div class="post-description" >
                                      <div class="post-descr-content" ><?php echo $post->post_excerpt; ?></div>
                              </div>
                          <?php else : ?>
                              <div class="post-description" >
                                      <div class="post-descr-content" ><?php custom_excerpt(154); ?></div>
                              </div>
                          <?php endif; ?>
                    </header>
               </a>
          </article>
    <?php else : ?>
          <article class="news-grid-1" >
              <a href="<?php the_permalink() ?>" class="cover-link" >

          <?php if(has_post_thumbnail($post->ID)) :?><!-- .article_image -->

                <div id="post-hero-image" style="background-image: url('<?php the_post_thumbnail_url('large'); ?>')" ></div><!-- .article_image -->
                    <?php else :?>

                          <!-- Nothing inside -->

                    <?php endif;?><!-- .article_image -->

                  <header class="news-item-data">
                      <h2 itemprop="headline" class="entry-title"><?php the_title(); ?></h2>
                    <?php get_template_part( 'types/content', 'meta' ); ?><!-- .entry-meta -->
                  </header>
               </a>
          </article>
    <?php endif; ?>
          <?php   endwhile; wp_reset_postdata(); ?>
          </div>
  </section>
1
  • There is no faster way to do those queries. Not while still using WP_Query. Those are pretty well optimal for the described case. If you need more speed, look into using persistent object caching.
    – Otto
    May 1, 2020 at 2:11

1 Answer 1

4

Two bits of advice:

  1. Most importantly, database query performance hinges on how many rows match the query, not how many rows you want. Even if you're only asking for 5 posts, the database could have to query and sort a million results in order to give you those 5. Say I gave you a 100,000 index cards, each with a different random number on it, and I asked you to pull out the 5 biggest numbers. I may only want 5, but you still have to look at all 100,000 in order to figure out which 5 those are. Bottom line, you need to get the result set down, and often times the easiest way to do that in this scenario is to add a date query to the WP_Query arguments. If you only want the 7 or 5 most recent posts, and you know that they will always be from the last month, add a date query restricting the query to the last month: 'date_query' => [ [ 'after' => '-30 days' ] ],. Go even more recent if you can, or pull it back to a wider range if you must. You'll be shocked at how much this can help! I gave a WordCamp talk that was pretty heavy on this topic, if you're interested.
  2. Less important, but still a best practice, NOT IN() queries are not optimal. When possible, it's preferable to query for additional posts and then remove them using PHP. In this case, you'd query for 12 posts in your second query, then use something like PHP's array_filter() to exclude the 7 you don't want duplicated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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