ssg  
Article Series

Jekyll in General

Jekyll Plain

Where to Discuss?

Local Group

Preface

Goal: Get organized with your theme.

Source Code

This article use tutor-04 theme. We will create it step by step.


4: Content: Category and Tag

My motivation to move code is to refactor, and then reuse. Like previous code, consider move liquid code, from content in pages/ folder to partial in _includes/index/.

Partial Liquid: Terms Array

Consider isolate our liquid code in its own partial file artefact.

{% capture spaceless %}
  {% assign term_array = "" | split: "|" %}
  {% for tag in terms %}
    {% assign term_first = tag | first %}
    {% assign term_array = term_array | push: term_first %}
  {% endfor %}
  
  {% assign term_array = term_array | sort %}
{% endcapture %}

Partial Liquid: Terms List

And move the view to its own partial file artefact.

  <p>Tag List:
  <ul>
  {% for item in (0..terms.size) %}{% unless forloop.last %}
    {% assign this_word = term_array[item] | strip_newlines %}
    <li id="{{ this_word | slugify }}" class ="anchor-target">
      {{ this_word }}
    </li>
  {% endunless %}{% endfor %}
  </ul>
  </p>

This is exactly the same code as previous theme.

Content: Simple Tags List

---
layout    : index
title     : All Tags
permalink : /tags/
---

{% assign terms = site.tags %}
{% include index/terms-array.html %}
{% include index/terms-list.html %}

Now see how this custom page looks like.

Jekyll: Custom Pages: Simple Tags List

Partial Liquid: Terms Badge

With the same logic, we can make a list of terms badge.

  <p>Tag Badges:
  {% for item in (0..terms.size) %}{% unless forloop.last %}
    {% assign this_word = term_array[item] | strip_newlines %}
    <span>[
      <a href="#{{ this_word | slugify }}">
        {{ this_word }}
      </a> 
      <small>({{ terms[this_word].size }})</small>
    ]</span>
    &nbsp;
  {% endunless %}{% endfor %}
  </p>

This is not a hard thing to do, just need extra imagination.

Partial Liquid: Terms Tree

Why not go further, create tags tree. With each tags as key, and each post as branch list.

  <p>Tag Tree:
  <ul>
  {% for item in (0..terms.size) %}{% unless forloop.last %}
    {% assign this_word = term_array[item] | strip_newlines %}
    <li id="{{ this_word | slugify }}" class ="anchor-target">
      {{ this_word }}
      <ul>
        {% for post in terms[this_word] %}
          {% if post.title != null %}
          <li>
            <a href="{{ post.url | prepend: site.baseurl }}">
              {{ post.title }}
            </a>
          </li>
          {% endif %}
        {% endfor %}
      </ul>
    </li>
  {% endunless %}{% endfor %}
  </ul>
  </p>

Content: Tags Tree

Now is a good time to put the whole thing together.

---
layout    : index
title     : All Tags
permalink : /tags/
---

{% assign terms = site.tags %}
{% include index/terms-array.html %}
{% include index/terms-badge.html %}
{% include index/terms-tree.html %}

Now see how this custom page looks like.

Jekyll: Custom Pages: Tags Tree

Content: Categories Tree

Apply the refactored code above for categories page is easy.

---
layout    : index
title     : All Categories
permalink : /categories/
---

{% assign terms = site.categories %}
{% include index/terms-array.html %}
{% include index/terms-badge.html %}
{% include index/terms-tree.html %}

Now see how this custom page looks like.

Jekyll: Custom Pages: Categories Tree


5: Content: Archive by Year, then by Month

My motivation to move code is to have complex code by-month, while at the same time keeping the simple code by-year. This way, I can track, anytime I forget how it works.

Partial Liquid: By Year

Like above code, consider move liquid code, from content in pages/ folder to partial in _includes/index/.

{% assign postsByYear = posts
          | group_by_exp: "post", "post.date | date: '%Y'"  %}

<div id="archive">
{% for year in postsByYear %}

  {% capture spaceless %}
    {% assign current_year = 'now' | date: '%Y' %}
    {% assign year_text = nil %}

    {% if year.name == current_year %}
      {% assign year_text = year.name
                | prepend: "This year's posts (" | append: ')' %}
    {% else %}
      {% assign year_text = year.name %}
    {% endif %}
  {% endcapture %}

  <section>
    <p class ="anchor-target" 
       id="{{ year.name }}"
      >{{ year_text }}</p>

    <ul>
      {% for post in year.items %}
      <li><a href="{{ site.baseurl }}{{ post.url }}">
          {{ post.title }}
      </a></li>
      {% endfor %}
    </ul>
  </section>

{% endfor %}
</div>

Content: Archive by Year

The code in pages should be simpler by now.

---
layout    : index
title     : Archive by Year
permalink : /by-year/
---

{% assign posts = site.posts %}
{% include index/by-year.html %}

Now see how this custom page looks like.

Jekyll: Custom Pages: Archive by Year

Partial Liquid: By Month

Like above code, we can have better view. With a little effort, we can make a tree view. By year, then by month for each year. Things going to get more complex by now.

{% assign postsByYear = posts
          | group_by_exp: "post", "post.date | date: '%Y'"  %}

<div id="archive">
{% for year in postsByYear %}

  {% capture spaceless %}
    {% assign current_year = 'now' | date: '%Y' %}
    {% assign year_text = nil %}

    {% if year.name == current_year %}
      {% assign year_text = year.name 
                | prepend: "This year's posts (" | append: ')' %}
    {% else %}
      {% assign year_text = year.name %}
    {% endif %}
  {% endcapture %} 

  <section>
    <p class ="anchor-target" 
         id="{{ year.name }}"><b>{{ year_text }}</b></p>

    {% assign postsByMonth = year.items
              | group_by_exp:"post", "post.date | date: '%m'"
              | sort: 'name'
              | reverse %}
    <ul>
      {% for month in postsByMonth %}
      <li>
        {% for post in month.items limit:1 %}
        <div id="{{ year.name }}-{{ month.name }}">
             {{ post.date | date: '%b - %Y' }}</div>
        {% endfor %}

        <ul>
          {% for post in month.items %}
          <li><a href="{{ site.baseurl }}{{ post.url }}">
            {{ post.title }}
          </a></li>
          {% endfor %}
        </ul>
      </li>
      {% endfor %}
    </ul>
  </section>

{% endfor %}
</div>

Content: Archive by Year

The code in pages is also simple.

---
layout    : index
title     : Archive by Month
permalink : /by-month/
---

{% assign posts = site.posts %}
{% include index/by-month.html %}

Now see how this custom page looks like.

Jekyll: Custom Pages: Archive by Month

Liquid Loop: How Does It Works?

We have outer loop by year, and inner loop by month.

{% assign postsByYear = posts
          | group_by_exp: "post", "post.date | date: '%Y'"  %}

{% for year in postsByYear %}
    ...

    {% assign postsByMonth = year.items
              | group_by_exp:"post", "post.date | date: '%m'"
              | sort: 'name'
              | reverse %}

      {% for month in postsByMonth %}
          {% for post in month.items %}
            ...
          {% endfor %}
      {% endfor %}

{% endfor %}

What’s Next?

Consider continue reading [ Jekyll - Plain - Managing Code - Part Three ].

Thank you for reading.