How to reference properties in liquid - jekyll

I have a Jekyll template pulling in text from data objects.
eg.
{% for speaker_hash in site.data.2015.speakers %}
{% assign speaker = speaker_hash[1] %}
<li>
<div class="speaker">
<img class="head" src="/img/2015/speakers/sample.jpg">
<h2> {{ speaker.name}} </h2>
</div>
</li>
{% endfor %}
However I would like to have each page specify what year its for with a page.year property.
Is it possible to create the same for loop but specify the year dynamically?
eg
{% for speaker_hash in site.data.[page.year].speakers %}

Answer yes.
1 - Your page.year must be a string as hash indexes are strings. So in you front matter : year: '2015'
2 - Get speakers depending on page.year :
{% for speaker_hash in site.data[{{page.year}}].speakers %}

Related

<ol> tag doesn't increment from 1 and stays at 1 while using in a 'for' loop in HTML

Firstly, I don't know anything about HTML. I am trying to build a website using Jekyll and found a template for the website, to which I am making modifications.
I have the following code:
{% for publi in site.data.publist %}
{% assign even_odd = number_printed | modulo: 2 %}
{% if even_odd == 0 %}
<div class="row">
{% endif %}
<div>
<ol>
<li>{{ publi.title }}</li>
<!-- <img src="{{ site.url }}{{ site.baseurl }}/images/pubpic/{{ publi.image }}" class="img-responsive" width="33%" style="float: left" />
--> <p>{{ publi.description }}</p>
<p><em>{{ publi.authors }}</em></p>
<p><strong>{{ publi.link.display }}</strong></p>
<!-- <p class="text-danger"><strong> {{ publi.news1 }}</strong></p>
<p> {{ publi.news2 }}</p> -->
</ol>
</div>
{% assign number_printed = number_printed | plus: 1 %}
{% if even_odd == 1 %}
</div>
{% endif %}
{% endfor %}
There is a YAML file in the site.data.publist which has a number of members, each with different fields. The for loop helps to go through all the members of the YAML file.
As you can see in the code, I am using the <ol> tag in the for loop and I have used the <li> tag for the publi.title (a field in the members of the YAML file). But all I get is one repeating for all the members in the YAML file. I have attached the output I get.
As sirko mentioned in his comment, you are generating invalid HTML.
First of all, the <ol> may only contain li as direct children. So make sure to put everything else also within the li tag.
But your real problem is that you generate the ol tags within your loop. As mentioned in the comment, your output the contains multiple lists with one element each, not one list with n elements.
In order to change that, you have to move the ol outside of the for loop. (And then make sure you still generate valid HTML => see point 1.)

How to use multiple objects in a single Django template for loop? [duplicate]

