I am developing the online web shop, and making the product list, the following code are related:
<?php 
global $hkdNBF;
$categories = $this->category_model->get_categories('');

// Your full products array:
$all_products = $products['product']; 

// Chunk size (number of products per batch):
$batch_size = 6;

// Chunk products into batches:
$product_batches = array_chunk($all_products, $batch_size);

// Encode batches as JSON for JS:
$product_batches_json = json_encode($product_batches);

?>
<!-- ========================= Breadcrumb Start =============================== -->
<div class="breadcrumb mb-0 py-26 bg-main-two-50">
    <div class="container container-lg">
        <div class="breadcrumb-wrapper flex-between flex-wrap gap-16">
            <h6 class="mb-0">產品列表</h6>
            <ul class="flex-align gap-8 flex-wrap">
                <li class="text-sm">
                    <a href="<?=base_url()?>" class="text-gray-900 flex-align gap-8 hover-text-main-600">
                        <i class="ph ph-house"></i>
                        主頁
                    </a>
                </li>
                <li class="flex-align">
                    <i class="ph ph-caret-right"></i>
                </li>
                <li class="text-sm text-main-600">產品列表</li>
            </ul>
        </div>
    </div>
</div>
<!-- ========================= Breadcrumb End =============================== -->

<section class="shop py-80">
    <div class="container container-lg">
        <div class="row">
            <!-- Sidebar Start -->
            <div class="col-lg-3">
                <div class="shop-sidebar">
                    <?php if (isset($categories)) { ?>
                        <div class="shop-sidebar__box border border-gray-100 rounded-8 p-32 mb-32">
                            <h6 class="text-xl border-bottom border-gray-100 pb-12">產品分類</h6>
                            <div id="product-page-cat-filter" class="responsive-dropdown style-two common-dropdown nav-submenu p-0 submenus-submenu-wrapper shadow-none border border-gray-100 position-relative border-top-0" style="border: 0px !important;width:100%;height:100%;">
                                <ul class="responsive-dropdown__list scroll-sm overflow-y-auto" style="margin-top: 12px !important;">
                                    <?php $_cnt = 0; foreach($categories as $cat) { ?>
                                        <li class="has-submenus-submenu">
                                            <a href="javascript:void(0)" class="text-gray-500 text-15 py-12 px-16 flex-align gap-8 rounded-0" style="color: black !important;">
                                                <span><?=$cat['name']?></span>
                                                <span class="icon text-md d-flex ms-auto"></span>
                                            </a>
                                            <div class="submenus-submenu py-16" style="top:<?=$_cnt*48?>px !important">
                                                <h6 class="text-lg px-16 submenus-submenu__title"><?=$cat['name']?></h6>
                                                <ul class="submenus-submenu__list overflow-y-auto scroll-sm">
                                                    <?php foreach($cat['children'] as $subCat) { ?>
                                                        <li>
                                                            <a href="<?=base_url("products/category/".$subCat['slug'])?>"><?=$subCat['name']?></a>
                                                        </li>
                                                    <?php } ?>
                                                </ul>
                                            </div>
                                        </li>
                                    <?php $_cnt++; } ?>
                                </ul>
                            </div>
                        </div>
                    <?php } ?>

                    <!-- Brand Filter -->
                    <div class="shop-sidebar__box border border-gray-100 rounded-8 p-32 mb-32">
                        <h6 class="text-xl border-bottom border-gray-100 pb-24 mb-24">品牌</h6>
                        <ul class="max-h-540 overflow-y-auto scroll-sm">
                            <li class="mb-24">
                                <div class="form-check common-check common-radio">
                                    <input class="form-check-input" type="radio" name="brand" id="brand1">
                                    <label class="form-check-label" for="brand1">Apple</label>
                                </div>
                            </li>
                            <li class="mb-24">
                                <div class="form-check common-check common-radio">
                                    <input class="form-check-input" type="radio" name="brand" id="brand2">
                                    <label class="form-check-label" for="brand2">Samsung</label>
                                </div>
                            </li>
                            <li class="mb-24">
                                <div class="form-check common-check common-radio">
                                    <input class="form-check-input" type="radio" name="brand" id="brand3">
                                    <label class="form-check-label" for="brand3">Microsoft</label>
                                </div>
                            </li>
                            <li class="mb-24">
                                <div class="form-check common-check common-radio">
                                    <input class="form-check-input" type="radio" name="brand" id="brand4">
                                    <label class="form-check-label" for="brand4">HP</label>
                                </div>
                            </li>
                            <li class="mb-0">
                                <div class="form-check common-check common-radio">
                                    <input class="form-check-input" type="radio" name="brand" id="DELL">
                                    <label class="form-check-label" for="DELL">DELL</label>
                                </div>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
            <!-- Sidebar End -->

            <!-- Content Start -->
            <div class="col-lg-9">
                <div class="flex-between gap-16 flex-wrap mb-40 ">
                    <div class="position-relative flex-align gap-16 flex-wrap">
                        <div class="list-grid-btns flex-align gap-16">
                            <button type="button" class="w-44 h-44 flex-center border border-gray-100 rounded-6 text-2xl list-btn">
                                <i class="ph-bold ph-list-dashes"></i>
                            </button>
                            <button type="button" class="w-44 h-44 flex-center border border-main-600 text-white bg-main-600 rounded-6 text-2xl grid-btn">
                                <i class="ph ph-squares-four"></i>
                            </button>
                        </div>  
                        <div class="position-relative text-gray-500 flex-align gap-4 text-14">
                            <label for="product_sort_by" class="text-inherit flex-shrink-0">排序方式: </label>
                            <select class="form-control common-input px-14 py-14 text-inherit rounded-6 w-auto" id="product_sort_by">
                                <option value="" selected>預設排序</option>
                                <option value="top-rated" <?= ($this->input->get('sort') == "top-rated") ? 'selected' : '' ?>>最熱門</option>
                                <option value="date-desc" <?= ($this->input->get('sort') == "date-desc") ? 'selected' : '' ?>>最新</option>
                                <option value="price-asc" <?= ($this->input->get('sort') == "price-asc") ? 'selected' : '' ?>>價格: 低至高</option>
                                <option value="price-desc" <?= ($this->input->get('sort') == "price-desc") ? 'selected' : '' ?>>價格: 高至低</option>
                            </select>
                        </div>
                        <button type="button" class="w-44 h-44 d-lg-none d-flex flex-center border border-gray-100 rounded-6 text-2xl sidebar-btn"><i class="ph-bold ph-funnel"></i></button>
                    </div>

                </div>

                <!-- Product List Container -->
                <div class="row" id="product-list">
                    <!-- Products will be loaded here by JS -->
                </div>

                <div id="loading" class="text-center py-3" style="display:none;">加載更多商品...</div>
            </div>
            <!-- Content End -->
        </div>
    </div>
