Skip to content

Blog Template

The blog template renders blog index pages that list all posts within a blog. It provides pagination and filtering capabilities for browsing blog content.

└── theme
└── templates
└── blog.liquid

The blog template has access to the blog object with these properties:

PropertyTypeDescription
idstringUnique identifier
titlestringBlog name
descriptionstringBlog description
slugstringURL-safe identifier
imagemediaBlog featured image
PropertyTypeDescription
postsarrayPosts in this blog (sorted by publish date)
PropertyTypeDescription
themeobjectTheme-specific field values
PropertyTypeDescription
meta.titlestringSEO title
meta.descriptionstringSEO description
meta.imagemediaSEO/OG image
createdAtstringCreation timestamp
updatedAtstringLast update timestamp
{% layout 'layouts/default.liquid' %}
{% capture content_for_layout %}
<div class="blog">
<header class="blog-header">
<h1>{{ blog.title }}</h1>
{% if blog.description %}
<p class="lead">{{ blog.description }}</p>
{% endif %}
</header>
<div class="blog-posts">
{% for post in blog.posts %}
<article class="post-preview">
{% if post.image %}
<img
src="{{ post.image | image_url: width: 400, height: 250 }}"
alt="{{ post.title }}"
loading="lazy"
>
{% endif %}
<div class="post-preview__content">
<h2>
<a href="/posts/{{ post.slug }}">{{ post.title }}</a>
</h2>
{% if post.publishDate %}
<time datetime="{{ post.publishDate }}">
{{ post.publishDate | date: '%B %d, %Y' }}
</time>
{% endif %}
{% if post.description %}
<p>{{ post.description | truncate: 150 }}</p>
{% endif %}
<a href="/posts/{{ post.slug }}" class="read-more">Read more</a>
</div>
</article>
{% endfor %}
</div>
</div>
{% endcapture %}

Display the most recent post prominently:

