Display all categories linked to an article - twig

I make a loop to browse the categories linked to my articles but if an article with several categories it displays the name of my first category as many times as there are categories.
How do I display all the names?
Here Gary Moore in 2 categories: blues and metal but blues is displayed 2 times.
{% for category in articleDer.category %}
{% if category.articles | length >=1 %}
<a class="textPostcard" href="{{ path('portcategory_categorie', {'slug': category.slug }) }}"><i class="fas fa-list-alt mr-2"></i> {{ articleDer.category[0].name }}</a>
{% else %}
{% endif %}
{% endfor %}

In your loop you are looping articleDer.category array and printing <a class="textPostcard" ...></a>.
But inside the loop you are accessing only the first index of the articleDer.category and fetching the name.
In your code,
{{ articleDer.category[0].name }}
Should be changed to
{{ category.name }}

Related

RainLab.Blog Post List: List Sub-Categories under a specific Top-Level Category

I'm working on an October CMS project which use a blog where I need to seperate blog posts in two major categories. When listing blog posts using the RainLab.Blog plugin's Post List component, I need to list categories that are sub-categories under a specific top-level category and exclude other categories.
In the TWIG template, I want to iterate through and list out the categories that belong to "Birds" and not "Sealife".
In the default Post List component, categories are listed like this:
{% for category in post.categories %}
{{ category.name }}{% if not loop.last %}, {% endif %}
{% endfor %}
I would like to change this to something like this:
{% for category in post.categories %}
{# if category is a sub-category of "Birds"... #}
{{ category.name }}{% if not loop.last %}, {% endif %}
{# endif #}
{% endfor %}
So I would like the post to be listed as "Shorebirds" and "Hummingbirds" but not as "Corals" as this is a category that is not a direct child of "Birds".
I came across this stack overflow question, but it avoids rendering posts that do not match the criteria all together. I still want to fetch and render posts that are in other categories, but only list the categories if they match.
If it's totally fine to hardcode category then you can simply compare categories parent's slug or id to hardcoded value.
Here I am using the slug to compare parent, you can also use id it's totally up to you.
{% for category in post.categories %}
{% set parentCat = category.getParent().first() %}
{% if parentCat.slug == 'birds' %}
<!-- here we are ^ comparing ^ please replace value as per your need -->
{{ category.name }}
{% if not loop.last %}, {% endif %}
{% endif %}
{% endfor %}
now it should only show a categories which have a parent category having given slug.
if any doubt please comment

A For Loop in Jinja can't be used again or how to move First

When reusing the same SQLAlchemy Result to iterate it only works the first time.
See the below how I get all the qual.workforce but none of the displayname, busunit or certcount's:
<ul class="empltype">
{% for qual in allquals %}
<li>{{qual.workforce}}</li>
{% endfor %}
</ul>
<ul class="names">
{% for qual in allquals %}
<li>{{qual.displayname}}</li>
{% endfor %}
</ul>
<ul class="busunit">
{% for qual in allquals %}
<li>{{qual.busunit}}</li>
{% endfor %}
</ul>
<ul class="certcount">
{% for qual in allquals %}
<li>{{qual.certcount}}</li>
{% endfor %}
I would like to MoveFirst before the 3 loops for displaynames, busunit and certcount so they all work.
I don't want have 4 copies of the same variable (allquals1,2,3) even though I know that will work. I'm guessing the jinja render engine only iterates through objects once, is there a way to tell it to iterate over the same result set each time its used in a loop?
it happens just because the result is a generator, and it's values can be accessed only once. you have to do allquals = list(query_result) to iterate multiple times over it

Use loop.index as part of template name to include with Twig?

I have an array of 3 items so in the following I'm including sub-component.twig 3 times:
{% for i in array %}
<div class="my-class">
{% include "sub-component.twig" %}
</div>
{% endfor %}
However I actually have 3 slightly different templates and I would like to load a different one for each iteration over the array:
sub-component-1.twig
sub-component-2.twig
sub-component-3.twig
When I print loop.index in the template the result is "1", "2" and "3". Can I therefore use the index to form the template name?
{% for i in array %}
<div class="my-class">
{{ loop.index }}
{% include ["sub-component-" ~ loop.index ~ ".twig"] %}
</div>
Possibly because I'm using gulp twig I had to break things out into variables for this to work.
https://github.com/zimmen/gulp-twig
{% for i in array %}
<div class="my-class">
{% set sub-component_1 = "sub-component-" %}
{% set sub-component_2 = loop.index %}
{% set sub-component_3 = ".twig" %}
{% set sub-component_full = sub-component_1 ~ sub-component_2 ~ sub-component_3 %}
{% include sub-component_full %}
</div>
{% endfor %}

Twig execute a function once instead of 3 times

I was wondering if it is possible to create some sort of condition which can be used on 3 different places in a template with Twig.
Let's say I have 3 slider images with a link. A user of the template has the option to choose between a button link or a normal link via a dropdown menu. Like so (below is only the first slider):
{% if theme.slide1 %}
<li class="animate-in f1">
<div class="wrap">
{{ 'Read more' | t }}
</div>
</li>
{% endif %}
{% if theme.slide2 %}
<li class="animate-in f2">
<div class="wrap">
{{ 'Read more' | t }}
</div>
</li>
{% endif %}
Normally you would do something like:
{% if theme.slide1_link_setting == 'Link' %} do this {% else %} do that {% endif %}
You have to do this 3 times if you have 3 slider images. But what if you have eg. 10 slider images?
I tried to create a function which checks if a setting is a button or normal link.
{% set link_style = theme.slide1_link in ['link', 'button'] ? 'normal-link': 'btn btn-custom-2 btn-sequence' %}
First of all the function above doesn't work.
Second I don't know how to set the number of the slide you're in. I want something like below:
{% set link_style = theme.slide[numberOfSlide]_link in ['link', 'button'] ? 'normal-link': 'btn btn-custom-2 btn-sequence' %}
Is there anybody who can help me with this?

How can I use Jinja2 to group articles by date and paginate in Pelican?

I'm using the Pelican static site generator to create a high-volume blog. Pelican themes paginate the index page, showing a list of post titles and summaries, sorting the posts by date. Here's an example of how this is accomplished, from the bootstrap theme:
{% if articles %}
{% for article in (articles_page.object_list if articles_page else articles) %}
<div class='article'>
<h2>{{ article.title }}</h2>
<div class="well small">{% include "metadata.html" %}</div>
<div class="summary">{{ article.summary }} <a class="btn primary xsmall" href="{{ SITEURL }}/{{ article.url }}">more…</a>
</div>
</div>
{% endfor %}
{%endif%}
And here's the also-pretty-standard code for the pagination navigation:
{% if articles_page and articles_paginator.num_pages > 1 %}
<div class="pagination">
<ul>
{% if articles_page.has_previous() %}
{% set num = articles_page.previous_page_number() %}
<li class="prev">← Previous</li>
{% else %}
<li class="prev disabled">← Previous</li>
{% endif %}
{% for num in range( 1, 1 + articles_paginator.num_pages ) %}
<li class="{{ 'active' if num == articles_page.number else '' }}">{{ num }}</li>
{% endfor %}
{% if articles_page.has_next() %}
<li class="next">Next →</li>
{% else %}
<li class="next disabled">→ Next</li>
{% endif %}
Since my site has lots of information to share in a small space--sometimes 20 articles a day--I've written summaries fit in a single line. Instead of listing the date with each post, I'd like the index page to group posts by date, like this:
February 1, 2014
Post 1
Post 2
Post 3
February 2, 2014
Post 1
Post 2
Here's a way to group articles by date with Jinja2:
{% if articles %}
{% for year, year_articles in articles|groupby('date.year')|sort(reverse=True) %}
{% for month, month_articles in year_articles|groupby('date.month')|sort(reverse=True) %}
{% for day, day_articles in month_articles|groupby('date.day')|sort(reverse=True) %}
<dl>
<dt>{{ day_articles[0].date.strftime('%d %B %Y') }}</dt>
{% for article in day_articles %}
<dd>
{{ article.title }}
</dd>
{% endfor %}
</dl>
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
I want to combine these features so that the articles are grouped by date and paginated. So far my admitted-guesswork has failed. I'm using 100 articles to start with, set to show 10 articles per page; in my attempts, the index lists 10 pages of articles but it shows all of the articles on each page. I'd be happy with any working solution. Any ideas how to proceed?
Further thoughts
Maybe instead of all the grouping, a Jinja if-loop could identify the first article listed for that date and write the date, then the linked article title, etc. For all subsequent articles, it would skip printing the date and write the linked article title, etc. I'm not sure how to do that, and that if-loop would still have to avoid knocking the paginator off its game. But if it works, creating a nice-looking list is a CSS job instead of a Jinja job.
Use the dates_page variable instead of articles, see details here: http://pelican.readthedocs.org/en/latest/themes.html#index-html
dates_paginator A paginator object for the article list, ordered by date, ascending.
dates_page The current page of articles, ordered by date, ascending.
Probably far too late to be helpful, but I'm sharing because I just spent an evening fighting with this and finally got it working in Pelican 4.2. I'm not grouping by individual date, but this should still work with an extra inner loop for the day:
{% for year, year_group in dates_page.object_list|groupby('date.year')|reverse %}
{% for month, month_group in year_group|groupby('date.month')|reverse %}
<h1>{{ (month_group|first).date|strftime('%B %Y') }}</h1>
{% for article in month_group %}
... do stuff with individual article here ...
{% endfor %}
{% endfor %}
{% endfor %}
{% if dates_page.has_other_pages() %}
{% include 'pagination.html' %}
{% endif %}
The key thing is to the start outer loop with dates_page.object_list; dates_page provides the paged list of articles ordered by date, and object_list is the iterable that provides the actual list of articles used by the template. Other examples I was trying to use omitted object_list and causing various errors.
The block of code at the bottom loads the pagination template as needed.

Resources