Skip to content

Post Template

The post template renders individual blog posts or news articles. It displays the full post content, author information, categories, and related metadata.

└── theme
└── templates
└── post.liquid

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

PropertyTypeDescription
idstringUnique identifier
titlestringPost title
descriptionstringPost excerpt/lede
slugstringURL-safe identifier
imagemediaFeatured image
PropertyTypeDescription
publishDatestringPublication date (ISO 8601)
blogblogParent blog
PropertyTypeDescription
authorsarrayPost authors (people)
categoriesarrayPost categories
tagsarrayPost tags
PropertyTypeDescription
blocksarrayContent blocks
customAttributesobjectCustom attribute values
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 %}
<article class="post">
<header class="post-header">
{% if post.image %}
<img
src="{{ post.image | image_url: width: 1200, height: 600 }}"
alt="{{ post.image.alt | default: post.title }}"
class="post-header__image"
>
{% endif %}
<h1>{{ post.title }}</h1>
{% if post.publishDate %}
<time datetime="{{ post.publishDate }}">
{{ post.publishDate | date: '%B %d, %Y' }}
</time>
{% endif %}
{% if post.description %}
<p class="lead">{{ post.description }}</p>
{% endif %}
</header>
<div class="post-body">
{% stageblocks post %}
</div>
</article>
{% endcapture %}
{% if post.authors.size > 0 %}
{% assign author = post.authors.first %}
<div class="post-author">
{% if author.image %}
<img
src="{{ author.image | image_url: width: 80, height: 80 }}"
alt="{{ author.name }}"
class="author-avatar"
>
{% endif %}
<div class="author-info">
<span class="author-name">
<a href="/people/{{ author.slug }}">{{ author.name }}</a>
</span>
{% if author.role %}
<span class="author-role">{{ author.role }}</span>
{% endif %}
</div>
</div>
{% endif %}
{% if post.authors.size > 0 %}
<div class="post-authors">
<span class="byline">By</span>
{% for author in post.authors %}
<a href="/people/{{ author.slug }}">{{ author.name }}</a>
{% unless forloop.last %}
{% if forloop.index == post.authors.size | minus: 1 %}
and
{% else %}
,
{% endif %}
{% endunless %}
{% endfor %}
</div>
{% endif %}
{% if post.authors.size > 0 %}
<aside class="author-box">
<h3>About the Author{% if post.authors.size > 1 %}s{% endif %}</h3>
{% for author in post.authors %}
<div class="author-bio">
{% if author.image %}
<img
src="{{ author.image | image_url: width: 120, height: 120 }}"
alt="{{ author.name }}"
>
{% endif %}
<div>
<h4>{{ author.name }}</h4>
{% if author.role %}
<p class="role">{{ author.role }}</p>
{% endif %}
{% if author.biography_html %}
{{ author.biography_html }}
{% endif %}
</div>
</div>
{% endfor %}
</aside>
{% endif %}
{% if post.categories.size > 0 %}
<div class="post-categories">
{% for category in post.categories %}
<a href="/blog?category={{ category | handleize }}" class="category-badge">
{{ category }}
</a>
{% endfor %}
</div>
{% endif %}
{% if post.tags.size > 0 %}
<div class="post-tags">
<span class="tags-label">Tags:</span>
{% for tag in post.tags %}
<a href="/blog?tag={{ tag | handleize }}" class="tag">
{{ tag }}
</a>
{% unless forloop.last %}, {% endunless %}
{% endfor %}
</div>
{% endif %}
<footer class="post-meta">
{% if post.categories.size > 0 %}
<div class="meta-item">
<strong>Categories:</strong>
{% for category in post.categories %}
<a href="/blog?category={{ category | handleize }}">{{ category }}</a>
{% unless forloop.last %}, {% endunless %}
{% endfor %}
</div>
{% endif %}
{% if post.tags.size > 0 %}
<div class="meta-item">
<strong>Tags:</strong>
{% for tag in post.tags %}
<a href="/blog?tag={{ tag | handleize }}">{{ tag }}</a>
{% unless forloop.last %}, {% endunless %}
{% endfor %}
</div>
{% endif %}
</footer>
{% if post.blog %}
<a href="/blogs/{{ post.blog.slug }}" class="back-link">
&larr; Back to {{ post.blog.title }}
</a>
{% endif %}
<nav class="breadcrumb" aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
{% if post.blog %}
<li><a href="/blogs/{{ post.blog.slug }}">{{ post.blog.title }}</a></li>
{% endif %}
<li aria-current="page">{{ post.title }}</li>
</ol>
</nav>

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

