问题
For a simple personal Jekyll blog, I want to group my site.posts
by an attribute on post
, lang (language). This is either "en", "nl" or nil.
I then want to render two lists of posts. Currently I have:
<section lang="nl">
<h2>Nederlandse Artikelen</h2>
<ul class="posts">
{% for post in site.posts limit:50 %}
{% if post.lang == "nl" %}
{% include li_for_post_with_date.yml %}
{% endif %}
{% endfor %}
</ul>
<a href="archief.html">Archief »</a>
</section>
<section lang="en">
<h2>English Articles</h2>
<ul class="posts">
{% for post in site.posts limit:50 %}
{% if post.lang == nil or post.lang == "en" %}
<li><span>{{ post.date | date_to_string }}</span> » <a href="{{ BASE_PATH }}{{ post.url }}">{{ post.title }}</a></li>
{% endif %}
{% endfor %}
</ul>
This has two problems:
- Most annoying; when in the last 50 posts, there are 47 lang=en and 3 lang=nl, I now get a skewed list. I would want 25 lang=en and 25 lang=nl entries.
- The loop is walked over twice, this strikes me as inneficient.
Is there a way to assign or prepare a collection in Liquid? That way I could loop over site.posts
once and prepare a nested collection like site.grouped_posts[en]
.
Or another trick?
Solution
As Tom Clarkson points out, maintaining a counter is the right direction. However, incrementing a counter has only landed in recent Liquid versions, the one running on Github (where my liquid is compiled) has 2.2.2, without ability to increment a counter. Toms solution itself is not working either, because Liquid turns the variable counter
into a string, which cannot be compared with <
.
I created a hack, by appending a string and counting the characters.
{% assign counter = '.' %}
{% for post in site.posts %}
{% if counter.size <= 25 and post.lang == "nl" %}
{% capture counter %}{{ counter | append:'.' }}{% endcapture %}
{% include li_for_post_with_date.yml %}
{% endif %}
{% endfor %}
As said, ugly, so if there are cleaner solutions, please add a solution!
回答1:
I don't think you can create the filtered collection without making a plugin or custom filter, but you may be able to count the number of posts already collected for the group rather than using limit.
{% for post in site.posts %}
{% if counter < 25 and post.lang == nil or post.lang == "en" %}
{% capture counter %}{{ counter | plus:1 }}{% endcapture %}
<li></li>
{% endif %}
{% endfor %}
The code is untested, but something fairly similar should work.
回答2:
Unfortunately, Liquid's filters dont't work in for
loops. However, they do work in variable assignments.
{% assign posts_by_lang = site.posts | group_by: "lang" %}
{% for lang in posts_by_lang %}
{{ lang.name }}
{% for post in lang.items limit: 25 %}
{{ post.title }}
{% endfor %}
{% endfor %}
name
and items
attributes are generated by group_by
, the rest is business as usual.
来源:https://stackoverflow.com/questions/13568052/filter-or-group-a-collection-in-liquid