How do I get related posts in Jekyll to work? - jekyll

I wanted to modify the answer found here but it doesn't seem to be working for me as it just results in duplicate statements of "there are no related posts".
Originally, when there are no related posts, nothing is displayed and I wanted to change that. Again, at the moment, with the else statement I added, it just displays "there are no related posts" 3 times and I cant seem to figure out why.
Any help would be appreciated.
{% assign maxRelated = 0 %}
{% assign minCommonTags = 3 %}
{% assign maxRelatedCounter = 0 %}
{% for post in site.posts %}
{% assign sameTagCount = 0 %}
{% assign commonTags = '' %}
{% for tag in post.tags limit:1 %}
{% if post.url != page.url %}
{% if page.tags contains tag %}
{% assign sameTagCount = sameTagCount | plus: 1 %}
{{ post.title }}
<p>{{ post.excerpt | strip_html | truncatewords:80 }}</p>
{% assign commonTags = commonTags | append: tagmarkup %}
{% else %}
There are no related posts.
{% endif %}
{% endif %}
{% endfor %}
{% if sameTagCount >= minCommonTags %}
{% assign maxRelatedCounter = maxRelatedCounter | plus: 1 %}
{% if maxRelatedCounter >= maxRelated %}
{% break %}
{% endif %}
{% endif %}
{% endfor %}

In the linked answer there is no else block and no out put, it just generates commonTags.
{% for tag in post.tags %}
{% comment %}---> Only compare if post is
not same as current page {% endcomment %}
{% if post.url != page.url %}
{% if page.tags contains tag %}
{% assign sameTagCount = sameTagCount | plus: 1 %}
{% capture tagmarkup %} <span class="label label-default">{{ tag }}</span> {% endcapture %}
{% assign commonTags = commonTags | append: tagmarkup %}
{% endif %}
{% endif %}
{% endfor %}
Then it outputs a link as h5 in case sameTagCount is greater or equal minCommonTags.
{% if sameTagCount >= minCommonTags %}
<div>
<h5>{{ post.title }}{{ commonTags }}</h5>
</div>
...
In your case ìt outputs 'There are no related posts.' if the condition {% if page.tags contains tag %} is not true, which apparently happens three times.

Related

Unable to use concat on `nil`

