Basker Docs

Category template

Reference for the category object — primary post groupings within a blog

The category template renders pages that display all posts within a specific category. It provides a filtered view of blog content organized by category.

Location

└── theme
    └── templates
        └── category.liquid

URL Structure

Categories are scoped to a blog, so category pages are accessible at:

  • /blogs/:blogSlug/categories/:slug

For example: /blogs/news/categories/reviews, /blogs/news/categories/announcements

Each category record exposes a ready-built url property in exactly this shape. Prefer linking with the url property rather than assembling the path by hand, so links stay correct if the URL structure ever changes.

Template Variables

The category template receives these variables:

The category Object

PropertyTypeDescription
idstringUnique identifier
titlestringCategory name
slugstringURL-safe identifier
descriptionstringOptional description shown at the top of the listing
urlstringThe category's archive page, e.g. /blogs/news/categories/reviews

The posts Array

An array of all published posts in this category:

PropertyTypeDescription
postsarrayPosts belonging to this category

Each post in the array has access to all standard post properties (title, description, publishDate, authors, image, etc.).

A post's own categories and tags are arrays of objects, not plain strings. Each entry has a title and a slug — loop over them and read category.title and category.slug. You do not need handleize; use category.slug directly when building links.

Basic Template Example

{% layout 'layouts/default.liquid' %}

{% capture content_for_layout %}
<div class="category-page">
  <header class="category-header">
    <h1>{{ category.title }}</h1>
    <p class="post-count">{{ posts.size }} {% if posts.size == 1 %}post{% else %}posts{% endif %}</p>
  </header>

  <div class="posts-list">
    {% if posts.size > 0 %}
      {% for post in posts %}
        <article class="post-card">
          {% if post.image %}
            <img
              src="{{ post.image | image_url: width: 400, height: 250 }}"
              alt="{{ post.title }}"
              loading="lazy"
            >
          {% endif %}

          <div class="post-card__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 %}
          </div>
        </article>
      {% endfor %}
    {% else %}
      <p class="no-posts">No posts in this category yet.</p>
    {% endif %}
  </div>
</div>
{% endcapture %}

Working with Posts

Display Post Authors

{% for post in 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="author">
          By {{ post.authors.first.name }}
        </span>
      {% endif %}

      {% if post.publishDate %}
        <time datetime="{{ post.publishDate }}">
          {{ post.publishDate | date: '%b %d, %Y' }}
        </time>
      {% endif %}
    </div>
  </article>
{% endfor %}
{% for post in posts %}
  <article class="post-card">
    {% if post.image %}
      <img
        src="{{ post.image | image_url: width: 400, height: 250 }}"
        alt="{{ post.title }}"
        class="post-card__image"
        loading="lazy"
      >
    {% elsif settings.global.fallbackImage %}
      <img
        src="{{ settings.global.fallbackImage | image_url: width: 400, height: 250 }}"
        alt=""
        class="post-card__image post-card__image--fallback"
        loading="lazy"
      >
    {% endif %}

    <h3>{{ post.title }}</h3>
  </article>
{% endfor %}

Posts Grouped by Month

{% assign current_month = '' %}

{% for post in 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 %}

  <article class="post-item">
    <a href="/posts/{{ post.slug }}">{{ post.title }}</a>
    <time>{{ post.publishDate | date: '%d' }}</time>
  </article>

  {% if forloop.last %}</div>{% endif %}
{% endfor %}

Complete Template Example

{% layout 'layouts/default.liquid' %}

{% capture content_for_layout %}
<div class="category-page">
  {# Breadcrumb navigation #}
  <nav class="breadcrumb" aria-label="Breadcrumb">
    <ol>
      <li><a href="/">Home</a></li>
      <li><a href="/blog">Blog</a></li>
      <li aria-current="page">{{ category.title }}</li>
    </ol>
  </nav>

  {# Category header #}
  <header class="category-header">
    <h1>{{ category.title }}</h1>
    <p class="category-meta">
      {{ posts.size }} {% if posts.size == 1 %}article{% else %}articles{% endif %}
    </p>
  </header>

  {# Posts listing #}
  {% if posts.size > 0 %}
    <section class="category-posts">
      {# Featured post (first/latest) #}
      {% assign featured = posts.first %}
      <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 }}"
            >
          </a>
        {% endif %}

        <div class="featured-post__content">
          <h2>
            <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">Read Article</a>
        </div>
      </article>

      {# Remaining posts grid #}
      {% if posts.size > 1 %}
        <div class="post-grid">
          {% for post in posts offset: 1 %}
            <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">
                  <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: 100 }}
                    </p>
                  {% endif %}
                </div>
              </a>
            </article>
          {% endfor %}
        </div>
      {% endif %}
    </section>

  {% else %}
    <div class="category-empty">
      <h2>No Articles Yet</h2>
      <p>There are no posts in the "{{ category.title }}" category yet. Check back soon!</p>
      <a href="/blog" class="btn btn--secondary">Browse All Posts</a>
    </div>
  {% endif %}

  {# Navigation #}
  <nav class="category-nav">
    <a href="/blog" class="back-link">
      &larr; Back to Blog
    </a>
  </nav>
</div>
{% endcapture %}

{% schema %}
{
  "name": "category",
  "settings": [
    {
      "type": "checkbox",
      "name": "show_featured",
      "label": "Feature Latest Post",
      "defaultValue": true
    },
    {
      "type": "select",
      "name": "layout",
      "label": "Posts Layout",
      "options": [
        { "value": "grid", "label": "Grid" },
        { "value": "list", "label": "List" }
      ],
      "defaultValue": "grid"
    }
  ]
}
{% endschema %}

Linking to Categories

From Post Templates

A post's categories are objects with title and slug. Build the archive URL from the post's blog slug and the category slug — the same shape core generates:

{# In post.liquid template #}
{% if post.categories.size > 0 %}
  <div class="post-categories">
    {% for category in post.categories %}
      <a href="/blogs/{{ post.blog.slug }}/categories/{{ category.slug }}" class="category-link">
        {{ category.title }}
      </a>
    {% endfor %}
  </div>
{% endif %}

Category Navigation

When you have the full category records (for example via the blog's categories list), each one carries a ready-built url, so you can link to it directly:

{# Display all categories #}
{% if blog.categories.size > 0 %}
  <nav class="category-nav">
    <h3>Categories</h3>
    <ul>
      {% for category in blog.categories %}
        <li>
          <a href="{{ category.url }}">{{ category.title }}</a>
        </li>
      {% endfor %}
    </ul>
  </nav>
{% endif %}

Alternate Category Templates

Create variations for different category presentations:

templates/
├── category.liquid           # Default category template
├── category.featured.liquid  # Hero-style featured layout
├── category.compact.liquid   # Compact list view
└── category.archive.liquid   # Archive-style chronological

On this page