A reader writes in:
I’m developing a new theme and I’m having trouble getting duplicate posts from showing when running two loops (one standard loop and one from a specific category). Even when I copied the specific code from directly from the codex, it was not working.
The Codex article the reader mentioned was regarding the Loop. Although the example shows how to avoid a single duplicate post, it doesn’t show how to avoid duplicating multiple posts.
Here’s how to show two individual loops without duplicating posts in either loop.
Step 1: Add a ‘posts_where’ Function
A WordPress filter is needed to accomplish this, and we’re going to be tapping into the ‘posts_where‘ filter.
The reason being is we need to modify the query used for the loop and exclude some posts.
Here’s the function we’ll be using called post_strip:
function post_strip($where) { global $myPosts, $wpdb; $where .= " AND $wpdb->posts.ID not in($myPosts) "; return $where; }
In the above code, I use a global variable called $myPosts, which is comma-separated string of post IDs to exclude.
Step 2: Start the First Loop
Within this first loop we’ll be keeping track of the post IDs being used. Nothing fancy is being done here. We’re just pulling the last five posts posted.
<?php global $myPosts; $myPosts = ''; ?> <div> <?php $my_query = new WP_Query(); $my_query->query('showposts=5'); if ($my_query->have_posts()) : while ($my_query->have_posts()) : $my_query->the_post(); ?> <?php $myPosts .= $post->ID . ","; ?> <div><?php the_title(); ?></div> <!-- Post Stuff --> <?php endwhile; endif; ?> </div>
Pay special attention to the $myPosts variable, which is used to keep track of all of the post IDs.
Step 3: Add the Filter
We’ll now need to add a posts_where filter for the second loop. This filter will use the post_strip function we started in Step 1.
<?php add_filter('posts_where', 'post_strip'); ?>
Step 4: Start the Second Loop
The second loop is a repeat of the first loop to demonstrate that the posts are not being duplicated. The second loop uses a different loop technique since paging isn’t necessary.
<div> <?php $my_query = new WP_Query('showposts=5'); while ($my_query->have_posts()) : $my_query->the_post();?> <div><?php the_title(); ?></div> <!-- Post Stuff --> <?php endwhile; ?> </div>
Step 5: Remove the Filter
The filter we added in Step 3 now needs to be removed.
<?php remove_filter('posts_where', 'post_strip'); ?>
Step 6: Admire the Results
Before – Duplicates Being Shown
After – Duplicates Removed
Downloadable Code
Here is a sample index.php for download.
Ronald, another enlightening post. Your knowledge of the loop is astounding. Maybe YOU should right the Codex 🙂 Thanks for the great tutorial
Something to think about further. Thanx.
I’ve tried posting code a couple of times just now, and i keep getting some kind of spam error, so i’ll put the code in a pastebin.
Basically I think there is a quicker and easier way of doing this, by storing the ids in an array and then searching that array in the second loop.
@Epic Alex
Just glancing over your code it looks to me like if your second loop encounters duplicates then it will end up not showing the correct number of posts. Your code is removing the duplicate posts after five have been selected from the database. If two of those are duplicates, only the remaining three will be shown. If all five are duplicates, no posts will be shown!
Do correct me if I’m wrong as I haven’t tested your code.
@Epic,
Yes, that is an easier way of doing it, but say you want to display five posts. If there are two duplicates, then only three would be shown.
@Johnbillion,
You hit the nail on the head. That’s why I decided to modify the original query, which would return the correct number of posts without the duplicates.
@All,
As Epic pointed out, posting code here is problematic. I suggest using Pastebin and posting the link here. Thanks.
Sorry about the posting code issue. Pastebin is the best option.
Very helpful post for every wordpress coder.
Thank you so much Ronald for this post – it has helped me greatly. I have come across a new problem however. When I click the “Previous Posts” link, it displays an error (see below) and then proceeds to display all my posts, including those already displayed. If I keep clicking “Previous Posts” it will even display posts not yet published, but in Draft mode, and also all my pages (Contact, About).
The error I get:
Warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, ‘post_strip’ was given in /../wp-includes/plugin.php on line 163
I am using WordPress 2.5
Also, my setup is a little different than your example loop. I display the last article from one author in one loop and save the ID. Then I have another loop that displays the last post from the other author, and it makes the variable = variable + new ID. Then I run the generic loop to display the last 5 posts excluding the two that have already been displayed. This is to feature the last post from each author at the top. Just slightly different from your example. It works fine except for the navigation.
TIA for any help.
Just to clarify. I had incorrectly placed the code to remove the filter. Now that I have corrected that the problem is slightly different. When I click the “Previous Post” link, it still displays the error, and the chronologically lists the 5 last posts (not 6-10, but 1-5 from the first page). No “Previous Posts” link appears at the bottom of this 2nd page. In effect, it displays the first page all over again without the exclusions and then fails to display the navigation.
Ronald emailed me and helped me out. See this article for help.
Nice tutorial. How would you get three loops to work. Basically, in this order: Feature loop (1 post), Standard Loop (1 posts), Specific Category Loop (5 posts). I’m trying not to repeat content between the three loops. I have the Feature Loop and Standard loop working, I’m just not getting the third (Specific Category) loop to function. Thanks.
My question is:
Can I extend this to more than two loops and for a single category posts(displayed in 3 different blocks)?
Any answer plz?
Hi, great post.
How I should do it, if I want to filter by Title, not by ID.
Thanks