I am trying to build a related post include file for my Jekyll site. The site is based around the concept of members, attractions and parks (each as collections). Each post has a many to many relationships. I am trying to up a combined array of each of the page attributes (members, attractions and parks) loop through the array and find posts with a common number of tags.
It's quite simple but I am getting stuck with one section, not all the posts have members, attractions and parks fields so they are returning nil but the concat filter requires an array. I am trying to default the variable to an [] but it always gets set to nil. Any ideas?
Here's the code:
<ul class="row">
{% assign pageTags = [] %}{% if page.tags.first %}{% assign pageTags = page.tags %}{% endif %}
{% assign pageAttractions = [] %}{% if page.attractions.first %}{% assign pageAttractions = page.attractions %}{% endif %}
{% assign pageMembers = [] %}{% if page.members.first %}{% assign pageMembers = page.members %}{% endif %}
{% assign pageParks = [] %}{% if page.parks.first %}{% assign pageParks = page.parks %}{% endif %}
{% assign pageTagList = pageTags | concat: pageAttractions | concat: pageMembers | concat: pageParks %}
{% for post in site.documents %}
{% assign sameTagCount = 0 %}
{% assign commonTags = '' %}
{% assign postTags = [] %}{% if post.tags %}{% assign postTags = post.tags %}{% endif %}
{% assign postAttractions = [] %}{% if post.attractions %}{% assign postAttractions = post.attractions %}{% endif %}
{% assign postMembers = [] %}{% if post.members %}{% assign postMembers = post.members %}{% endif %}
{% assign postParks = [] %}{% if post.parks %}{% assign postParks = post.parks %}{% endif %}
{% assign postTageList = postTags | concat: postAttractions | concat: postMembers | concat postParks %}
{% if post.hidden == true %}
{% break %}
{% endif %}
{% for tag in postTageList %}
{% if post.url != page.url %}
{% if pageTagList contains tag %}
{% assign sameTagCount = sameTagCount | plus: 1 %}
{% capture tagmarkup %} <span class="label label-default">{{ tag }}</span> {% endcapture %}
{% assign commonTags = commonTags | append: tagmarkup %}
{% endif %}
{% endif %}
{% endfor %}
{% if sameTagCount >= minCommonTags %}
<li class="col-lg-4 col-md-12">
<div class="main-image">
</div>
<h5>{{ post.categories | first }}</h5>
<h3>{{ post.title | replace: 'Review', '' }}</h3>
<p>
{% if post.description %}
{{ post.description }}
{% else %}
{{ post.content | markdownify | strip_html | truncatewords: 20 }}
{% endif %}
</p>
<p>
Read Article →
</p>
</li>
{% assign maxRelatedCounter = maxRelatedCounter | plus: 1 %}
{% if maxRelatedCounter >= maxRelated %}
{% break %}
{% endif %}
{% endif %}
{% endfor %}
</ul>
You can see the repo here: https://github.com/dtsn/jungleskipper/blob/feature/members/_includes/related-posts.html
From the Liquid documentation:
You cannot initialize arrays using only Liquid.
You can, however, use the split filter to break a string into an array of substrings.
You should look at compact which removes any nil values from an array.
Here is a link to the doc on shopify.
Example from Liquid documentation
Input:
{% assign site_categories = site.pages | map: "category" %}
{% for category in site_categories %}
- {{ category }}
{% endfor %}
Output:
- business
- celebrities
-
- lifestyle
- sports
-
- technology
With Compact
Input:
{% assign site_categories = site.pages | map: "category" | compact %}
{% for category in site_categories %}
- {{ category }}
{% endfor %}
Output:
- business
- celebrities
- lifestyle
- sports
- technology

Single Index Blog Post for Multiple Series Posts in Jekyll

