light
light

Reputation: 51

Jeykll: Sorting files in _data subfolders by common property

I want to iterate over each file in _data/sections/, but have output sorted by data contained in said files (order property). The current output happens to be in the correct order, though I am not sure why, and the order does not change when modifying the sorted property.

The files are structured as follows:

// project/_data/sections/food.yml

title: Food
order: 2
content: "Food ipsum dolor sit amet."

-----

// project/_data/sections/drink.yml

title: Drink
order: 1
content: "Drink ipsum dolor sit amet."

Following the structure found on the Jekyll docs for data files, the for-loop code is as follows:

// project/index.html

// ...
{% for section_hash in site.data.sections | sort: 'order' %}
  {% assign section = section_hash[1] %}
  <p><strong>{{ section.title }}</strong> - {{ section.content }}</p>
{% endfor %}
// ...

I have also tried to sort the sections before passing them to the for-loop as seen here:

{% assign sections_sorted = sita.data.sections | sort: 'order' %}
{% for section in sections_sorted %}
  <p><strong>{{ section.title }}</strong> - {{ section.content }}</p>
{% endfor %}

Finally, I have tried to move the order property to the front-matter of each section file in _data/sections/, but that has resulted in the exception: Liquid Exception: no implicit conversion of String into Integer

// project/_data/sections/drink.yml
---
order: 1
---

title: Drink
content: "Drink ipsum dolor sit amet."

Is this possible with files in subdirectories of _data/? How can I sort the output of these files numerically by order, reverse-alphabetically by title, and so on?

Upvotes: 5

Views: 1364

Answers (4)

Matthias Bruns
Matthias Bruns

Reputation: 900

Even if this is pretty dated, I've run into the same problem. My solution was to provide a _index.xml which defined the order of e.g. projects.

We are in this folder: _data/projects

There are many files, e.g.

  • _index.yml
  • project_1.yml
  • project_2.yml
  • project_3.yml

The content of _index.yml looks like this:

- project_2
- project_1
- project_3

And the call to display your projects looks like this:

{% for project_id in site.data.projects["_index"] %}
{% assign project = site.data.projects[project_id] %} 
  // do something with the project
{% endfor %}

I hope this helps

Upvotes: 0

Steve C
Steve C

Reputation: 21

Your second example should work, but you have a typo: sita.data.sections should be site.data.sections.

{% assign sections_sorted = site.data.sections | sort: 'order' %}
{% for section in sections_sorted %}
  <p><strong>{{ section.title }}</strong> - {{ section.content }}</p>
{% endfor %}

Upvotes: 1

Vladimir Chervanev
Vladimir Chervanev

Reputation: 1652

Just faced the same issue. site.data.whateverfor folders is always Hash

{ file_name => file_content, ... }

Unfortunately Liquid arrays filters don't support hashes. To convert it to array the following filter can be used:

module Jekyll
  module ValuesFilter
    def values(input)
      case
        when input.instance_of?(Hash)
          input.values
        else
          input
      end
    end
  end
end

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

Put it into _plugins folders and use the next Liquid code:

{% assign ordered_items =(site.data.folder_name | sort | order: 'field') %}
{% for item in ordered_items %}
    {{ item.<property_name> }}
{% endfor %}

This code also works if folder_name points to a CSV file or an array inside JSON file.

Upvotes: 2

user4461099
user4461099

Reputation: 35

I'm not sure whether my problem is related to yours or not. I am trying to sort files in the _data directory, but my files are in a JSON format. No matter what I do, I receive this error message: jekyll 2.5.3 | Error: no implicit conversion of String into Integer. My JSON files do not contain any frontmatter at all. The error message tells me that Ruby tries to access an array by using a string, but expects an integer for any reason, e.g. my_array["blah"] instead of my_array[1]. This does not make much sense as sort:"blah" actually provides a string. Were you able to resolve this issue?

Concerning your first example:
{% for section_hash in site.data.sections | sort: 'order' %}
I don't think this works, I believe this is not implemented in Liquid. See this issue: https://github.com/Shopify/liquid/pull/304

But I cannot see why your second example does not work, maybe I misunderstand something here:
{% assign sections_sorted = sita.data.sections | sort: 'order' %}
Apparently, this should work from Jekyll 2.2.0 onwards, see this thread: Sorted navigation menu with Jekyll and Liquid

Upvotes: 0

Related Questions