So here's my problem: I've got a bunch of instances of a class. I would like to have a sort of table of these instance objects, so that there is a maximum of six in every row. In bootstrap terms, I would like each object to be represented by a thumbnail in a "div" of class "span2".
My initial impulse was to use a nested for loop, but I am having trouble manipulating my index variable in the template, and I can't figure out how to do so outside of my template.
Here is generally what the python/django template/pseudo code is I'm trying to figure out.
queryset = Class.objects.all()
set_length = queryset.count()
num_rows = set_length/6
#because I want 6 columns in each row, each with one instance
set_as_list = list(queryset)
# have a list so I can iterate through objects by index
for i in range(table_rows):
# make a row
<div class="row">
for j in range (i*6,(i+1)*6):
#make six or less columns
<div class="span2">
<p>set_as_list[j].attribute1</p>
<p>set_as_list[j].attribute2</p>
</div>
</div> # end row
I hope this flagrant mixing of django templating language, python, and html doesn't offend anybody too badly. just trying to express the idea of what I'm trying to do. I would appreciate any help someone may be willing to offer because I've been struggling with this for days and have done quite a bit of searching for a solution both within a template and outside.
I also realise that there will be need to be a final row with the remainder of objects after the integer division.
Have no time to explain, but I've had similar problem and until i closed this browser page here is a solution
{% for sub_article in articles %}
{% if forloop.first %}<div class="row">{% endif %}
<div class="col-xs-4">
<a href="#">
{{ sub_article.name }}
</a>
</div>
{% if forloop.counter|divisibleby:3 %}</div><div class="row">{% endif %}
{% if forloop.last %}</div>{% endif %}
{% endfor %}
Since forloop.counter starts the index with 1, divisibleby 3 does not work.
So use forloop.counter0 instead.
<div class="row">
{% for product in all_products %}
{% if forloop.counter0|divisibleby:3 %}
</div><br><div class="row">
{% endif %}
<div class="col-4"></div>
{% endfor %}
I would recommend to add a custom tag as_chunk. I think it makes the code prettier and more readable.
# app/templatetags/my_tags.py
from math import ceil
from django import template
register = template.Library()
#register.filter
def as_chunks(lst, chunk_size):
limit = ceil(len(lst) / chunk_size)
for idx in range(limit):
yield lst[chunk_size * idx : chunk_size * (idx + 1)]
# app/templates/your-template.html
{% load my_tags %}
...
{% for chunk in elements|as_chunk:6 %}
<div class="row">
{% for element in chunk %}
<div class="col-2">
{{ element.name }}
</div>
{% endfor %}
</div>
{% endfor %}
...
maybe too late but there is simple solution as follow
<div class="container">
<div class="row">
{% for product in products %}
{% if forloop.counter0|divisibleby:3 and not forloop.first %}<div class="w-100"></div>{% endif %}
<div class="col">{{product.title}}</div>
{% endfor %}
</div>
</div>
You could make the code a bit more generic. Here's the logic:
queryset = Class.objects.all()
set_length = queryset.count()
<div class="row">
{% for i in queryset %}
<div class="span2">
<p>i.attr</p>
<p>i.attr</p>
</div>
{% if forloop.counter|divisibleby:"6" or forloop.last %}
</div> <!--end row-->
{% endif %}
{% endfor %}
I hope this solves your problem :-)

display data in liquid

I'm looking to display information from a csv file on a jekyll-generated site. I need to search for the appropriate category in the csv file, then display four of them on the page. Filtering to the selected category is no problem, but I'm having difficulty limiting the output to four.
Is there a way to apply a limit to an if statement? Or is there any other way to write this? I'm not that savvy in Liquid, so it's extremely likely that I'm missing an obvious solution.
Basic code to make all the applicable data show up on the screen:
{% for study in site.data.studies %}
{% if study.category contains "foo" %}
<div class="col-sm-3">
<h3>{{ study.title }}</h3>
<div class="list-of-attributes">
<h6>Attributes: </h6>
{{ study.attributes }}
</div>
</div>
{% else %}
{% continue %}
{% endif %}
{% endfor %}
I've also tried unless and tablerow, neither of which worked at all. Am I at least on the right track? How can I limit this forloop to stop at four items?
Thank you!
Ideally data should be filtered before rendering however you can also create a variable in liquid to hold the number of stuff rendered
{% assign rendered = 0 %}
{% for study in site.data.studies %}
{% if study.category contains "foo" %}
<div class="col-sm-3">
<h3>{{ study.title }}</h3>
<div class="list-of-attributes">
<h6>attributes: </h6>
{{ study.attributes }}
</div>
</div>
{% assign rendered = rendered | plus: 1 %}
{% if rendered == 4 %}
{% break %}
{% endif %}
{% endif %}
{% endfor %}
The ideal solution as I said would be to create your own filter which does all the work (filter by category and limit the number of results)
{% assign filtered = site.data.studies | my_custom_filter %}
{% for study in filtered %}
<div class="col-sm-3">
<h3>{{ study.title }}</h3>
<div class="list-of-attributes">
<h6>attributes: </h6>
{{ study.attributes }}
</div>
</div>
{% endfor %}
Presuming that your category is a string, not an array, you can do :
{% assign selected = site.data.studies | where: 'category','foo' %}
{% for study in selected limit:4 %}
<div class="col-sm-3">
<h3>{{ study.title }}</h3>
<div class="list-of-attributes">
<h6>Attributes: </h6>
{{ study.attributes }}
</div>
</div>
{% endfor %}
And if your category is a string like "foo, bar, baz" or and array of strings you can use the jekyll 3.2 where_exp filter like this :
{% assign selected = site.data.studies | where_exp:"item", "item.category contains 'foo'" %}