{# Template schema defines: reading_time, show_social_share, related_posts #}
{% if post.theme.reading_time %}
<span class="reading-time">{{ post.theme.reading_time }} min read</span>
{% endif %}
{% if post.theme.show_social_share %}
{% render 'snippets/social-share' title: post.title %}
{% endif %}
{% layout 'layouts/default.liquid' %}
{% capture content_for_layout %}
<article class="post-page">
{# Breadcrumb #}
<nav class="breadcrumb" aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
{% if post.blog %}
<li><a href="/blogs/{{ post.blog.slug }}">{{ post.blog.title }}</a></li>
{% endif %}
<li aria-current="page">{{ post.title }}</li>
</ol>
</nav>
{# Post header #}
<header class="post-header">
{% if post.categories.size > 0 %}
<div class="post-categories">
{% for category in post.categories %}
<a href="/blog?category={{ category | handleize }}" class="category-badge">
{{ category }}
</a>
{% endfor %}
</div>
{% endif %}
<h1 class="post-title">{{ post.title }}</h1>
<div class="post-meta">
{% if post.publishDate %}
<time datetime="{{ post.publishDate }}">
{{ post.publishDate | date: '%B %d, %Y' }}
</time>
{% endif %}
{% if post.theme.reading_time %}
<span class="reading-time">{{ post.theme.reading_time }} min read</span>
{% endif %}
</div>
{# Authors #}
{% if post.authors.size > 0 %}
<div class="post-authors">
{% for author in post.authors %}
<a href="/people/{{ author.slug }}" class="author">
{% if author.image %}
<img
src="{{ author.image | image_url: width: 48, height: 48 }}"
alt="{{ author.name }}"
class="author-avatar"
>
{% endif %}
<span class="author-name">{{ author.name }}</span>
</a>
{% endfor %}
</div>
{% endif %}
</header>
{# Featured image #}
{% if post.image %}
<figure class="post-featured-image">
<img
src="{{ post.image | image_url: width: 1200, height: 600 }}"
alt="{{ post.image.alt | default: post.title }}"
>
{% if post.image.caption %}
<figcaption>{{ post.image.caption }}</figcaption>
{% endif %}
</figure>
{% endif %}
{# Post content #}
<div class="post-content">
{% if post.description %}
<p class="lead">{{ post.description }}</p>
{% endif %}
{% stageblocks post %}
</div>
{# Tags #}
{% if post.tags.size > 0 %}
<footer class="post-footer">
<div class="post-tags">
<span class="tags-label">Tagged:</span>
{% for tag in post.tags %}
<a href="/blog?tag={{ tag | handleize }}" class="tag">{{ tag }}</a>
{% endfor %}
</div>
</footer>
{% endif %}
{# Social sharing #}
{% if post.theme.show_social_share != false %}
<div class="post-share">
<h3>Share this post</h3>
{% render 'snippets/social-share' title: post.title %}
</div>
{% endif %}
{# Author bio #}
{% if post.authors.size > 0 %}
<aside class="author-bio-section">
{% for author in post.authors %}
<div class="author-bio">
{% if author.image %}
<img
src="{{ author.image | image_url: width: 120, height: 120 }}"
alt="{{ author.name }}"
class="author-bio__image"
>
{% endif %}
<div class="author-bio__content">
<h4>
<a href="/people/{{ author.slug }}">{{ author.name }}</a>
</h4>
{% if author.role %}
<p class="author-role">{{ author.role }}</p>
{% endif %}
{% if author.biography_html %}
<div class="author-bio__text">{{ author.biography_html }}</div>
{% endif %}
</div>
</div>
{% endfor %}
</aside>
{% endif %}
{# Navigation #}
<nav class="post-nav">
{% if post.blog %}
<a href="/blogs/{{ post.blog.slug }}" class="back-link">
&larr; More from {{ post.blog.title }}
</a>
{% endif %}
</nav>
</article>
{% endcapture %}
{% schema %}
{
"name": "post",
"settings": [
{
"type": "number",
"name": "reading_time",
"label": "Reading Time (minutes)"
},
{
"type": "checkbox",
"name": "show_social_share",
"label": "Show Social Share Buttons",
"defaultValue": true
},
{
"type": "checkbox",
"name": "show_author_bio",
"label": "Show Author Bio",
"defaultValue": true
}
],
"blocks": [
"content",
"image-gallery",
"video-gallery",
"well"
]
}
{% endschema %}

Create a reusable post card component:

{# components/post-card.liquid #}
{#
Required: post (post object)
Optional: show_excerpt (boolean), show_author (boolean)
#}
{% assign show_excerpt = show_excerpt | default: true %}
{% assign show_author = show_author | default: false %}
<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>
{% if show_excerpt and post.description %}
<p class="post-card__excerpt">{{ post.description | truncate: 120 }}</p>
{% endif %}
<div class="post-card__meta">
{% if post.publishDate %}
<time datetime="{{ post.publishDate }}">
{{ post.publishDate | date: '%b %d, %Y' }}
</time>
{% endif %}
{% if show_author and post.authors.size > 0 %}
<span class="post-card__author">
by {{ post.authors.first.name }}
</span>
{% endif %}
</div>
</div>
</a>
</article>

Usage:

<div class="post-grid">
{% for post in all_posts limit: 6 %}
{% render 'components/post-card' post: post, show_author: true %}
{% endfor %}
</div>

Create variations for different post types:

templates/
├── post.liquid # Default blog post template
├── post.news.liquid # News article layout
├── post.review.liquid # Review with rating
└── post.interview.liquid # Interview Q&A format

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