</section>


<script>
const productBatches = <?= $product_batches_json ?>;
const batchSize = <?= $batch_size ?>;
let currentBatchIndex = 0;

const productListElem = document.getElementById('product-list');
const loadingElem = document.getElementById('loading');

function escapeHtml(text) {
    const map = {'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;'};
    return (text || '').toString().replace(/[&<>"']/g, m => map[m]);
}

function formatCurrency(value) {
    // Use your global currency formatter as desired
    // Here simple HKD display as fallback:
    return 'HKD ' + Number(value).toFixed(2);
}

function buildProductHTML(row) {
    if (!row || !row.variants || row.variants.length == 0) return '';

    let variant_price = (row.variants[0].special_price > 0 && row.variants[0].special_price !== '') ? row.variants[0].special_price : row.variants[0].price;
    let original_price = row.variants[0].price;
    let special_price = row.variants[0].special_price;

    let name = escapeHtml(row.name);
    let slug = escapeHtml(row.slug);
    let image_sm = escapeHtml(row.image_sm);
    let category_name = escapeHtml(row.category_name);
    let store_name = escapeHtml(row.store_name);
    let seller_slug = escapeHtml(row.seller_slug);

    // Tags HTML:
    let tags_html = '';
    if (row.tags && Array.isArray(row.tags)) {
        tags_html = row.tags.map(tag => `<span class="py-2 px-8 text-xs rounded-pill text-main-two-600 bg-main-two-50"><a href="<?=base_url("products/tags/")?>${encodeURIComponent(tag)}">${escapeHtml(tag)}</a></span>`).join(' ');
    }

    return `
    <div class="col-6 col-md-3 col-lg-2 product-grid mb-30">
        <div class="product-card h-100 rounded-16 position-relative transition-2" style="padding:0 !important;">
            <div class="product-card__thumb rounded-8 position-relative">
                <a href="<?=base_url()?>products/details/${slug}" class="w-100 h-100 flex-center">
                    <img src="${image_sm}" alt="${name}" class="w-auto rounded-8">
                </a>
                <div class="expand-btn-container bg-white p-2 rounded-pill z-1 position-absolute inset-inline-end-0 inset-block-start-0 me-16 mt-16 shadow-sm">
                    <button type="button" class="expand-btn w-40 h-40 text-md d-flex justify-content-center align-items-center rounded-circle hover-bg-main-two-600 hover-text-white">
                        <i class="ph ph-plus"></i>
                    </button>
                    <div class="expand-icons gap-20 my-20">
                        <button type="button" class="text-neutral-600 text-xl flex-center hover-text-main-two-600 wishlist-btn">
                            <i class="ph ph-heart"></i>
                        </button>
                        <button type="button" class="text-neutral-600 text-xl flex-center hover-text-main-two-600">
                            <i class="ph ph-eye"></i>
                        </button>
                        <button type="button" class="text-neutral-600 text-xl flex-center hover-text-main-two-600">
                            <i class="ph ph-shuffle"></i>
                        </button>
                    </div>
                </div>
            </div>
            <div class="product-card__content w-100 pt-3">
                <div class="product-card-tags">
                    ${tags_html}
                </div>
                <h6 class="title text-lg fw-semibold" style="margin-bottom:0;">
                    <a href="<?=base_url()?>products/details/${slug}" class="link text-line-2" tabindex="0">${name}</a>
                </h6>
                <span class="py-2 px-8 text-xs rounded-pill text-main-two-600 bg-main-two-50 mt-4 d-inline-block">
                    <a href="<?=base_url()?>products/category/${encodeURIComponent(category_name)}">${category_name}</a>
                </span>
                <span class="py-2 px-8 text-xs rounded-pill text-main-two-600 bg-main-two-50 mt-4 d-inline-block">
                    <a href="<?=base_url()?>sellers/seller_details/${seller_slug}">由${store_name}提供</a>
                </span>
                <div class="product-card__price mt-4 mb-4">
                    ${special_price && special_price > 0 && special_price != original_price ? `<span class="text-gray-400 text-md fw-semibold text-decoration-line-through">${formatCurrency(original_price)}</span>` : ''}
                    <span class="text-heading text-md fw-semibold">${formatCurrency(variant_price)}</span>
                </div>
            </div>
        </div>
    </div>
    `;
}

function renderBatch(index) {
    if (index >= productBatches.length) {
        currentBatchIndex = 0; // Loop back to first batch
        index = 0;
    }
    const batch = productBatches[index];
    let html = '';
    batch.forEach(item => {
        html += buildProductHTML(item);
    });
    productListElem.insertAdjacentHTML('beforeend', html);

    // Optional: limit max products chunks to avoid too many nodes for performance
    const maxBatchesInDOM = 5; // e.g. max 5 batches ~ 30 products
    if(productListElem.children.length > maxBatchesInDOM * batchSize) {
        // Remove oldest batch:
        for(let i = 0; i < batchSize; i++) {
            if(productListElem.firstChild) productListElem.removeChild(productListElem.firstChild);
        }
    }
}

function onScroll() {
    if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 400) {
        currentBatchIndex++;
        renderBatch(currentBatchIndex);
    }
}

// Initial load first batch:
renderBatch(currentBatchIndex);

window.addEventListener('scroll', onScroll);
</script>

CSS:
/* ============================= Product Card Css Start ========================== */
.product-card {
    display: flex;
    flex-direction: column;
    /*justify-content: space-between;*/
    align-items: start;
}

.product-card:hover .product-card__thumb img {
    transform: scale(1.05);
}

.product-card__cart{
    position: absolute;
    bottom: 0px;
    left: 0px;
    width: 100%;
}

@media screen and (max-width: 1499px) {
    .product-card__cart {
        font-size: 12px;
        padding: 9px 12px !important;
    }
}

.product-card__badge {
    border-radius: 16px 0 16px 0;
}

.product-card__thumb {
    /*height: 232px;*/
    width: 100%;
    transition: 0s !important;
}

.product-card__thumb img {
    max-width: 160px;
    width: 100%;
    transition: 0.2s linear;
}

.product-card.style-two {
    flex-direction: row;
}

.product-card.style-two .product-card__thumb {
    width: 260px;
    height: 190px;
}

.list-grid-wrapper:not(.list-view) > .product-card{
    max-width: 270px !important;
}

@media screen and (max-width: 991px) {
    .product-card.style-two .product-card__thumb {
        width: 190px;
    }
}

@media screen and (max-width: 575px) {
    .product-card.style-two .product-card__thumb {
        width: 124px;
    }
    .list-grid-wrapper:not(.list-view) > .product-card{
        max-width: 100% !important;
        width: 100% !important;
    }
}

@media screen and (max-width: 1199px) {
    .product-card__thumb {
        min-height: 160px;
    }

    .product-card__thumb img {
        max-width: 120px;
    }

    .product-card__content .product-card__price span {
        font-size: 0.75rem !important;
    }

    .product-card__content .title .link {
        font-size: 0.875rem;
    }

    .product-card__content .text-xs {
        font-size: 0.625rem !important;
    }
}
/* ============================= Product Card Css End ========================== */

And the current layout is look like the image: https://i.ibb.co/YTfyPFJ4/image.png

Please view the code and the image in link, and then solve the following problem:
The product name will be over the tags below the name (e.g. the fourth grid)
The first row tags and the second tags should be set within one row, if the length exceed one row, add the + sign at the end for view more by hover (PC) or Click (Mobile)