Listing Jekyll Collection pages by tags
Asked Answered
C

3

8

I am trying to make a list of pages within a collection grouped by tags. I know this is easily possible with Jekyll's built-in site.tags feature, which I can (and have) achieve with something like:

 <h3>Tags</h3>

{% for tag in site.tags %}
  {% assign t = tag | first %}
  {% assign posts = tag | last %}

<h4><a name="{{t | downcase | replace:" ","-" }}"></a><a class="internal" href="/tagged/#{{t | downcase | replace:" ","-" }}">{{ t | downcase }}</a></h4>

<ul>
{% for post in posts %}
  {% if post.tags contains t %}
  <li>
    <a href="{{ post.url }}">{{ post.title }}</a>
    <span class="date">{{ post.date | date: "%B %-d, %Y"  }}</span>
  </li>
  {% endif %}
{% endfor %}
</ul>

<hr>

{% endfor %}

In order to get this:

Grouped by tags

I want to replicate the site.tags function in a Collection called note. Tags in my collections are grouped like they are for posts, using, e.g., tags: [urban growth, California, industrialization] in the YAML header. But I want to get this working with a Collection instead. I can almost achieve what I want with the following:

{% assign collection = site.note | group_by: "tags" | uniq %}
{% for group in collection %}
{% comment %} This is super hacky and I don't like it {% endcomment%}
  <h3>{{ group.name | replace: '"', '' | replace: '[', '' | replace: ']', '' }}</h3>
  <ul>
  {% for item in group.items %}
    <li><a href="{{ item.url | prepend: site.baseurl | prepend: site.url }}">{{ item.title }}</a></li>
  {% endfor %}
  </ul>
{%endfor%}

But as you can probably see, this doesn't break tags out into their unique groups; instead, each set of tags in the YAML is treated as a single, large tag. Any pointers on constructing the array of unique tags and listing the Collection pages under them?

Crissycrist answered 30/4, 2016 at 19:1 Comment(0)
N
23

Try this :

{% assign tags =  site.note | map: 'tags' | join: ','  | split: ',' | uniq %}
{% for tag in tags %}
  <h3>{{ tag }}</h3>
  <ul>
  {% for note in site.note %}
    {% if note.tags contains tag %}
    <li><a href="{{ site.baseurl }}{{ note.url }}">{{ note.title }}</a></li>
    {% endif %}
  {% endfor %}
  </ul>
{% endfor %}
Nolasco answered 2/5, 2016 at 9:39 Comment(0)
T
7

The tags assignment method mentioned in David Jacquel's answer can be simplified as:

{% assign tags =  site.note | map: 'tags' | uniq %}
Trope answered 19/10, 2017 at 10:11 Comment(0)
S
1

This is a very old question but if you are able use plugins (ie not github pages) as an alternative I created a short ruby filter to do this with less liquid in the pages.

module Jekyll
  module CollectionTags
    def process_tags(collection)
      tags_dict = {}

      collection.each do |item|
        if item.data['tags']
          item.data['tags'].each do |tag|
            tags_dict[tag] ||= []
            tags_dict[tag] << item
          end
        end
      end

      tags_dict.keys.sort.each_with_object({}) do |key, result|
        result[key] = tags_dict[key]
      end
    end
  end
end

Liquid::Template.register_filter(Jekyll::CollectionTags)

With that in your _plugins directory (as eg collection_tags.rb), you can basically access tags from collections the same way you would in posts, with the addition of one assign.

{% assign tags = site.some-collection | process_tags -%}
{% for tag in tags %}
  {{ tag[0] }}<br>
  {% for item in tag[1] %}
  - {{ item.title }}
  {% endfor -%}
{% endfor -%}

I'm not claiming it's vastly superior or anything, but I prefer not to do heavy lifting with liquid as I think it's ugly and likely slow. And I like that this is more consistent with how you'd handle posts. So I just offer this as another approach.

Seton answered 6/6, 2023 at 6:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.