How to filter posts by date, number of comments or number of words in a post?

Hello everyone, I want to make a filter for my messages.
I already made buttons for this:

<div id='sorters'>
Sort by:
<span id="by_date" onclick="sort_by_date();" class="sorter active">date</span>
|
<span id="by_comments" onclick="sort_by_comments();" class="sorter">comments</span>
|
<span id="by_length" onclick="sort_by_length();" class="sorter">length</span>
</div>

But I don’t know how to write JS functions to display posts for my parameters.
I tried to use a simple string replacement via the innerHTML function, but it doesn’t work because you just have to copy entire sections of code.

I know how to use Jekyll Filters, but I don’t know how to display them on a button. Please help me solve the problem

this is definitely a JS thing, there are probably multiple ways to do this. You can probably find an example of this type of thing just not with Jekyll, and then you just have jekyll output things like you need.

This is not a trivial thing, though it shouldn’t be too difficult. Not something one of us is likely to post a full working example of but who knows.

One idea is you can use jekyll to create a json file of all your posts, then you could use JS to display those and then you would be able to filter them easily I think.

As @rdyar points out, you are definitely heading into JavaScript territory. Here is a starter example I found on W3Schools to sort data on a page using tables. If you want to go this route, I suspect you will want to code your page in a very specific way with HTML which is easy enough to do with Jekyll. For JavaScript, I suspect Stack Overflow would be a better place to ask the question.

That said, you could start to run into problems with JavaScript if you have too many posts and start paginating the posts. For example, imagine having a web page load, say, 25 posts out of 100. The user has to click the next button to open the next 25 and so on. Now, JavaScript is not as useful because all the content is not on one page.

A way to handle this with Jekyll is to create multiple files, each one displaying the content by a defined sort. Here is a way to accomplish what you are looking for with reusable code.

:card_file_box: Create files that represent each sort order

In my example, I am going to put all my sorting options into a folder. If the user visits https://myjekyllsite.com/myposts, the index file displays. However, I could also link to https://myjekyllsite.com/myposts/bylength and get a list of posts sorted by the size of the content instead.

Create a folder under the root Jekyll folder and call it myposts and then add a file that represents each sort order, like this:

./myposts/index.html (displays the default Jekyll sort order)
./myposts/bydate.html (sorts oldest to newest)
./myposts/bylength.html (sorts from the shortest to the longest)

^^ Note, those could be markdown files instead of HTML

:wavy_dash: Custom YAML sortby element

Open each file and add the YAML front matter as listed below.

./myposts/index.html (no sortby)

---
layout: myposts
---
<p>Sort by Jekyll default

./myposts/bydate.html

---
layout: myposts
sortby: date
---
<p>Sort by date

./myposts/bylength.html

---
layout: myposts
sortby: length
---
Sort by length

:technologist: Create the myposts layout file

The files you just created will reuse the same exact layout, so you are just creating a holding place for the content. If you do not have a folder called _layouts in your Jekyll website folder, create it and then create a file called myposts.html as follows:

./_layouts/myposts.html

---
layout: default
---

{{content}}

{%- assign sortBy = page.sortby -%}
{%- case sortBy -%}
    {%- when "date" -%}
        {%- assign posts = site.posts | sort: 'date' -%}
    {%- when "length" -%}
        {%- assign posts = site.posts | sort: page.content.size -%}
    {%- else -%}
        {%- assign posts = site.posts -%}
{%- endcase -%}

<h2>List of posts</h2>
{% for post in posts %}
    <p></p><strong>{{post.title}} (length: {{post.content.size}}) / (date: {{post.date}})</strong>
{% endfor %}

With Jekyll running, visit each of those index.html, bydate.html, and bylength.html pages and you will notice they display the content using the same exact layout, but are sorted differently.

:page_facing_up: Code walkthrough

In the myposts.html layout file, you first get the sortby YAML front matter from the loading page (in our case, index.html, bydate.html, and bylength.html).

Next, you create a case statement that defines the list of posts you want, along with a filter that defines how you want them sorted. If there is no sortby, then the code uses Jekyll’s default sort order, which is typically newest->oldest. That is why I did not create a sortby in the index.html file. You can of course do whatever you want and add a sortby element to the index page if you want.

The last bit of code displays the lists of posts based on the sortby method you defined. In my example, I created some helper code to display the title of the post along with the length (content size) of each post and the date so you can verify the titles sort as you would expect.

:bulb: Tips

  • In the layout file, you should add some hrefs or buttons that link to the various sorting options.

  • You could move all that the code from {%- assign sortBy = page.sortby -%} to {%- endcase -%} into an include file in the ./_includes folder. That way you can re-use the code for something else.

  • I did not include an example for comments as you requested because I am unsure how you would want to handle that and Jekyll does not have built-in support for comments.

  • You can get fancy and provide multiple sort types (by date, by length, descending) in your YAML front matter, but that will of course add a lot more complexity.

  • You can create more pages with more YAML front matter, like sortby: lengthdescending and add more case statements for ascending and descending sort orders. Again, I suggest you move that case statement to an include file if the code gets too bulky.

  • When you sort with Liquid, it is usually smallest->greatest or alphabetical order. For example, in my code example, if you visit the bylength.html page, it will display the post with the least amount of content first. If you want to reverse that order, use the reverse filter, like this:
    {%- assign posts = site.posts | sort: page.content.size | reverse -%}

I hope this helps!

1 Like

Thanks so much Bill for such a comprehensive answer! It’s not the first time you’ve helped me, thank you very much

1 Like

No problem! I hope the solution works for you!