{% if blog.posts.size > 0 %}
{% assign featured_post = blog.posts.first %}
<article class="featured-post">
{% if featured_post.image %}
<img
src="{{ featured_post.image | image_url: width: 1200, height: 600 }}"
alt="{{ featured_post.title }}"
class="featured-post__image"
>
{% endif %}
<div class="featured-post__content">
{% if featured_post.categories.size > 0 %}
<span class="category">{{ featured_post.categories.first }}</span>
{% endif %}
<h2>
<a href="/posts/{{ featured_post.slug }}">{{ featured_post.title }}</a>
</h2>
{% if featured_post.publishDate %}
<time datetime="{{ featured_post.publishDate }}">
{{ featured_post.publishDate | date: '%B %d, %Y' }}
</time>
{% endif %}
{% if featured_post.description %}
<p class="lead">{{ featured_post.description }}</p>
{% endif %}
<a href="/posts/{{ featured_post.slug }}" class="btn">Read Article</a>
</div>
</article>
{# Remaining posts #}
{% if blog.posts.size > 1 %}
<div class="post-grid">
{% for post in blog.posts offset: 1 %}
{% render 'components/post-card' post: post %}
{% endfor %}
</div>
{% endif %}
{% endif %}
{% for post in blog.posts %}
<article class="post-item">
<h2><a href="/posts/{{ post.slug }}">{{ post.title }}</a></h2>
<div class="post-meta">
{% if post.authors.size > 0 %}
<span class="authors">
By
{% for author in post.authors %}
{{ author.name }}{% unless forloop.last %}, {% endunless %}
{% endfor %}
</span>
{% endif %}
{% if post.publishDate %}
<time datetime="{{ post.publishDate }}">
{{ post.publishDate | date: '%b %d, %Y' }}
</time>
{% endif %}
</div>
</article>
{% endfor %}
{% assign current_month = '' %}
{% for post in blog.posts %}
{% assign post_month = post.publishDate | date: '%B %Y' %}
{% if post_month != current_month %}
{% unless current_month == '' %}
</div>
{% endunless %}
<h3 class="month-header">{{ post_month }}</h3>
<div class="month-posts">
{% assign current_month = post_month %}
{% endif %}
{% render 'components/post-card' post: post %}
{% if forloop.last %}</div>{% endif %}
{% endfor %}

Display posts filtered by category:

{# Get unique categories from all posts #}
{% assign all_categories = '' %}
{% for post in blog.posts %}
{% for category in post.categories %}
{% unless all_categories contains category %}
{% if all_categories != '' %}
{% assign all_categories = all_categories | append: ',' %}
{% endif %}
{% assign all_categories = all_categories | append: category %}
{% endunless %}
{% endfor %}
{% endfor %}
{% assign categories = all_categories | split: ',' %}
{# Category filter navigation #}
<nav class="category-filter">
<a href="/blogs/{{ blog.slug }}" class="filter-link {% unless request.params.category %}active{% endunless %}">
All
</a>
{% for category in categories %}
<a href="/blogs/{{ blog.slug }}?category={{ category | handleize }}"
class="filter-link {% if request.params.category == category | handleize %}active{% endif %}">
{{ category }}
</a>
{% endfor %}
</nav>

Access custom fields defined in the template schema via blog.theme:

{# Template schema defines: posts_per_page, show_featured, newsletter_signup #}
{% if blog.theme.show_featured and blog.posts.size > 0 %}
{% assign featured = blog.posts.first %}
{# Display featured post #}
{% endif %}
{% if blog.theme.newsletter_signup.enabled %}
<aside class="newsletter-signup">
<h3>{{ blog.theme.newsletter_signup.heading | default: 'Subscribe' }}</h3>
<p>{{ blog.theme.newsletter_signup.description }}</p>
<form action="{{ blog.theme.newsletter_signup.form_action }}" method="post">
<input type="email" name="email" placeholder="Your email" required>
<button type="submit">Subscribe</button>
</form>
</aside>
{% endif %}
{% layout 'layouts/default.liquid' %}
{% capture content_for_layout %}
<div class="blog-page">
{# Blog header #}
<header class="blog-header">
{% if blog.image %}
<img
src="{{ blog.image | image_url: width: 1920, height: 400 }}"
alt="{{ blog.title }}"
class="blog-header__image"
>
{% endif %}
<div class="blog-header__content">
<h1>{{ blog.title }}</h1>
{% if blog.description %}
<p class="lead">{{ blog.description }}</p>
{% endif %}
</div>
</header>
{% if blog.posts.size > 0 %}
{# Featured post #}
{% if blog.theme.show_featured != false %}
{% assign featured = blog.posts.first %}
<section class="featured-section">
<article class="featured-post">
{% if featured.image %}
<a href="/posts/{{ featured.slug }}" class="featured-post__image-link">
<img
src="{{ featured.image | image_url: width: 1200, height: 500 }}"
alt="{{ featured.title }}"
class="featured-post__image"
>
</a>
{% endif %}
<div class="featured-post__content">
{% if featured.categories.size > 0 %}
<span class="featured-post__category">{{ featured.categories.first }}</span>
{% endif %}
<h2 class="featured-post__title">
<a href="/posts/{{ featured.slug }}">{{ featured.title }}</a>
</h2>
<div class="featured-post__meta">
{% if featured.publishDate %}
<time datetime="{{ featured.publishDate }}">
{{ featured.publishDate | date: '%B %d, %Y' }}
</time>
{% endif %}
{% if featured.authors.size > 0 %}
<span class="author">
by {{ featured.authors.first.name }}
</span>
{% endif %}
</div>
{% if featured.description %}
<p class="featured-post__excerpt">{{ featured.description }}</p>
{% endif %}
<a href="/posts/{{ featured.slug }}" class="btn btn--primary">
Read Article
</a>
</div>
</article>
</section>
{% endif %}
{# Posts grid #}
<section class="posts-section">
<h2 class="visually-hidden">All Posts</h2>
<div class="post-grid">
{% assign offset = 0 %}
{% if blog.theme.show_featured != false %}
{% assign offset = 1 %}
{% endif %}
{% for post in blog.posts offset: offset %}
<article class="post-card">
<a href="/posts/{{ post.slug }}" class="post-card__link">
{% if post.image %}
<img
src="{{ post.image | image_url: width: 400, height: 250 }}"
alt="{{ post.title }}"
class="post-card__image"
loading="lazy"
>
{% endif %}
<div class="post-card__content">
{% if post.categories.size > 0 %}
<span class="post-card__category">{{ post.categories.first }}</span>
{% endif %}
<h3 class="post-card__title">{{ post.title }}</h3>
<div class="post-card__meta">
{% if post.publishDate %}
<time datetime="{{ post.publishDate }}">
{{ post.publishDate | date: '%b %d, %Y' }}
</time>
{% endif %}
</div>
{% if post.description %}
<p class="post-card__excerpt">
{{ post.description | truncate: 120 }}
</p>
{% endif %}
</div>
</a>
</article>
{% endfor %}
</div>
</section>
{% else %}
<div class="blog-empty">
<p>No posts yet. Check back soon!</p>
</div>
{% endif %}
{# Newsletter signup #}
{% if blog.theme.newsletter_signup_enabled %}
<aside class="newsletter-section">
<div class="newsletter-content">
<h3>{{ blog.theme.newsletter_heading | default: 'Stay Updated' }}</h3>
<p>{{ blog.theme.newsletter_description | default: 'Subscribe to get the latest posts delivered to your inbox.' }}</p>
<form class="newsletter-form" action="{{ blog.theme.newsletter_action }}" method="post">
<input type="email" name="email" placeholder="Enter your email" required>
<button type="submit" class="btn btn--primary">Subscribe</button>
</form>
</div>
</aside>
{% endif %}
</div>
{% endcapture %}
{% schema %}
{
"name": "blog",
"settings": [
{
"type": "checkbox",
"name": "show_featured",
"label": "Show Featured Post",
"defaultValue": true
},
{
"type": "number",
"name": "posts_per_page",
"label": "Posts Per Page",
"defaultValue": 12
},
{
"type": "checkbox",
"name": "newsletter_signup_enabled",
"label": "Enable Newsletter Signup",
"defaultValue": false
},
{
"type": "text",
"name": "newsletter_heading",
"label": "Newsletter Heading"
},
{
"type": "textarea",
"name": "newsletter_description",
"label": "Newsletter Description"
},
{
"type": "text",
"name": "newsletter_action",
"label": "Newsletter Form Action URL"
}
]
}
{% endschema %}
{# components/post-card.liquid #}
{#
Required: post (post object)
Optional: show_category (boolean), show_excerpt (boolean)
#}
{% assign show_category = show_category | default: true %}
{% assign show_excerpt = show_excerpt | default: true %}
<article class="post-card">
<a href="/posts/{{ post.slug }}" class="post-card__link">
{% if post.image %}
<img
src="{{ post.image | image_url: width: 400, height: 250 }}"
alt="{{ post.title }}"
class="post-card__image"
loading="lazy"
>
{% endif %}
<div class="post-card__content">
{% if show_category and post.categories.size > 0 %}
<span class="post-card__category">{{ post.categories.first }}</span>
{% endif %}
<h3 class="post-card__title">{{ post.title }}</h3>
{% if post.publishDate %}
<time class="post-card__date" datetime="{{ post.publishDate }}">
{{ post.publishDate | date: '%b %d, %Y' }}
</time>
{% endif %}
{% if show_excerpt and post.description %}
<p class="post-card__excerpt">{{ post.description | truncate: 120 }}</p>
{% endif %}
</div>
</a>
</article>

For use on other pages:

{# Display recent posts from a specific blog #}
{% assign news_blog = all_blogs | where: 'slug', 'news' | first %}
{% if news_blog.posts.size > 0 %}
<section class="recent-posts">
<h2>Latest News</h2>
<div class="post-grid">
{% for post in news_blog.posts limit: 3 %}
{% render 'components/post-card' post: post %}
{% endfor %}
</div>
<a href="/blogs/{{ news_blog.slug }}" class="view-all-link">
View All Posts &rarr;
</a>
</section>
{% endif %}

Create variations for different blog styles:

templates/
├── blog.liquid # Default blog listing
├── blog.magazine.liquid # Magazine-style layout
├── blog.minimal.liquid # Minimal text-focused
└── blog.grid.liquid # Grid gallery view

Alternate templates appear in the CMS for editors to select per blog.