Output Markup Inside of Tag Markup - jekyll

My question is how can I rewrite this output markup (which does work)
{{ forloop.index0 | modulo:4 }}
so that it can be used inside of a tag markup (which doesn't work).
{% if forloop.index0 | modulo:4 == 0 %}

This is what ended up working (David helped me get started).
{% assign mod = forloop.index0 | modulo:4 %}
{% if mod == 0 %}
<!-- Do stuff -->
{% endif %}

Edited answer :
For this example I use a custom array, but the array can be site.pages or site.posts or site.data.somedatas.
{% assign words = "zero,one,two,three,four,five" | split: ',' %}
Then process the words array :
<ol>
{% for word in words %}
{% comment %} Here we assign the filtered array to myTest {% endcomment %}
{% assign myTest = forloop.index0 | modulo:4 %}
{% comment %} then we process the filtered array {% endcomment %}
{% if myTest == 0 %}
<li>
<h4>Test passing (index = {{ forloop.index0 }} >> modulo = {{ myTest }})</h4>
</li>
{% else %}
<li>
<h4>test NOT passing (index = {{ forloop.index0 }} >> modulo = {{ myTest }})</h4>
</li>
{% endif %}
{% endfor %}
</ol>
This works on Jekyll 2.2.0, the current Github pages version.

Related

Jekyll liquid syntax for loading _data subfolders for Staticman comments?

I’m trying to set up staticman comments and have gotten all the code implemented to save comments correctly, but the comments are not loading.
My site has multiple types of pages so I have recipe comments save in _data/comments/recipes/recipe-name/entry12233445430320.yml
The problem is in this code:
{% assign urlslug = page.url | remove:'.html' | remove_first:'/' | split: '/' %}
{% assign urlfolder = urlslug[0] %}
{% assign urlfilename = urlslug[1] %}
<p>folder: {{urlfolder}}</p><p>filename: {{urlfilename}}</p>
<h2>{{post_slug}}</h2>
{% if site.data.comments.recipes[urlfilename] %}
<!-- Start static comments -->
<div id="comments" class="js-comments">
<h2 class="page__section-label">
{% if site.data.comments.recipes[urlfilename].size > 1 %}
{{ site.data.comments.recipes[urlfilename] | size }}
{% endif %}
Comments test 1
</h2>
<h2> {{ site.data.comments.recipes[urlfilename] }} </h2>
{% assign comments = site.data.comments.recipes[urlfilename] | sort | where_exp: 'entry', 'comment[1].replying_to_uid == blank' %}
<h3>a: {{ comments }} </h3>
<h3>b: {{ comments[0] }} </h3>
{% for comment in comments %}
<h3>comment test 2</h3>
{% assign index = forloop.index %}
<!-- {% assign replying_to = comment[1].replying_to | to_integer %}
{% assign avatar = comment[1].avatar %} -->
{% assign email = comment[1].email %}
{% assign name = comment[1].name %}
{% assign url = comment[1].url %}
{% assign date = comment[1].date %}
{% assign message = comment[1].message %}
{%- assign uid = comment[1]._id %}
{% include comment.html index=index replying_to=replying_to avatar=avatar email=email name=name url=url date=date message=message %}
{% endfor %}
</div>
<!-- End static comments -->
{% endif %}
I'm successfully accessing the right comment and printing it on the page in raw format, but I can't make it print the comment correctly.
Any help is greatly appreciated.

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.

How to use Jekyll to sort posts by a custom YAML front matter variable?

I'm trying to create a page in my Jekyll site that will display a custom variable and list the posts that contain that custom variable.
I have created a movie review blog using a template Thiago Rossener created:
Thiago's Template: https://github.com/thiagorossener/jekflix-template
My Site: https://www.howdareyoureview.com/
in each post, I have defined custom variables in the YAML front matter that relate to the movie's details (i.e actor, director score, etc.)
for example:
---
layout: post
title: "Baby Driver"
image: 'https://res.cloudinary.com/how-dare-you-review/image/upload/c_fill,h_399,w_760/v1529865791/baby-driver.png'
tags:
- action
score: 72
director: Edgar Wright
written-by: Edgar Wright
staring:
- Ansel Elgort
- Lily James
- Eiza González
- Jon Hamm
- Jamie Foxx
---
I want to create pages exactly like the tags page that already exists in this template:
https://www.howdareyoureview.com/tags/
except I would want to sort by director, starring, etc. instead of by tags.
the tags page is created using the following code in a tags.html file:
---
layout: minimal
title: "#Tags"
permalink: /tags/index.html
description: "Procure por sua #tag favorita."
---
<div class="tags">
{% assign tags_list = site.tags %}
{% if tags_list.first[0] == null %}
{% for tag in tags_list %}
{{ tag }}
{% endfor %}
{% else %}
{% for tag in tags_list %}
{{ tag[0] }}
{% endfor %}
{% endif %}
{% assign tags_list = nil %}
</div>
{% for tag in site.tags %}
<div class="tag-wrapper">
<span class="tag-title" id="{{ tag[0] | slugify }}">{{ tag[0] }}</span>
<ul class="post-list">
{% assign pages_list = tag[1] %}
{% for post in pages_list reversed %}
{% if post.title != null %}
{% if group == null or group == post.group %}
<li>{{ post.title }}<span class="entry-date"><time datetime="{{ post.date | date_to_xmlschema }}" itemprop="datePublished">{{ post.date | date: "%m/%d/%Y" }}</time></li>
{% endif %}
{% endif %}
{% endfor %}
{% assign pages_list = nil %}
{% assign group = nil %}
</ul>
</span>
</div>
{% endfor %}
To achieve this for the custom variables I created I tried replacing "tag/tags" with director and saving the file out into to root directory as "directors.html" but the page is blank.
---
layout: minimal
title: "#Directors"
permalink: /directors/index.html
description: "Procure por sua director favorita."
---
<div class="directors">
{% assign directors_list = site.director %}
{% if directors_list.first[0] == null %}
{% for director in directors_list %}
{{ director }}
{% endfor %}
{% else %}
{% for director in directors_list %}
{{ director[0] }}
{% endfor %}
{% endif %}
{% assign directors_list = nil %}
</div>
{% for director in site.director %}
<div class="director-wrapper">
<span class="director-title" id="{{ tag[0] | slugify }}">{{ director[0] }}</span>
<ul class="post-list">
{% assign pages_list = director[1] %}
{% for post in pages_list reversed %}
{% if post.title != null %}
{% if group == null or group == post.group %}
<li>{{ post.title }}<span class="entry-date"><time datetime="{{ post.date | date_to_xmlschema }}" itemprop="datePublished">{{ post.date | date: "%m/%d/%Y" }}</time></li>
{% endif %}
{% endif %}
{% endfor %}
{% assign pages_list = nil %}
{% assign group = nil %}
</ul>
</span>
</div>
{% endfor %}
Since the code and the concept is exactly the same as the way tags are populated - I cannot understand why this doesn't work - I'm hoping someone can assist!
Here is my entire directory for reference:
https://github.com/howdareyoureview/howdareyoureview.github.io
Tags page uses site.tags, which is an array of site.posts grouped by tag, created by Jekyll at generation time.
You're trying to replicate by targeting site.directors but this expected array doesn't exist. But, you can use the group_by filter to achieve your goal.
<div class="directors">
{% assign directors = site.posts | group_by: 'director' | sort: "name" %}
{% for director in directors %}
{% if director.name == "" %}
{% assign name = "Anonymous" %}
{% else %}
{% assign name = director.name %}
{% endif %}
{{ name }}
{% endfor %}
</div>
{% for director in directors %}
<div class="director-wrapper">
{% if director.name == "" %}
{% assign name = "Anonymous" %}
{% else %}
{% assign name = director.name %}
{% endif %}
<span class="director-title" id="{{ name | slugify }}">{{ name | debug }}</span>
<ul class="post-list">
{% assign pages_list = director.items %}
{% for post in pages_list reversed %}
<li>{{ post.title }}<span class="entry-date"><time datetime="{{ post.date | date_to_xmlschema }}" itemprop="datePublished">{{ post.date | date: "%m/%d/%Y" }}</time></li>
{% endfor %}
</ul>
</span>
</div>
{% endfor %}
Tip : You can use the inspect filter to debug your vars. {{ myvar | inspect }}

How to set up related collection items rather than related posts in Jekyll?

I've successfully implemented related posts in my site by using site.related_posts with the following Liquid templating:
The code bellow returns 4 posts related by tags on every post page, so far so good, but what's the best approach to achieve something like this for Jekyll collections?
{% assign hasSimilar = '' %}
{% for post in site.related_posts %}
{% assign postHasSimilar = false %}
{% for tag in post.tags %}
{% for thisTag in page.tags %}
{% if postHasSimilar == false and hasSimilar.size < 4 and post != page and tag == thisTag %}
{% if hasSimilar.size == 0 %}
{% endif %}
<a href="{{ site.baseurl }}{{ post.url }}" class="entry">
<div class="entry-media">
<img src="{{ post.thumbnail | prepend: site.baseurl }}" alt="">
<p class="post-cat">{% for category in post.categories.last %}{{ category }}{% endfor %}</p>
</div>
<h6 class="entry-title">{{ post.title | truncatewords: 70, '...' }}</h6>
<p class="post-date">{{ post.date | date: "%d/%m/%Y" }}</p>{% if post.series %}(Series: {{ post.series }}){% endif %}
</a>
{% capture hasSimilar %}{{ hasSimilar }}*{% endcapture %}
{% assign postHasSimilar = true %}{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% if hasSimilar.size > 0 %}
{% endif %}
As per Jekyll's documentation, when you create a collection it becomes available via the site Liquid variable, much like site.pages and site.posts, so in order to create a related collection items for my portfolio collection I replicated the Liquid logic above and assigned site.portfolio as posts, see:
{% assign posts = site.portfolio | sort: "tags" %}
So I set tags: [tag1, tag2, tag3] on every "project.md" document's front-matter within my _portfolio collectionas, as I'd normally do with posts and the liquid logic above returns the related portfolio collection items.
Anyway, although I'm not sure if this is the right path to achieve such functionality, it works as intended. I couldn't find any references/ usage for site.related_posts when it come to collections.
I'd really appreciate any thoughts regarding this issue. Thanks in advance.
site.related_posts are the ten most recent posts.
So, your code is only looking for related in ten posts not all posts.
The following code will looks for tags related items for site.posts or any site.collection
{% assign pageTagsNumber = page.tags | size %}
{% assign related = "" | split: "/" %}<!-- create empty array -->
{% assign relatedCount = 0 %}
{% assign maxRelated = 4 %}<!-- maximum number of related items -->
{% assign minTagMatch = 4 %}<!-- minimum number of tag match to be a related -->
{% if minTagMatch > pageTagsNumber %}
{% assign minTagMatch = pageTagsNumber %}
{% endif %}
{% assign matchedComplete = false %}<!-- flag -->
<!--
numberOfTag to match to be in the related list
Will try to match all page tags, then page tags size - 1, -2, until reaching minTagMatch
-->
{% for numberOfTag in (minTagMatch...pageTagsNumber) reversed %}
<!-- Looping over site.posts or any site.mycollection -->
<!-- here you can do {% for item in site.mycollection %} -->
{% for item in site.posts %}
<!-- !!! ITEM SPECIFIC -->
<!-- for a collection change item.title == page.title if needed-->
{% if related contains item or item.title == page.title %}
<!--
Don't scan an item that is already in related
Don't scan an item if we are on his page
-->
{% continue %}<!-- go to next item -->
{% endif %}
{% assign itemTagsNumber = item.tags | size %}
{% if itemTagsNumber < numberOfTag %}
<!-- Not enough tags {{ itemTagsNumber }} -->
{% continue %}<!-- go to next item -->
{% endif %}
{% assign matchingTags = 0 %}<!-- tag match counter -->
{% for tag in page.tags %}
<!-- Comparing page tag "{{ tag }}" to {{ item.tags | join: ", " }} -->
{% if item.tags contains tag %}
<!-- one matching tag increment matchingTags counter-->
{% assign matchingTags = matchingTags | plus: 1 %}
<!-- We have a match and {{ matchingTags }} matching tags total -->
{% if matchingTags >= numberOfTag %}
<!-- we have enough matching tag, this is a related item -->
{% capture html %}
<li><a href="{{ site.baseurl }}{{ item.url }}">
{{ item.title }}
{% assign pageTagsNumber = item.tags | size %}
- has {{ pageTagsNumber }} tags
- match on {{ matchingTags }} tags
</a></li>
{% endcapture %}
{% assign related = related | push: html %}
{% assign relatedCount = related | size %}
{% if relatedCount >= maxRelated %}
<!-- if we have all our related set the matchedComplete flag to true -->
{% assign matchedComplete = true %}
{% endif %}
{% break %}
{% endif %}
{% endif %}
{% endfor %}
{% if matchedComplete == true %}
<!-- matchedComplete breaking item loop! -->
{% break %}
{% endif %}
{% endfor %}
{% if matchedComplete == true %}
<!-- matchedComplete breaking numberOfTag loop! -->
{% break %}
{% endif %}
{% endfor %}
{% if relatedCount > 0 %}
<!-- print related items -->
<ul>
{% for item in related %}
{{ item }}
{% endfor %}
</ul>
{% endif %}