Have you experienced duplicate posts appearing on your WordPress blog? By duplicate posts, I mean – posts repeating again-and-again in the post index. Basically, duplicate posts in WordPress appear due to the use of multiple loops in the WordPress themes.

A WordPress loop is responsible to display each of your posts, whether it’s the index of posts on your WordPress home page, category page, tag page, or it’s a single post. Read more about the loop at WordPress Codex, and that’s the same place where you’ll get the solution to avoid Duplicate posts in WordPress loop. I just have implemented that solution on this blog and am sharing my experience right here, hope it helps you to explore the problem and the solution a bit more.

I was using multiple loops in the main index template (index.php) of the blog to display posts from different categories. Below given is an overview of code I was using in my template:

<?php if(have_posts()) :
  // Loop#1
  $rp_query = new WP_Query('posts_per_page=4');
  while ($rp_query->have_posts()) :
    $rp_query->the_post(); ?>
    <h1><a href="<?php the_permalink(); ?> title="<?php the_title(); ?>"><?php the_title(); ?></a></h1>
    <?php the_excerpt();
  endwhile;
  // Loop#2 for category ID 23
  $sm_query = new WP_Query(array(
    'cat'  =>  23,
    'posts_per_page'  =>  3
  ));
  while ($sm_query->have_posts()) :
    $sm_query->the_post(); ?>
    <h1><a href="<?php the_permalink(); ?> title="<?php the_title(); ?>"><?php the_title(); ?></a></h1>
    <?php the_excerpt();
... ... ...
  endwhile;
endif; ?>

The first loop I’m using in the template displays 4 recent posts regardless of the category and the second loop pops posts from the category with ID 3 (that I specified in the query). The problem with the above code is: if I publish a post in category with ID 3, it will be shown two times, in the recent posts loop (Loop#1) and the loop for category ID 3 (Loop#2).

So, how to get rid of such a repetition of posts with multiple loops in WordPress? See the highlighted code in the below snippet which is an updated version of the above one:

<?php if(have_posts()) :
  // Loop#1
  $rp_query = new WP_Query('posts_per_page=4');
  while ($rp_query->have_posts()) :
    $rp_query->the_post(); ?>
    $dnd[] = $post->ID;
    <h1><a href="<?php the_permalink(); ?> title="<?php the_title(); ?>"><?php the_title(); ?></a></h1>
    <?php the_excerpt();
  endwhile;
  // Loop#2 for category ID 23
  $sm_query = new WP_Query(array(
      'cat'  =>  23,
      'post__not_in'  =>  $dnd,
      'posts_per_page  =>  3
  ));
  while ($sm_query->have_posts()) :
    $sm_query->the_post(); ?>
    <h1><a href="<?php the_permalink(); ?> title="<?php the_title(); ?>"><?php the_title(); ?></a></h1>
    <?php the_excerpt();
  endwhile;
... ... ...
endif; ?>

What we’ve done exactly: Collected the main loop’s post IDs in and array $dnd and told our next loop not to display the posts with any of the IDs stored in $dnd by making use of post__not_in handle in WP_Query.

Similarly, we can also tell our other loops to not to output the posts with the IDs stored in $dnd. Hope you find this useful.