I have several blog posts that fall under one umbrella blog post. For example, I have several posts about SQL Zoo tutorials, but I want to be able to link them all up to one "umbrella" post so that I only have one SQL Zoo post on the index page of my blog. I got this idea from: https://codeasashu.github.io/implement-series-post-jekyll-part-2/ and tried to follow the instructions, but now my series post does not show up on my index page. I have the following code in a file called post-series.html located in my _includes folder:
{% assign seriesarray = '|' | split : '|' %}
{% assign seriestitle = '' %}
{% assign serieslabel = '' %}
{% assign sortedposts = (site.posts | sort: 'date') %}
{% for post in sortedposts %}
{% if post.series and page.series_slug != nil and post.series == page.series_slug %}
{% capture postitem %} <li> {{ post.title }} </li> {% endcapture %}
{% assign seriesarray = seriesarray | push: postitem %}
{% assign seriestitle = 'Posts in this series' %}
{% assign serieslabel = 'Series Post' %}
{% elsif post.series != nil and page.series != nil and page.series == post.series %}
{% assign pageurl = page.url | split:'/' | last %}
{% assign posturl = post.url | split:'/' | last %}
{% if pageurl != posturl %}
{% capture postitem %} <li> {{ post.title }} </li> {% endcapture %}
{% else %}
{% capture postitem %} <li> {{ post.title }} </li> {% endcapture %}
{% endif %}
{% assign seriesarray = seriesarray | push: postitem %}
{% endif %}
{% if post.series_slug != nil and page.series != nil and page.series == post.series_slug %}
{% capture series_title %} {{ post.title }} {% endcapture %}
{% assign seriestitle = 'This posts is part of series - ' | append: series_title %}
{% assign serieslabel = 'This posts is part of series - ' | append: series_title %}
{% endif %}
{% endfor %}
{% capture serieslayout %}
{% if seriesarray.size > 0 %}
<hr />
<div class="panel">
<div class="panel-body">
<h4> {{ seriestitle }} </h4>
<ul id="post-series-list">
{% endif %}
{% for post in seriesarray %} {{ post }} {% endfor %}
{% if seriesarray.size > 0 %} </ul> </div> </div> {% endif %}
{% endcapture %}
and the following code from my index.html file in the root of my directory:
---
layout: index
---
<div id="home">
<h1>{{ site.title }}</h1>
<hr />
<ol class="posts">
{% for post in paginator.posts %}
{% assign seriesPost = nil %}
{% if post.series == nil %}
{% if post.series_slug != nil %} {% assign seriesPost = '(Series)' %} {% endif %}
<li class="post-listing">
<img class="post__image" src="/static/img/{{ post.cover_image}}" alt="{{ post.cover_alt }}" />
<div class="post__text">
<a class="post__title" href="{{ post.url }}">{{ post.title }}</a><br>
<span>
{{ post.date | date_to_string }} •
{% assign words = post.content | number_of_words %}
{% if words < 360 %}
1 min read
{% else %}
{{ words | divided_by:180 }} min read
{% endif %}
</span>
{{ post.excerpt }}
</div>
</li>
{% endif %}
{% endfor %}
</ol>
<!-- <div class="sidebar-right sidebar"></div> -->
<!-- <ul>
{% for post in paginator.posts %}
<li>
{{ post.title }}
{{ post.excerpt }}
</li>
{% endfor %}
</ul> -->
<!-- Pagination links -->
{% if paginator.total_pages > 1 %}
<ul class="pagination pagination-sm">
{% if paginator.previous_page %}
<li>«</li>
{% else %}
<li class="disabled"><span aria-hidden="true">«</span></li>
{% endif %}
<li>First</li>
{% for page in (1..paginator.total_pages) %}
{% if page == paginator.page %}
<li class="active"><a>{{ page }}<span class="sr-only">(current)</span></a></li>
{% elsif page == 1 %}
<li>{{ page }}</li>
{% else %}
<li>{{ page }}</li>
{% endif %}
{% endfor %}
<li>Last</li>
{% if paginator.next_page %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
</div><!-- end #home -->
My full repo can be found here: https://github.com/thedatasleuth/thedatasleuth.github.io
In your index.html, {% if post.series == nil %} simply bares posts containing a series: someserie front matter variable to be printed.
For the second problem (note that on SO, you are supposed to ask one question at a time) :
Umbrella post always have series_slug: "My serie slug" in front
matter.
Serie's posts always have series: "My serie slug" in front
matter, and this must be strictly equal to umbrella page series_slug. (eg : you have a post with published: false and series: "SQL Zoology" that will not appear in SQL Zoo serie if you publish it.)
In _layouts/post.html remove {% include series.html %}.
In _includes/post-series.html replace all your code by the following :
{% comment %} #### On an umbrella page {% endcomment %}
{% if page.series_slug != nil %}
{% assign key = page.series_slug %}
{% assign title = page.title %}
{% assign url = page.url %}
{% assign sentence = "All posts in this serie :" %}
{% endif %}
{% comment %} #### On a serie page {% endcomment %}
{% if page.series != nil %}
{% assign key = page.series %}
{% assign umbrella_page = site.posts | where: 'series_slug', key | first %}
{% assign title = umbrella_page.title %}
{% assign url = umbrella_page.url %}
{% assign series_posts = site.posts | where: "series", key %}
{% for post in series_posts %}
{% if post.url == page.url %}
{% assign idx = forloop.index %}
{% endif %}
{% endfor %}
{% capture sentence %}
This article is <strong>Part {{ idx }}</strong> in a <strong>{{ series_posts.size }}-Part</strong> in {{ title }} serie
{% endcapture %}
{% endif %}
{% if page.series_slug != nil or page.series != nil %}
{% assign series_posts = site.posts | where: "series", key %}
<hr />
<div class="panel">
<div class="panel-body">
{% if page.series_slug != nil %}
{% assign key = page.series_slug %}
{% assign title = page.title %}
{% assign url = page.url %}
{% endif %}
<h4>{{ sentence }}</h4>
<ul id="post-series-list">
{% for post in series_posts %}
<li>
{% if page.url == post.url %}
This post : {{ post.title }} - part {{ forloop.index }}
{% else %}
{{ post.title }} - part {{ forloop.index }}
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
The problem you are facing
You forgot to add the series and series_slug YML variables. That is why it is not working in your case. You seem to not fully understand how the code works, probably due to the complexity of the solution. Therefore, I added another (much simpler) solution, that might fit your needs equally well.
A better/simpler solution
Simply add a YML variable called group: groupname to each post you want in a group. Do NOT skip any of the posts during pagination. Next, list the posts with the same group on the footer of each post (in your page/post layout) with the code below. Finally, add 'part 1', 'part 2', etc. to the post names in the series.
{% if post.group != nil %}
<ul>
{% for post in site.posts %}
{% if post.group == page.group %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
PS. If you really want to skip some posts in the pagination, I would create an universal solution. Add a skip_pagination boolean to the Front Matter (YML) and see if it is true in the pagination loop. This enables you to skip any post in the paginator.

jekyll: check if there are no posts

How can I check if there are no posts in the _posts folder?
So far, I've tried
{% if site.posts == null %}
<p>No posts...yet.</p>
{% endif %}
and
{% if site.posts == nil %}
<p>No posts...yet.</p>
{% endif %}
Is this possible in Liquid?
Grab the size of the posts array and then compare that to 0:
{% assign psize = site.posts | size %}
{% if psize == 0 %}
<p>No posts...yet.</p>
{% endif %}
Here is a simpler approach.
{% if site.posts.size == 0 %}
<p>No posts...yet.</p>
{% endif %}

jekyll variables, if functions

Why is something like this not working ?
i try to filter all posts from this year
<div class="tiles">
{% for post in site.categories.articles %}
{% capture pubyear %} {{ post.date | date: "%Y" }} {% endcapture %}
{% if pubyear == "2014" %}
{% include post-grid.html %}
{% endif %}
{% endfor %}
</div><!-- /.tiles -->
The problem is that it is capturing the output with some spaces in it, so it fails the if condition, remove those spaces and it should work
<div class="tiles">
{% for post in site.categories.articles %}
{% capture pubyear %}{{ post.date | date: "%Y" }}{% endcapture %}
{% if pubyear == "2014" %}
{% include post-grid.html %}
{% endif %}
{% endfor %}
</div>
Capturing the pubyear is vaild but you can also assign pubyear with no spaces.
{% assign pubyear = post.date | date: "%Y" %}

Jekyll - Liquid Templating - Exclude a Category from Widget

I am attempting to rebuild a sidebar widget which shows my categories used in Jekyll. It works fine as it is now. I want to change the liquid templating to exclude one specific category link from being shown in this widget.
{% assign cat_list = site.categories %}
{% if cat_list.first[0] == null %}
{% for category in cat_list %}
<li>{{ category }} <span class="cat-count">{{ cat_list[category].size }}</span></li>
{% endfor %}
{% else %}
{% for category in cat_list %}
<li>{{ category[0] }} <span class="cat-count">{{ category[1].size }}</span></li>
{% endfor %}
{% endif %}
{% assign cat_list = nil %}
I think what I want is something like
{% for category in cat_list **UNLESS category = 'CATEGORY'** %}
But that did not work. I'm kinda stuck, is this possible?
Thank You.
Not displayed categories array :
{% assign noDisplay = "one,two,three" | split: "," %} => ["one", "two", "three"]
The test :
{% unless noDisplay contains category[0] %}
{{ category[0] }}...
{% endunless %}
Thank you, #David Jacquel
{% assign noDisplay = "CATEGORY" | split: "," %}
{% assign cat_list = site.categories %}
{% if cat_list.first[0] == null %}
{% for category in cat_list %}
<li>{{ category }} <span class="cat-count">{{ cat_list[category].size }}</span></li>
{% endfor %}
{% else %}
{% for category in cat_list %}
{% unless noDisplay contains category[0] %}
<li>{{ category[0] }} <span class="cat-count">{{ category[1].size }}</span></li>
{% endunless %}
{% endfor %}
{% endif %}
{% assign cat_list = nil %}