How to group posts by date on home page in Jekyll? - ruby

In Jekyll, I would like my home page to list the most recent posts grouped by date, like so:
September 6, 2013
Post 1
Post 2
Post 3
September 5, 2013
Post 1
Post 2
Basically, I just want to spit out a date heading when a post in the loop is from a different date from the one previously processed. I've tried to do this by testing if the next post in the for loop matches the date of the last post, and to display a date header only if it doesn't. This is what my Liquid template looks like:
---
layout: default
title: Home Page
---
{% assign thedate = '' %}
{% for post in site.posts %}
{% if thedate != post.date | date: "%m-%d-%Y" %}
<h2>{{ post.date | date: "%A, %B %e, %Y" }}</h2>
{% endif %}
{% assign thedate = post.date | date: "%m-%d-%Y" %}
<h3 class="headline">{{ post.title }}</h3>
{{ post.content }}
<hr>
{% endfor %}
If instead of using post.date | date: "%m-%d-%Y" I instead say simply post.date it works, and posts are grouped together, but only if the posts have the exact same date and time (not just the same day of the month). That's why I add the more specific post.date | date: "%m-%d-%Y".
Any ideas? Thanks so much for our help!!

Found the answer by modifying the archives solution here: http://www.mitsake.net/2012/04/archives-in-jekyll/
Here is the code that works:
layout: default
title: Home Page
---
{% for post in site.posts %}
{% capture day %}{{ post.date | date: '%m%d%Y' }}{% endcapture %}
{% capture nday %}{{ post.next.date | date: '%m%d%Y' }}{% endcapture %}
{% if day != nday %}
<h5 class="date">{{ post.date | date: "%A, %B %e, %Y" }}</h5>
{% endif %}
{{ post.content }}
<hr>
{% endfor %}

These previous solutions are fantastic and elegant way to get around the shortcomings of previous versions of Jekyll but luckily in late 2016, Jekyll added a group_by_exp filter that can do this much more cleanly.
{% assign postsByDay =
site.posts | group_by_exp:"post", "post.date | date: '%A, %B %e, %Y'" %}
{% for day in postsByDay %}
<h1>{{ day.name }}</h1>
<ul>
{% for post in day.items %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endfor %}
Documentation can be found on the Jekyll Templates page.

Alternative solution:
Directly capture the date in the format that you want to display at the end.
(here: %A, %B %d, %Y --> Monday, April 30, 2012)
Then you don't need to use | date: that often:
{% for post in site.posts %}
{% capture currentdate %}{{post.date | date: "%A, %B %d, %Y"}}{% endcapture %}
{% if currentdate != thedate %}
<h2>{{ currentdate }}</h2>
{% capture thedate %}{{currentdate}}{% endcapture %}
{% endif %}
<h3>{{ post.title }}</h3>
{% endfor %}
The generated HTML:
<h2>Monday, April 30, 2012</h2>
<h3>Foo</h3>
<h2>Friday, March 09, 2012</h2>
<h3>Bar</h3>
<h3>Baz</h3>

Related

Why is my logic in my Liquid datetime comparison failing

so I'm making a little redirect on my Shopify website that runs on Liquid given that a customer doesn't have an active subscription-based upon a one day time requirement but every time the page loads, it seems to redirect anyway. expirationDate is the Order created_at plus 1 day. I just don't understand why the conditional expirationDate < today_date is forcing a redirect even when the expirationDate is further in time than the current date.
Values that show on the webpage:
expirationDate: January 29, 2020 05:12PM
today_date: January 28, 2020 06:49PM
{% capture expirationDate %} {{ ordercreatedat | date: '%s' | plus: 86400 | date: '%B %d, %Y %I:%M%p' }} {% endcapture %}
{% assign today_date = 'now' | date: '%B %d, %Y %I:%M%p' %}
<p>{{ expirationDate }}
<p>{{ today_date }}
{% if expirationDate < today_date %}
<script>
window.location = "google.com"
</script>
{% else %}
<div class="rte">
{{ page.content }}
</div>
{% endif %}

Jekyll custom date

