hbrls
hbrls

Reputation: 2150

how to get a sorted tags_list in jekyll

I'm using jekyll-bootstrap to maintain a blog on GitHub.

I'd like to have a sorted tags_list. The tag with the most posts comes first. Then I can have a display that shows the first tags with bigger font-size and last tags with smaller font-size. And I also want a splice function.

If in python/Jinja2, I'd like some code like this:

{% for tag in sorted_tags[:10] %}
  <li style="font-size:{{ tag.count }}px;">{{ tag.name }}</li>
{% endfor %}

What's the equivalent implementation in ruby/jekyll?

Upvotes: 7

Views: 2087

Answers (4)

Thomas
Thomas

Reputation: 182000

This is how I'm sorting by the number of posts in a tag (descending), without any plugins (i.e. GitHub Pages compatible).

It also works when your tag names contain spaces; only , and : are forbidden characters (but you can easily change those).

{% capture counts_with_tags_string %}{% for tag in site.tags %}{{ tag[1] | size | prepend:"000000" | slice:-6,6 }}:{{ tag[0] }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %}
{% assign counts_with_tags = counts_with_tags_string | split:"," | sort | reverse %}

<ol>
  {% for count_with_tag in counts_with_tags %}
    {% assign tag = count_with_tag | split:":" | last %}
    {% assign count = site.tags[tag] | size %}
    <li><a href="/blog/tags/{{ tag | slugify }}">{{ tag }} ({{ count }})</a></li>
  {% endfor %}
</ol>

It's super gross. What it does:

  • counts_with_tags_string is set to a string like 000005:first_tag,000010:second_tag,000002:third_tag. The zero-padded numbers are generated using the filter chain | prepend:"000000" | slice:-6,6.
  • This is split on commas and sorted lexicographically, which works because of the zero padding. The result is assigned to counts_with_tags.
  • Finally, we iterate over the elements and split each on : to find the original tag name. We could find the count in the same way, but because it's zero padded, it's easier to look it up using site.tags[tag] | size instead.

Upvotes: 3

Kelsin
Kelsin

Reputation: 833

I'm hosting my blog on github and wanted a solution to sorting a tag list that did not involve any jekyll plugins since Github doesn't allow for custom plugins (jekyll bootstrap attempts this as well). My post here doesn't really answer the question since I sort by tag name, and NOT by size. You can adapt this method to output the tag size as well in the string and then do some fancier spliting to get a different sort order (but it will be messy)

I was able to do this with the following code:

{% capture tagString %}{% for tag in site.tags %}{{ tag[0] }}{% unless forloop.last %}|{% endunless %}{% endfor %}{% endcapture %}
{% assign tags = tagString | split: '|' | sort: 'downcase' %}
<div id="cloud">
  {% for tag in tags %}
  {% assign number = site.tags[tag].size %}
  {% assign slug = tag | downcase | replace: ' ', '_' %}
  <span class="{% if number == 1 %}small{% elsif number <= 5 %}medium{% elsif number <= 10 %}large{% else %}huge{% endif %}">
    <a href="#tag-{{ slug }}">{{ tag | downcase }}</a>
  </span>
  {% endfor %}
</div>

It's kind of odd since I capture a string of tags (using | as separator) and then use that to create an array. After that point (in the loop) I can refer to the tag as tag and the list of sites that use that tag as site.tags[tag].

I use this on my blog: https://github.com/kelsin/kelsin.github.io/blob/master/tags/index.html

The rest of the code is just how I've chosen to make a tag cloud on my tag page. Hope this helps someone else looking for a solution (without plugins)!

Upvotes: 0

John Kary
John Kary

Reputation: 7242

I only needed to do this in one place, on the page where my list of Tags was listed, so I wrote it as a Jekyll filter:

tag_index.html

<h2>Posts by Tag</h2>

<ul class="tags-list">
  {{ site.tags | render_tags_list }}
</ul>

_plugins/filters.rb

module Jekyll
  module Filters
    def render_tags_list(tags)
      sorted_tags = tags.keys.sort_by! { |tag| tag.downcase }

      str = ''
      sorted_tags.each { |tag|
        str << '<li>' + tags[tag].size.to_s + ' - <a href="/tag/' + tag + '">' + tag + '</a></li>'
      }

      str
    end
  end
end

You could certainly just allow the filter to return sorted_tags above if you wanted to keep a better separation between "view" logic and programming logic, but my case was very simple. Trying to re-access a hash value by a specific key using Liquid templating wasn't a very concise process, or maybe I was just doing it wrong, but was much easier in Ruby.

Upvotes: 0

heliotrope
heliotrope

Reputation: 1001

I thought that the tags array is sorted. Assuming so, you can do this:

{% for tag in site.tags %}
    <li style="font-size: {{ tag[1].size }}px">{{ tag[0] }}</li>
{% endfor %}

That feels a little hacky, but it should work. Unfortunately, Liquid doesn't currently allow you to sort arrays within your templates. If you want to do any sorting on the array, you'd probably have to write a plugin to do so - it shouldn't be too complex. In fact, there's an existing plugin for sorting accessors that may do it: https://github.com/krazykylep/Jekyll-Sort

Upvotes: 0

Related Questions