How to add a second tag list using pelican-bootstrap3

I would like to list the Lego sets I used to build my models just like tags but in a separate list. According to the pelican documentation this should be possible. But when I run pelican content I get
Tags Animal / Duplo / MOC
Sets 1 / 0 / 5 / 7 / 1
instead of
Tags Animal / Duplo / MOC
Sets 10571
I modified the pelican-bootstrap theme from Daan Debie by adding {% include 'includes/setlist.html' %} to article_info.html.
This is what my setlist.html file looks like:
{% if article.sets %}
<span class="label label-default">Sets</span>
{% for set in article.sets %}
{{ set }}
{% if not loop.last %}
/
{% endif %}
{% endfor %}
{% endif %}
This is what my markdown file looks like:
Title: Girafe
Date: 2015-11-29 14:22:20
Modified: 2015-11-29 14:22:27
Category:
Tags: Animal, Duplo, MOC
Sets: 10571
Slug: girafe
Authors: Yann Baumgartner
![Girafe][girafe]
[girafe]: {filename}/images/girafe.jpg "Girafe"
I read through all the pelican questions on stackoverflow but couldn't find an answer. I tried the following:
If I use the taglist code within setlist without changing any
variables then the tags are displayed correctly
Renaming the variable
name to set_numbers didn't work.
Removing set.url didn't work.
Am I missing something (a template file, a jinja2 filter)? Any hint would be much appreciated.
pelican doesn't process any non-standard metadata. It'll be left as a string. So, article.sets will be a single string containing "10571". If you loop over that, you'll get individual characters. You need to process it yourself via a plugin or inside your template like:
{% if article.sets %}
<span class="label label-default">Sets</span>
{% for set in article.sets.split(',') %}
{{ set|trim }}
{% if not loop.last %}
/
{% endif %}
{% endfor %}
{% endif %}
PS: Also, I'm not sure what you expect the set.url to be. Again, since pelican doesn't do anything special with your custom metadata, it will be basic string and it won't have an url.

List tags within a specific category in Jekyll

I am migrating my Wordpress blog to Jekyll, which I like a lot so far. The current setup in the new site is like this:
use category to distinguish two types of posts (e.g., blog and portfolio)
use tag as normal
The challenge right now is to display all tags within a category because I want to create two separate tag clouds for two types of posts.
As far as I know, Liquid supports looping over all tags in a site like this:
{% for tag in site.tags %}
{{ tag | first }}
{% endfor %}
But I want to limit the scope to a specific category and am wishing to do something like this:
{% for tag in site['category'].tags %}
{{ tag | first }}
{% endfor %}
Any advice will be appreciated.
This seems to work for all kinds of filters like category or other front matter variables - like "type" so I can have type: article or type: video and this seems to get tags from just one of them if I put that in the 'where' part.
{% assign sorted_tags = site.tags | sort %}
{% for tag in sorted_tags %}
{% assign zz = tag[1] | where: "category", "Photoshop" | sort %}
{% if zz != empty %}
<li><span class="tag">{{ tag[0] }}</span>
<ul>
{% for p in zz %}
<li>{{ p.title }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
zz is just something to use to filter above the first tag[0] since all it seems to have is the tag itself, so you can filter anything else with it. tag[1] has all of the other stuff.
Initially I was using if zz != null or if zz != "" but neither of them worked.
This will work, it will list only the tags on post of category 'X'. Replace X with the name of the category.
{% for post in site.categories['X'] %}
{% for tag in post.tags %}
{{ tag }}
{% endfor %}
{% endfor %}