I want use bellow code to display custom date in my Jekyll site
{% assign m = page.date | date: "%-m" %}
{% case m %}
{% when '1' %}Januar
{% when '2' %}Februar
{% when '3' %}März
{% when '4' %}April
{% when '5' %}Mai
{% when '6' %}Juni
{% when '7' %}Juli
{% when '8' %}August
{% when '9' %}September
{% when '10' %}Oktober
{% when '11' %}November
{% when '12' %}Dezember
{% endcase %}
But I don't now where to put it (I tried in post.html but does not work)
I've made a template for this.
This template translate a date in a specific language. Here it's french but feel free to change month and day arrays.
This template can be used in an enumeration of post/page (eg: the index page) or in a post/page template.
When used in an enumeration, you need to pass the date to process
{% for post in site.posts %}
<li>
<span class="post-date">{% include custom_date_full_fr.html date = post.date %}</span>
<a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
</li>
{% endfor %}
Where used in a page/post template, you just have to include the template, as the page.date will already be available.
{% include custom_date_full_fr.html %}
custom_date_full_fr.html
{% if include.date %}
{% assign processed_date = include.date %}
{% else if page.date %}
{% assign processed_date = page.date %}
{% endif %}
{% comment %}-------- Test if we have a date to process --------{% endcomment %}
{% if processed_date %}
{% assign month = "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre" | split: "," %}
{% comment %}------ Note : sunday is the first day in this array -------{% endcomment %}
{% assign day = "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi" | split: "," %}
{% assign month_index = processed_date | date: "%m" | minus: 1 %}
{%comment%}----------------------------------------------
Here **minus: 0** is a trick to convert day_index from string to integer and then use it as an array index.
----------------------------------------------{%endcomment%}
{% assign day_index = processed_date | date: "%w" | minus: 0 %}
{%comment%}-------- Output the date ----------{%endcomment%}
{{ day[day_index] }} {{ processed_date | date: "%d" }} {{ month[month_index] }} {{ processed_date | date: "%Y" }}
{% endif %}
See here for more info :
Jekyll Date Formatting Examples by Alan W. Smith
Liquid documentation - date filters

Shopify - sort array using liquid script with 2 criteria

This question is really close to Shopify Sort cart.items array using Liquid script
I have unsorted sessions that I want to sort by date and by time (expected result: 1,2,3,4).
{
"date"=>"2014-06-24",
"time"=>"09:00",
"name"=>"Session 2",
}
{
"date"=>"2014-06-25",
"time"=>"08:45",
"name"=>"Session 3",
}
{
"date"=>"2014-06-24",
"time"=>"08:00",
"name"=>"Session 1",
}
{
"date"=>"2014-06-25",
"time"=>"09:45",
"name"=>"Session 4",
}
Here's the code:
{% assign time_sorted_instances = instances | sort: "time" %}
{% assign day_sorted_instances = time_sorted_instances | sort: "date" %}
{% for instance in instances %}
{{ instance.date | date: "%A, %B %e, %Y" }} {{ instance.time }} {{ instance.session.name }} <br>
{% endfor %}
{% for instance in time_sorted_instances %}
{{ instance.date | date: "%A, %B %e, %Y" }} {{ instance.time }} {{ instance.session.name }} <br>
{% endfor %}
{% for instance in day_sorted_instances %}
{{ instance.date | date: "%A, %B %e, %Y" }} {{ instance.time }} {{ instance.session.name }} <br>
{% endfor %}
I'm able to get either instances sorted by date (2,1,3,4), or by time (1,3,2,4), but not sorted one after another (1,2,3,4). The matching function in ruby would be:
sorted_instances = instances.sort{|i| [i.date,i.time]}
Here's the code for the sort option in Liquid: https://github.com/Shopify/liquid/blob/master/lib/liquid/standardfilters.rb#L112-L123
And obviously it's not possible. If someone has a work around, let me know!
If using Javascript is an option, that could be an answer https://github.com/Shopify/liquid/issues/143#issuecomment-8718129
But I haven't found any Liquid only answer...

jekyll shared template different parameters

I am trying to share a single template in 2 other templates as follows:
_layouts/V2/post.slim
{% include V2/date_wrapper.html date_value=page.date %}
and
_includes/V2/footer/recent_posts.slim
| {% for post in site.posts limit: 5 %}
| <div class="w-bloglist-entry">
| <a class="w-bloglist-entry-link" href="{{ post.url }}">{{ post.title }}</a>
| <span class="w-bloglist-entry-date">
| <i class="fa fa-clock-o"></i>
| {% include V2/date_wrapper.html date_value=post.date %}
| </span>
| </div>
| {% endfor %}
This is the shared template:
_includes/V2/date_wrapper.html
{% assign d = include.date_value | date: "%-d" %}
{{ include.date_value | date: "%B" }}
{% case d %}
{% when '1' or '21' or '31' %}{{ d }}st,
{% when '2' or '22' %}{{ d }}nd,
{% when '3' or '23' %}{{ d }}rd,
{% else %}{{ d }}th,{% endcase %} {{ include.date_value | date: "%Y" }}
If I set this up using the template only in the post it works, however, no matter what I try I can not seem to get this to work in the footer in the for loop. The error is:
Liquid Exception: undefined method `data' for #<Jekyll::SlimPartialTag:0x007ffa549315b0> in _layouts/V2/post.slim
14:47:34 - ERROR - Jekyll build has failed
Thoughts? Is this possible in Jekyll?

Total number of posts?

I'm trying to figure out how to display the total number of posts in a category (or all together). I envision something like below, but can't quite figure it out. Did I miss something from the docs?
{% for post in site.categories.CAT %}
...do some counting
{% endfor %}
posts: {% number_of_posts %}
{% for post in site.categories.CAT %}
{{ post.title }}
{% endfor %}
# all posts
{{ site.posts | size }}
# posts in one category
{{ site.categories.CAT | size }}
{% for post in site.categories.CAT %}
{% capture post_count %} {{ post_count | plus: 1 }} {% endcapture %}
{% endfor %}
{{ post_count }}

Resources