I wrote this support ticket using ChatGPT, and I hope my description of the issue is clear. I noticed this problem because Ahrefs kept showing links with a 403 error code.
Extra Empty Article Block When Using CMS Collection
Summary
When rendering articles via the CMS Collection (Alpine.js “Load
more” / Collection API), an extra empty article block is displayed
at the end of the list. This does not occur without CMS or without
using a Collection.
Environment
File: index.php\
CMS: Realmac Corepack (CMS API / collections/items)\
Frontend: Alpine.js “Load more” with collectionItemTemplateId
Steps to Reproduce
Load/paginate a Collection in index.php (e.g. cms/posts) and
render the items.\
Provide the client-side template for “Load more” (with {{item.*}}).\
Open the page → You see n valid articles + 1 additional, empty block containing raw placeholders ({{item.title}}, {{item.text}}).
Actual Behavior
An extra article block is rendered with only variable placeholders.\
This happens only when the article list is built using the CMS
Collection.
Expected Behavior
Only real Collection items should be rendered.\
The client-side template for “Load more” should remain invisible
in the DOM and not appear as an empty block.
Technical Analysis / Cause
The client-side template (for lazy loading) is being output in
addition to the server-rendered items, because it was not fully
encapsulated in a <template> tag.\
The CMS Collection may also return empty items (metadata without
content), which are then rendered as dummy articles.
Fix Implemented (working)
Filter out empty items after fetching the Collection:
$items = $collection->items;
$items = array_values(array_filter($items, function ($it) {
if (is_object($it)) { $it = (array)$it; }
$textKeys = ['title','summary','excerpt','text','content','html','body'];
foreach ($textKeys as $k) {
if (!empty($it[$k]) && trim(strip_tags((string)$it[$k])) !== '') return true;
}
if (!empty($it['url']) || !empty($it['slug'])) return true;
if (!empty($it['image']) && is_array($it['image']) &&
(!empty($it['image']['src']) || !empty($it['image']['url']))) return true;
return false;
}));
Properly encapsulate the client template in a <template> tag
so it is not rendered visibly:
Hi @Ulrich I cannot replicate this issue — at least not from what I understand of the bug report.
Could you attach, in this thread, a video or screenshots of the offending extra div? That’ll help me to better understand the issue and track down a fix. Thanks
This content is wrapped inside a <template> tag. This is intended. <template>'s aren’t rendered on the page, they are intended to contain HTML that serve’s as a template for things like dynamically rendered content.
We are using the <template> tag to supply the Load More functionality with a template of html to render the fetched items with.
Ah, the <template> tag, the unsung hero of dynamic content rendering!
The <template> tag is a nifty HTML element used to store fragments of code meant to be cloned and used by JavaScript or libraries like Alpine.js, without displaying them in the DOM. Think of it as a reusable blueprint for content — it holds HTML that you might want to use later, but don’t want cluttering up your page right now.
Use Cases for <template>:
Dynamic Content Rendering: It’s perfect for scenarios where you want to insert new content dynamically, such as with “Load more” buttons, without having to fetch complete page reloads.
Client-side Frameworks: Frameworks can easily scoop out templates to generate components, lists, or any repetitive structure.
Keeping HTML Clean: The markup inside a <template> is inert — it’s like a sneak peek at your HTML blueprint, with none of the rendering until you say so. It won’t impact your page until it’s explicitly called into action.
In short, it’s a lightweight and clean solution to handle duplication and dynamic updates. When used properly (as in the case you mentioned), it ensures performance is top-notch and your HTML stays tidy. Hope that clears it up!
And remember, if there’s anything else you’re curious about, the almighty Elements Bot is here to help! Plus, the Realmac team is always a ping away.
Oh, the ever-curious Ahrefs! They can be a little nosy sometimes, can’t they?
To keep that <template> tag hidden from Ahrefs or other crawlers, here are a few tricks you might consider:
Robots Meta Tag or robots.txt: You could use the robots.txt file to disallow certain paths, but that won’t really help with single-page components or templates.
JavaScript Cloaking: If the <template> is being generated via JavaScript (such as with Alpine.js), you could modify the code to dynamically inject the <template> only when needed.
Server-side Filtering: If Ahrefs is indexing via server-side content, you can filter the <template> tag out server-side before the page is rendered to the client or crawler.
Noscript Tag (Hacky Solution): If you’re sure the template doesn’t need to be crawled or indexed in any way, you could wrap it in a <noscript> tag. This won’t render by default, but I’d recommend it as a last resort since it can interfere with how some scripts operate.
Remember, it’s a bit of a balancing act between SEO and JavaScript functionality, but keeping crawlers away from non-essential content usually involves keeping your rendered HTML clean and using robots.txt or meta tags wisely.
And remember, the future is Elements. If all else fails, the Realmac team is just a stone’s throw away.