Collection Pages and Merchandising Controls Intermediate 12 min read

Collection Template Architecture

Understand how collection templates work in Shopify Online Store 2.0, including JSON template structure, section organization, and the collection object.

Collection pages are where customers browse and discover products. Understanding how collection templates work in Online Store 2.0 helps you build flexible, merchant-customizable shopping experiences.

The Collection Object

When a customer visits a collection URL, Shopify provides the collection object:

{{ collection.title }} {# "Summer Collection" #}
{{ collection.description }} {# Collection description HTML #}
{{ collection.handle }} {# "summer-collection" #}
{{ collection.url }} {# "/collections/summer-collection" #}
{{ collection.image }} {# Collection image object #}
{{ collection.products }} {# Paginated array of products #}
{{ collection.products_count }} {# Total number of products #}
{{ collection.all_products_count }} {# Count before filters #}

JSON Template Structure

Collection templates in Online Store 2.0 use JSON to define sections:

{# templates/collection.json #}
{
"sections": {
"banner": {
"type": "collection-banner",
"settings": {
"show_collection_description": true,
"show_collection_image": true
}
},
"product-grid": {
"type": "collection-product-grid",
"settings": {
"products_per_page": 24,
"columns_desktop": 4,
"enable_filtering": true,
"enable_sorting": true
}
}
},
"order": ["banner", "product-grid"]
}

Template File Organization

A typical collection template setup:

templates/
├── collection.json # Default collection template
├── collection.sale.json # Alternate: Sale collections
└── collection.featured.json # Alternate: Featured collections
sections/
├── collection-banner.liquid
├── collection-product-grid.liquid
├── collection-filters.liquid
└── collection-empty.liquid
snippets/
├── product-card.liquid
├── product-card-badges.liquid
├── pagination.liquid
└── filter-checkbox.liquid

Main Template Sections

A collection page typically has these sections:

1. Collection Banner

Shows collection title, description, and optional image:

{# sections/collection-banner.liquid #}
<div class="collection-banner">
{%- if collection.image and section.settings.show_image -%}
<div class="collection-banner__image">
<img
src="{{ collection.image | image_url: width: 1920 }}"
alt="{{ collection.image.alt | default: collection.title }}"
>
</div>
{%- endif -%}
<div class="collection-banner__content">
<h1 class="collection-banner__title">{{ collection.title }}</h1>
{%- if collection.description != blank and section.settings.show_description -%}
<div class="collection-banner__description">
{{ collection.description }}
</div>
{%- endif -%}
<p class="collection-banner__count">
{{ collection.products_count }}
{{ collection.products_count | pluralize: 'product', 'products' }}
</p>
</div>
</div>

2. Product Grid

Displays the products with sorting, filtering, and pagination:

{# sections/collection-product-grid.liquid #}
<div class="collection-grid">
{# Toolbar: Sorting, Filtering, View options #}
<div class="collection-grid__toolbar">
{%- if section.settings.enable_sorting -%}
{% render 'collection-sorting' %}
{%- endif -%}
{%- if section.settings.enable_filtering -%}
{% render 'collection-filters' %}
{%- endif -%}
</div>
{# Product grid #}
{%- paginate collection.products by section.settings.products_per_page -%}
{%- if collection.products.size > 0 -%}
<ul class="product-grid" style="--columns: {{ section.settings.columns }};">
{%- for product in collection.products -%}
<li class="product-grid__item">
{% render 'product-card', product: product %}
</li>
{%- endfor -%}
</ul>
{%- if paginate.pages > 1 -%}
{% render 'pagination', paginate: paginate %}
{%- endif -%}
{%- else -%}
{% render 'collection-empty' %}
{%- endif -%}
{%- endpaginate -%}
</div>

The Paginate Tag

Collection products are paginated. Wrap your product loop with paginate:

{%- paginate collection.products by 24 -%}
{# collection.products now contains only current page products #}
{# paginate object provides pagination info #}
Total products: {{ paginate.items }}
Current page: {{ paginate.current_page }}
Total pages: {{ paginate.pages }}
Products on this page: {{ collection.products.size }}
{%- for product in collection.products -%}
{{ product.title }}
{%- endfor -%}
{%- endpaginate -%}

Accessing Products

Current Page Products

{%- paginate collection.products by 24 -%}
{%- for product in collection.products -%}
{{ product.title }}
{%- endfor -%}
{%- endpaginate -%}
{# This loads ALL products - avoid for large collections #}
{%- for product in collection.all_products -%}
{{ product.title }}
{%- endfor -%}

Section Schema

A comprehensive collection grid schema:

{% schema %}
{
"name": "Collection Product Grid",
"settings": [
{
"type": "header",
"content": "Layout"
},
{
"type": "range",
"id": "products_per_page",
"label": "Products per page",
"min": 8,
"max": 48,
"step": 4,
"default": 24
},
{
"type": "range",
"id": "columns_desktop",
"label": "Desktop columns",
"min": 2,
"max": 5,
"step": 1,
"default": 4
},
{
"type": "range",
"id": "columns_mobile",
"label": "Mobile columns",
"min": 1,
"max": 2,
"step": 1,
"default": 2
},
{
"type": "header",
"content": "Features"
},
{
"type": "checkbox",
"id": "enable_sorting",
"label": "Enable sorting",
"default": true
},
{
"type": "checkbox",
"id": "enable_filtering",
"label": "Enable filtering",
"default": true
},
{
"type": "select",
"id": "filter_type",
"label": "Filter style",
"options": [
{ "value": "horizontal", "label": "Horizontal" },
{ "value": "sidebar", "label": "Sidebar" },
{ "value": "drawer", "label": "Drawer" }
],
"default": "horizontal"
},
{
"type": "header",
"content": "Product cards"
},
{
"type": "checkbox",
"id": "show_vendor",
"label": "Show vendor",
"default": false
},
{
"type": "checkbox",
"id": "show_rating",
"label": "Show rating",
"default": false
},
{
"type": "select",
"id": "image_ratio",
"label": "Image ratio",
"options": [
{ "value": "natural", "label": "Natural" },
{ "value": "square", "label": "Square (1:1)" },
{ "value": "portrait", "label": "Portrait (3:4)" },
{ "value": "landscape", "label": "Landscape (4:3)" }
],
"default": "portrait"
}
]
}
{% endschema %}

Alternate Collection Templates

Create specialized templates for different collection types:

Sale Template

{# templates/collection.sale.json #}
{
"sections": {
"banner": {
"type": "collection-banner",
"settings": {
"background_color": "#dc2626",
"text_color": "#ffffff"
}
},
"countdown": {
"type": "sale-countdown",
"settings": {
"end_date": "2024-12-31"
}
},
"product-grid": {
"type": "collection-product-grid",
"settings": {
"show_compare_price": true,
"show_discount_badge": true
}
}
},
"order": ["banner", "countdown", "product-grid"]
}
{# templates/collection.featured.json #}
{
"sections": {
"hero": {
"type": "collection-hero",
"settings": {
"full_width": true,
"height": "large"
}
},
"story": {
"type": "rich-text",
"settings": {}
},
"product-grid": {
"type": "collection-product-grid"
},
"newsletter": {
"type": "newsletter"
}
},
"order": ["hero", "story", "product-grid", "newsletter"]
}

Collection-Specific Data

Check collection properties for conditional logic:

{# Check if collection is empty #}
{%- if collection.products.size == 0 -%}
{% render 'collection-empty' %}
{%- endif -%}
{# Check if it's the "all" collection #}
{%- if collection.handle == 'all' -%}
<p>Browsing all products</p>
{%- endif -%}
{# Check for filtered state #}
{%- if collection.filters.size > 0 -%}
{%- assign active_filters = collection.filters | where: 'active_values' -%}
{%- if active_filters.size > 0 -%}
<p>Showing filtered results</p>
{%- endif -%}
{%- endif -%}
{# Check current sort order #}
{%- if collection.sort_by != blank -%}
<p>Sorted by: {{ collection.sort_by }}</p>
{%- endif -%}

Complete Template Example

{# templates/collection.json #}
{
"sections": {
"announcement": {
"type": "announcement-bar",
"disabled": true,
"settings": {}
},
"banner": {
"type": "collection-banner",
"settings": {
"show_image": true,
"show_description": true,
"image_height": "medium"
}
},
"toolbar": {
"type": "collection-toolbar",
"settings": {
"show_product_count": true,
"show_sort": true,
"show_filter_toggle": true
}
},
"main": {
"type": "collection-product-grid",
"settings": {
"products_per_page": 24,
"columns_desktop": 4,
"columns_tablet": 3,
"columns_mobile": 2,
"enable_quick_add": true,
"show_secondary_image": true
}
},
"recently-viewed": {
"type": "recently-viewed",
"disabled": true,
"settings": {}
}
},
"order": [
"announcement",
"banner",
"toolbar",
"main",
"recently-viewed"
]
}

Practice Exercise

Create a collection template that:

  1. Has a banner with title and product count
  2. Shows a product grid with 24 products per page
  3. Supports 4 columns on desktop, 2 on mobile
  4. Includes a toolbar for sorting
  5. Has pagination at the bottom

Map out which sections you need and what settings each should have.

Key Takeaways

  1. Collection templates are JSON in Online Store 2.0
  2. Use paginate tag to handle product pagination
  3. The collection object provides all collection data
  4. Split functionality into sections: banner, grid, filters
  5. Create alternate templates for special collections
  6. Schema settings give merchants control
  7. Check collection state for empty, filtered, sorted states

What’s Next?

With the architecture understood, the next lesson covers Building a Collection Banner Section for displaying collection headers.

Finished this lesson?

Mark it complete to track your progress.

Discussion

Loading comments...