Build the collection page
The page of each collection in your store. Covers the page URL, the collection details, and the two ways to list its products, cards rendered by Astro or search & discovery.
A collection page is src/pages/collections/[slug].astro: one page for each entry of the collections content collection. The collection’s name, description and image come from the entry. The products can come from two places: the entry’s own products, rendered by Astro as product cards, or search & discovery, which loads them live from Shopify with filters and sorting. This guide covers both and helps you choose.
Note
Before you start, Smootify must be installed on the site (Install Smootify in Astro) and your products and collections loaded as content collections: see Content from Shopify. Each product’s collections field references its collections, and each collection has its shopifyId field.
How it fits together
What Smootify needs:
- one product card per product: a
smootify-productelement with the product’s id; - for search & discovery, a
smootify-search-discoveryelement that knows the collection.
What is up to you:
- the layout of the page, the collection header, the card design, the classes and the styles;
- which way you list the products. You can also start with cards rendered by Astro and move to search & discovery later: the card design stays the same.
The two ways side by side:
| Cards rendered by Astro | Search & discovery | |
|---|---|---|
| Products come from | the content collection, at build | Shopify, live |
| Filters and sorting | none | chosen by the visitor |
| Order | the collection’s order in Shopify, as loaded | the collection’s order in Shopify, until the visitor picks a sort |
| A new product | shows after the next build | shows without a build |
| Needs | nothing more | the Search & discovery add-on |
1. The template page and its URL
Create src/pages/collections/[slug].astro with a getStaticPaths that maps the collections content collection to { params: { slug: entry.id }, props: { entry } }. The entry’s id is the Shopify handle, so each page is at /collections/ followed by the handle, such as /collections/summer: the same address as in Shopify.
Smootify builds links to collection pages, for example with product="collections" on a product card. It expects them under /collections/. For another route, name the page folder after it, such as src/pages/categories/[slug].astro, and set collectionsBase to that name in the userOptions of the integration in astro.config.mjs: see the Smootify options.
2. The collection details
The header of the page is plain HTML. Write the entry’s name in a heading, its description (HTML) with set:html, and its image and imageAlt in an <img>. For the title and the meta description, give the entry to <Seo type="collection" entry={c} />: it uses seoTitle and seoDescription, and falls back to the name and the description. See Content from Shopify.
Smootify adds nothing here: these fields change when the content is loaded again, at the next build.
3. List the products with Astro
- Read the products of the collection in the frontmatter of the page:
(await getEntries(c.products)).filter(Boolean). Theproductsfield needs the loader optionwithProducts: true: see Content from Shopify. - Wrap each product in an element with the class
sm-dyn-item, the boundary of the card, and inside it add asmootify-productwithdata-idset to the product’sshopifyId. - Design the card inside
smootify-product: see Product cards.
---
const c = entry.data;
const products = (await getEntries(c.products)).filter(Boolean);
---
{products.map((p) => (
<div class="sm-dyn-item">
<smootify-product data-id={p.data.shopifyId}>
<a product="url" href={`/products/${p.id}/`}>{p.data.name}</a>
<smootify-price><div data-prop="price">{p.data.priceFormatted}</div></smootify-price>
</smootify-product>
</div>
))}The link and the name are in the HTML before Smootify loads, so search engines read them. Smootify then writes the same values from Shopify.
The list shows what the content collection holds, in the order of the collection in Shopify. Slice it to set a limit, such as products.slice(0, 24). A product added to the collection in Shopify appears after the next build. Price, stock and the add-to-cart form inside each card are always live, because Smootify loads them from Shopify.
4. Or list them with search & discovery
Use search & discovery when the page needs filters or sorting chosen by the visitor, when the collection is large, or when the products must follow the order set in Shopify.
- Add a
smootify-search-discoveryelement to the page. - Give it
data-collectionwith the collection’s Shopify ID:c.shopifyId, the numeric ID or the full ID, never the handle. - Inside it, render the real product cards as in step 3: an
sm-dyn-itemwith asmootify-productfor each of the first products. Render only as many cards aslimit.
---
const limit = 24;
---
<smootify-search-discovery data-collection={c.shopifyId} limit={limit}>
<div filter="count">{products.length}</div>
<div>
{products.slice(0, limit).map((p) => (
<div class="sm-dyn-item">
<smootify-product data-id={p.data.shopifyId}>
<a product="url" href={`/products/${p.id}/`}>{p.data.name}</a>
<smootify-price><div data-prop="price">{p.data.priceFormatted}</div></smootify-price>
</smootify-product>
</div>
))}
</div>
<button type="button" data-action="load">Load more</button>
</smootify-search-discovery>The count and the load more button above are optional. Smootify takes the first .sm-dyn-item as the card template, and rewrites the whole list from its results. The server cards stay as they are until the first results, so search engines see real products and the page keeps its height while it loads. When the results are the same products in the same order, as the first page served from the seed is, Smootify keeps the drawn cards: nothing flashes on the first load. Otherwise it replaces the list in one step. No placeholder card is needed. Every card is a copy of the first one, so give each element a Smootify attribute such as product="title", not only a value from the entry.
The first page of results comes from the page’s seed, with no request to Shopify, when the cards match it: the same limit on the element and in the code that picks the cards, the collection’s own order with no sort of your own, and the same unavailable-products as the element. See First load.
With data-collection:
- the products come in the order the collection has in Shopify, until the visitor picks a sort;
- the collection is locked: the reset button keeps it, and it stays out of the page address;
- the text search (
filter-search) looks inside the collection. For an exact search on a large collection, tag its products and adddata-tag: see Search inside a collection.
Filters, sorting, pagination and the empty state are in Filters, sorting and pagination.
5. Products of other collections
To show a few products of another collection, such as “New in” on the home page, read that collection’s entry in the frontmatter and render its first products as in step 3, or use data-id="specific-collection": see Product lists.
Before you publish
On the dev server and on your *.workers.dev address, the Smootify debugger lists the elements that are out of place on the page. Turn it on with Alt⇧ ShiftD, or open the page with ?smootify-debug.
Check these first
- Every collection page shows every product. The page reads the whole
productscollection, not the products of the entry. Readc.products. - A new product is missing from the list. The page shows what the content collection held at the last build. Build again, or use search & discovery, which reads Shopify directly.
- Search & discovery shows nothing. It needs a
smootify-productcard inside, or it is removed. On the live domain it also needs the Search & discovery add-on. - Every card shows the same name or image. Inside search & discovery, every card is a copy of the first one, so text that has no Smootify attribute is copied from it. Add
product="title",variant="image"and the other attributes to the card. - A search on a big collection misses products. Only its first 2,000 products are compared with the search. Tag them and use
data-tag: see Search inside a collection. - Collection links lead to a page that does not exist. Your collection pages are not under
/collections/. SetcollectionsBasein theuserOptionsof the integration. - The list reshuffles at load. The server cards are not in the collection’s own order, or there are more of them than
limit.