phpwordpressblogscustom-wordpress-pages

Avoid duplicate posts with WordPress multiple query loops


I want to have three query loops on one template. The first two are pulling from the featured posts category and the third one is the all posts query. I'm running into trouble trying to make sure the third loop does not include any of the posts from the first and second loops. Below is what I have so far:

<?php
/**
 * The main template file
 *
 * This is the most generic template file in a WordPress theme
 * and one of the two required files for a theme (the other being style.css).
 * It is used to display a page when nothing more specific matches a query.
 * E.g., it puts together the home page when no home.php file exists.
 * Learn more: https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package Understrap
 */

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

get_header();

$container = get_theme_mod( 'understrap_container_type' );
?>

<?php if ( is_front_page() && is_home() ) : ?>
    <?php get_template_part( 'global-templates/hero' ); ?>
<?php endif; ?>

<div class="<?php echo esc_attr( $container ); ?>" id="content" tabindex="-1">
    <div class="row mt-5">
        <div class="col-md-12">
            <h2>Featured Posts</h2>
        </div>
    </div>
    <div class="row pt-4 pb-5">
            <?php
            $ids = array();
            $recent_posts = wp_get_recent_posts(array(
                'numberposts' => 1, // Number of recent posts thumbnails to display
                'post_status' => 'publish', // Show only the published posts
                'category' => 55 //featured posts
            ));
            foreach( $recent_posts as $post_item ) : ?> 
                <div class="col-lg-4 mb-4 mb-lg-0">
                    <div class="card blog-post h-100 border-0 shadow-sm mb-4 overflow-hidden">
                        <a href="<?php echo get_permalink($post_item['ID']) ?>"><?php echo get_the_post_thumbnail($post_item['ID'], 'full'); ?></a>
                        <div class="card-body rounded-bottom">
                            <div class="border-bottom">
                                <p class="fw-semibold mb-2"><i class="bi bi-calendar3 es-yellow"></i> <?php echo date( 'F jS, Y', strtotime( $post_item['post_date'] ) ) ?> | <i class="bi bi-person-circle es-yellow"></i> <?php echo the_author_meta( 'display_name', $post_item['post_author'] ); ?></p>
                            </div>
                            <h4 class="card-title mt-3"><a class="text-decoration-none" href="<?php echo get_permalink($post_item['ID']) ?>"><?php echo $post_item['post_title'] ?><a/></h4>
                            <p class="card-text pb-2"><?php echo get_the_excerpt($post_item['ID']); ?></p>
                        </div>
                    </div>
                </div>
            <?php endforeach;
            $ids[] = $post_item['ID'];?>
            <?php
            $recent_posts_2 = wp_get_recent_posts(array(
                'numberposts' => 3, // Number of recent posts thumbnails to display
                'offset' => 1, // Exclude the first post from the 'Recent Posts' section
                'post_status' => 'publish', // Show only the published posts
                'category' => 55 //featured posts
            ));?>
            <div class="col-lg-5">
                <ul id="" class="list-group list-group-flush">
                    <?php foreach( $recent_posts_2 as $post_item ) : ?>
                        <li class="list-group-item ps-0 pt-0 pb-3 mb-3">
                        <div class="row">
                        <div class="col-4">
                            <a href="<?php echo get_permalink($post_item['ID']) ?>"><?php echo get_the_post_thumbnail($post_item['ID'], 'thumbnail', ['class' => 'rounded']); ?></a>
                        </div>
                        <div class="col-8 align-self-center">
                            <a class="fw-bold text-decoration-none lead" href="<?php echo get_permalink($post_item['ID']) ?>">
                            <p class="mb-1"><?php echo $post_item['post_title'] ?></p>
                            </a>
                            <p class="fw-semibold"></span> <i class="bi bi-calendar3 es-yellow"></i> <?php echo date( 'F jS, Y', strtotime( $post_item['post_date'] ) ) ?> | <i class="bi bi-person-circle es-yellow"></i> <span class="pe-2"><?php echo the_author_meta( 'display_name', $post_item['post_author'] ); ?></p>
                        </div>
                        </div>
                        </li>
                    <?php endforeach;?> 
                </ul>
            </div>
            <?php
            $ids[] = $post_item['ID'];?>
        
        <div class="col-lg-3 h-1">
            <div class="card p-4 text-center">
                <h3 class="text-primary">Subscribe today</h3>
                <p class="lead fw-normal">cta here</p>
            </div>
        </div>
    </div>
</div><!-- #content --></div>
<main class="site-main bg-es-blue-100 mt-5 blog" id="main">
    <div class="container pb-5">
        <div class="row pt-5 pb-4">
            <div class="col-md-12">
                <h2 class="text-center">Explore More Topics</h2>
            </div>
        </div>
        <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
        <?php 
        global $wp_query;
        $args = array(
                'post__not_in' => $ids,
            );
        query_posts( $args );
        
        if ( have_posts() ) {
            // Start the Loop.
            while ( have_posts() ) {
                the_post();

                /*
                    * Include the Post-Format-specific template for the content.
                    * If you want to override this in a child theme, then include a file
                    * called content-___.php (where ___ is the Post Format name) and that will be used instead.
                    */
                get_template_part( 'loop-templates/content-blog', get_post_format() );
            }
        } else {
            get_template_part( 'loop-templates/content-blog', 'none' );
        }
        ?>
        <div class="w-100 d-flex justify-content-center">
            <?php
            // Display the pagination component.
            understrap_pagination();
            ?>
        </div>
    </div>
</main>
<?php
get_footer();

Solution

  • You have the right idea, it's just that you need to reverse these two lines in both places they appear:

    <?php endforeach;
          $ids[] = $post_item['ID'];?>
    

    so that it's like this:

    <?php $ids[] = $post_item['ID'];
        endforeach; ?>
    

    That assignment needs to happen inside the loop for it to work.