I am grouping the posts on my site using this liquid tag.
{% assign postsForYear = site.posts | group_by_exp:"post", "post.date | date: '%Y'" | where: "name", "2020" %}
When I echo the postForYear out to screen, I see this:
{"name"=>"2020", "items"=>[#, #, #, #, #, #], "size"=>6} 0
Which makes sense, as I have six posts for that year. However, I am trying to dereference that object and get the .size property, which I can see in the output...I can't figure out the syntax!
How to get the .Size property?
None of these work.
{{ postsForYear.size }}
{{ postsForYear.items | size }}
After that, I would love to learn how to foreach my way through the posts...this also seems simple but doesn't work!
Ah, I figured it out. Strangely, the postsForYear array was actually treated like an array itself, so I had to index into the first position to get to the properties.
{% assign postsForYear = site.posts |
group_by_exp:"post", "post.date | date: '%Y'" | where: "name", "2020" %}
###doesn't work
{{ postsForYear.items | size }}
### does work
{{ postsForYear[0].items | size }}
### example
Posts for year {{ postsForYear[0].name }}, total posts {{ postsForYear[0].size }}
>Posts for year 2020, total posts 6
And to answer my other question, how to foreach your way through:
{% for post in postsForYear[0].items %}
<h1>{{post.title}}</h1><br>
{% endfor %}
Related
I am attempting to create a related posts section. I have used loops and conditionals to achieve this before, but I wanted a more efficient and cleaner method. I used include variables to achieve a similar result, but for whatever reason if I attempt to use a post's front matter, I get an empty result. Example:
---
categories:
- Featured
---
{% assign featured-posts = site.posts | where: "categories", page.categories %}
{% assign featured-posts = site.posts | where: "categories", page.categories %}
where filter looks for a string in a string or in an array.
Here page.categories is an array to look for in an array. This will return an empty array.
My shortest way to get related posts with at least one common category.
{% assign related-posts = "" | split: "" %}
{% for c in page.categories %}
{% assign related-posts = related-posts | concat: site.categories[c] | uniq %}
{% endfor %}
jekyll 2.4.0, Mac 10.12.5
{% for year_of_interest in (1997..2017) reversed %}
<large_year>{{year_of_interest}}</large_year>
{% for paper in site.data.publications | where,'site.data.publications.Year',year_of_interest %}
<div class="publication_card">
<a class="article_title" href="../../{{paper.Link}}" title="{{paper.Abstract}}">{{paper.Title}}</a>
</div>
<div class="paper_author_container">
<span class="paper_authors">{{paper.Author | upcase}}</span>
<br>
<span class="journal_info">{{paper.Year}}—{{paper.Journal | upcase}}</span>
<button class="btn" data-clipboard-text="{{paper.BibTex}}">
BIBTEX
</button>
</div>
{% endfor %}
{% endfor %}
The input CSV has this shape and the Year is a simple number:
Title,Link,Abstract,Author,BibTex,Year,Journal,SupplementalLink
background: I'm stuck! I have a CSV where each row represents publication metadata for papers from 1997 to 2016. Some years have many papers, but each year has at least 1 publication. I want a header for each year, and the publications to be posted below. Unfortunately, the where filter does not find any of the articles for a given year in the for loop.
Current functionality: under each header, it shows a list of ALL publications.
Desired: it should only show publications where the paper.Year == year_of_interest.
Thanks in advance!
Three problems here :
You can't filter in a loop
{% for paper in site.data.publications | where,'site.data.publications.Year', year_of_interest %}
Will not work as expected because it always returns all datas.
{% assign filtered = site.data.publications | where,'site.data.publications.Year', year_of_interest %}
{% for paper in filtered %}
Will work, but not now ...
Where filter filters on a key
It's not {% site.data.publications | where,'site.data.publications.Year', year_of_interest %}
but : {% site.data.publications | where,'Year', year_of_interest%}}
Nearly working ...
CSV datas are strings
{{ site.data.publications[0].Year | inspect }} returns "1987" and double quotes around signifies that its a string and that your filter, looking for an integer as "Year" value will never find it. You have to look for a string instead.
To cast an integer into a string you can append an empty string to it.
{% for year_of_interest in (1997..2017) reversed %}
{% comment %} casting an integer to a string {% endcomment %}
{% assign yearAsString = year_of_interest | append:"" %}
{% comment %} filtering datas {% endcomment %}
{% assign selectedEntries = site.data.publications | where: "Year", yearAsString %}
{% for paper in selectedEntries %}
Now, it does the job.
Notes :
1 - Use the | inspect filter to debug, it's useful to determine type of value (string, integer, array, hash).
2 - You can also cast a string to an integer by adding zero to it :
{% assign numberAsString = "1997" %}
{{ numberAsString | inspect }} => "1997"
{% assign numberAsInteger = numberAsString | plus: 0 %}
{{ numberAsInteger | inspect }} => 1997
This is the only documentation for the where filter because it is not a default liquid filter.
https://gist.github.com/smutnyleszek/9803727
site.data.publication.Year is an object of site.data.publications I believe you only need to specify "Year" This is case sensitive by the way.
{% for paper in site.data.publications | where, "Year", year_of_interest %}
I have a collection in Jekyll which I want to sort. Sorting by title is easy of course.
<ul>
{% for note in site.note | sort: "title" %}
<li>{{note.path | git_mod }}: {{ note. title }}</li>
{% endfor %}
</ul>
I want to sort by date. But since collections don't have a date, I have a custom Liquid filter which takes the path of the item, and gets its last modified time in Git. You can see that in the code above, where I pass the path to git_mod. I can verify that this works, because when I print out the list, I get the correct last modified times, and it is a full date. (In practice, I also pass it to date_as_string.)
But I can't sort by that value because Liquid doesn't know about it, since it is a value already in each item in the site.note collection. How can I sort by that value? I was thinking something like this, but it doesn't work:
<ul>
{% for note in site.note | sort: path | date_mod %}
<li>{{note.path | git_mod }}: {{ note. title }}</li>
{% endfor %}
</ul>
I've also tried variants like: {% for note in site.note | sort: (note.path | git_mod) %}
None of these throw an error, but none of them work either.
This is a case where you can use Jekyll hooks.
You can create a _plugins/git_mod.rb
Jekyll::Hooks.register :documents, :pre_render do |document, payload|
# as posts are also a collection only search Note collection
isNote = document.collection.label == 'note'
# compute anything here
git_mod = ...
# inject your value in dacument's data
document.data['git_mod'] = git_mod
end
You then will be able to sort by git_mod key
{% assign sortedNotes = site.note | sort: 'git_mod' %}
{% for note in sortedNotes %}
....
Note that you cannot sort in a for loop. You first need to sort in an assign, then loop.
So if the date is in the frontmatter, Can Jekyll use this data to order posts??
Could you have multiple ways of ordering post based on whats in the frontmatter???
{% assign sortedPosts = site.post | sort: 'date' %}
or
{% assign sortedPosts = site.posts | sort: 'anyFrontMatterVariable' %}
you can now loop like {% for post in sortedPosts %}
...
Note : Sorting in the loop like {% for post in site.posts | sort: 'date' %}doesn't work
Beside date there is a way of ordering post based on whats in the YAML Front Matter
Add weight in the YAML Front Matter of your posts
post #1
---
...
weight: 1
---
post #2
---
...
weight: 2
---
Then sort them like this:
{% assign posts = site.posts | sort: 'weight' %}
{% for post in posts %}
..your code
{% endfor %}
I'd like to convert the printed category names of my posts into title case. I couldn't find a Liquid filter that would work. I tried using dashes and the camelcase filter, but no dice.
Alternatively, I'd like to print the category name as it's written in the YAML frontmatter.
For instance, for a post with:
category: Here's the Category
When I reference the name:
{% for cat in site.categories %}
<h1>{{ cat[0] }}</h1>
{% endfor %}
I see "here's the category" on the page. I would like to see "Here's the Category" or even "Here's The Category," and I could replace (replace: 'The', 'the') the few articles that I wanted to be downcase.
EDIT
For anyone as desperate as I am, this disgusting hack works, where n is the max number of words you have in a category title.
{% for cat in site.categories %}
{% assign words = cat[0] | split: ' ' %}
<h1>{{ words[0] | capitalize | replace:'The','the'}} {{ words[1] | capitalize }} {{ words[2] }} {{ words[3] | capitalize }} {{ words[4] | capitalize }} {{ words[n] | capitalize }}</h1>
{% endfor %}
I'm going to leave the question unanswered in case someone knows a more elegant method.
You can achieve a part of what you want by using the capitalize filter:
Input
{{ 'capitalize me' | capitalize }}
Output
Capitalize me
Source.
Another possibility, which I didn't test for its edge cases, is to use join and camelize:
{{ "here's the category" | join: '-' | camelize }}
It should print "Here's The Category", but camelize might have a problem with here's.
Just use {{ category.first | capitalize }} is OK for my case, without additional '' on category.
Instead of manually stepping through words 0 to n, one can use another for loop as follows:
{% for category in site.categories %}
{% assign words = category | first | split: ' ' %}
{% for word in words %}
{{ word | capitalize | replace: 'The','the' }}
{% endfor %}
{% endfor %}
I know that this is old but it helped me to solve my problem and it could help others.
The solution I came was:
{% for category in site.categories %}
<a href="/{{category[0] | slugify }}/">
{{category[0]}}
</a>
{% endfor %}
This list all the blog categories (most used for building a menu)
It turns into:
<a href="/dicas/">
Dicas
</a>
<a href="/diário-de-bordo/">
Diário de bordo
</a>
Thank you for giving me a clue.
You can check another filters in: http://jekyllrb.com/docs/templates/#filters
Name pages in Kabab-case as you want them to appear, then use replace:
{{ category.name | replace: '-', ' '}}
Don't-Capitalize-the becomes Don't Capitalize the and Capitalize-The becomes Capitalize The
This solutions is a little more overwrought, but you can adapt the author data file solution from the Jekyll site to work with categories.
In your _data folder, make a file called categories.yml. Put in something like this:
my-first-category:
name: My First Category
another-category:
name: Another Category
Then, you can loop through your categories like this:
{% for category in site.categories %}
{% assign category_slug = category[0] %}
{% assign category_data = site.data.categories[category_slug] %}
{% if category_data %}
{{ category_data.name }}
{% endif %}
{% endfor %}
Side note: I'm not sure why I needed the category_slug assign. I didn't need it when looping through post.categories.
This increases overhead by adding an extra file, but opens the door for other data that can get attached to objects like a category image or description. You can be more granular over your names. This is a pretty readable solution too, which is nice.
I went the other way around. I hard coded my page title in Title case and use downcase, upcase and capitalize liquid filter in other pages.