Archive Page

Create year and month archive pages for blog content

3 min read 651 words
Edit this page

Was this page helpful?

Create archive pages that group content by year or month.

Note

Built into Default Theme

Bengal's default theme includes archive templates:

  • archive.html — Full archive page grouped by year
  • archive-year.html — Year-specific archive pages
  • partials/archive-sidebar.html — Sidebar widget with year links

This recipe shows how to customize grouping or build your own archive layouts.

The Pattern

Yearly Archive

KIDA
{% let posts = site.pages |> where('section', 'blog') |> sort_by('date', reverse=true) %}
{% let by_year = posts |> group_by_year %}

<div class="archive">
{% for year, year_posts in by_year.items() %}
  <section class="archive-year">
    <h2>{{ year }}</h2>
    <ul>
    {% for post in year_posts %}
      <li>
        <time>{{ post.date | dateformat('%b %d') }}</time>
        <a href="{{ post.href }}">{{ post.title }}</a>
      </li>
    {% end %}
    </ul>
  </section>
{% end %}
</div>

What's Happening

Filter Purpose
group_by_year Groups pages by publication year
group_by_month Groups pages by year-month
archive_years Returns list of years with post counts

Variations

Quick navigation showing years with counts:

KIDA
{% let posts = site.pages |> where('section', 'blog') %}
{% let years = posts |> archive_years %}

<aside class="archive-nav">
  <h3>Archive</h3>
  <ul>
  {% for item in years %}
    <li>
      <a href="/blog/{{ item.year }}/">{{ item.year }}</a>
      <span class="count">({{ item.count }})</span>
    </li>
  {% end %}
  </ul>
</aside>
KIDA
{% let posts = site.pages |> where('section', 'blog') |> sort_by('date', reverse=true) %}
{% let by_month = posts |> group_by_month %}

<div class="archive">
{% for (year, month), month_posts in by_month.items() %}
  <section class="archive-month">
    <h2>{{ month | month_name }} {{ year }}</h2>
    <ul>
    {% for post in month_posts %}
      <li>
        <time>{{ post.date | dateformat('%d') }}</time>
        <a href="{{ post.href }}">{{ post.title }}</a>
      </li>
    {% end %}
    </ul>
  </section>
{% end %}
</div>
KIDA
{% let posts = site.pages |> where('section', 'blog') |> sort_by('date', reverse=true) %}
{% let by_year = posts |> group_by_year %}

<div class="timeline">
{% for year, year_posts in by_year.items() %}
  <div class="timeline-year">
    <div class="year-marker">{{ year }}</div>
    <div class="year-posts">
      {% for post in year_posts %}
      <a href="{{ post.href }}" class="timeline-post">
        <span class="date">{{ post.date | dateformat('%b %d') }}</span>
        <span class="title">{{ post.title }}</span>
      </a>
      {% end %}
    </div>
  </div>
{% end %}
</div>
KIDA
{% let posts = site.pages |> where('section', 'blog') |> sort_by('date', reverse=true) %}
{% let by_year = posts |> group_by_year %}

{% for year, year_posts in by_year.items() %}
<section>
  <h2>{{ year }}</h2>

  {% let by_category = year_posts |> group_by('category') %}
  {% for category, cat_posts in by_category.items() %}
  <div class="category-group">
    <h3>{{ category | title }}</h3>
    <ul>
    {% for post in cat_posts %}
      <li><a href="{{ post.href }}">{{ post.title }}</a></li>
    {% end %}
    </ul>
  </div>
  {% end %}
</section>
{% end %}
KIDA
{% let posts = site.pages |> where('section', 'blog') %}
{% let years = posts |> archive_years %}

<header class="archive-header">
  <h1>Archive</h1>
  <p class="archive-stats">
    {{ posts | length }} posts across {{ years | length }} years
    ({{ years |> first |> attr('year') }}{{ years |> last |> attr('year') }})
  </p>
</header>

Example CSS

CSS
.archive-year {
  margin-bottom: 2rem;
}

.archive-year h2 {
  font-size: 1.5rem;
  border-bottom: 2px solid var(--accent);
  padding-bottom: 0.5rem;
  margin-bottom: 1rem;
}

.archive-year ul {
  list-style: none;
  padding: 0;
}

.archive-year li {
  display: flex;
  gap: 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border-color);
}

.archive-year time {
  color: var(--text-muted);
  font-family: monospace;
  min-width: 60px;
}

/* Timeline variant */
.timeline-year {
  display: flex;
  gap: 2rem;
  margin-bottom: 2rem;
}

.year-marker {
  font-size: 1.25rem;
  font-weight: bold;
  color: var(--accent);
  min-width: 60px;
}

.timeline-post {
  display: block;
  padding: 0.25rem 0;
}

.timeline-post .date {
  color: var(--text-muted);
  font-size: 0.875rem;
  margin-right: 0.5rem;
}

/* Sidebar nav */
.archive-nav .count {
  color: var(--text-muted);
  font-size: 0.875rem;
}

Seealso