Just a regular block reuse with Twig - how to? - twig

Imagine we have a block template which we want to use many times on a page. And every time we need to do three things:
set a class on the top level
set a title
add some content
How to achieve this on Twig?
I know about macro, but it doesn't take content.
I know about block, but it doesn't take parameters.
So... how to do this in a normal way?
Since I don't know how, I'll use an imaginary constructs 'blockdef' and 'blockuse' later on to demonstrate the task (which is absolutely ordinary).
So let's say we have this cute Twig block template:
blocks.twig:
{% blockdef myblock(class, title) %}
<div class="block {{class}}">
<div class="inner">
<div class="title">{{title}}</div>
<div class="content">{{content}}</div>
</div>
</div>
{% endgoodblock %}
And want to use it like this:
main.twig:
{% blockuse myblock('c1', 'Title1' %}
<p>Block 1 content</p>
{% endblockuse %}
{% blockuse myblock('c2', 'Title2' %}
<p>Block 2 content</p>
{% endblockuse %}
{% blockuse myblock('c3', 'Title3' %}
<p>Block 3 content</p>
{% endblockuse %}
Is there anything like this?
UPDATE. For example, this is how it's solved on Jade:
mixin myblock(cls, title)
.block(class=cls)
.inner
.title= title
.content
block
+myblock('c1', 'Title1')
p Block 1 content
+myblock('c2', 'Title2')
p Block 2 content
+myblock('c3', 'Title3')
p Block 3 content

You could use include with:
{% include 'template.html' with {'class': 'class', 'title': 'title', 'content: 'content'} %}

Related

How to do a foreach loop in a Twig

Here i have attached screenshot,in that 2nd section 2 rows are present. i need to display only one row with custom code condition, If i disable from admin side,it will work correctly,but i need loop condition for enable and disable to display only row. Here is my code,
<div class="col-md-12" >{% for module in modules %}<div class="img-responsive">
{{ module }}
{% endfor %}</div></div>
</div>
There's special loop variables inside a loop that let's you keep track of index and more. In your case loop.index.
<div class="col-md-12" >
{% for module in modules %}
<div class="img-responsive">
{# Replace 1 with a specific index you want to use as condition #}
{% if loop.index == 1 %}
{{ module }}
{% else %}
No module
{% endif %}
</div>
{% endfor %}
</div>

If statement in Twig (for Particle in Joomla)

Trying to edit a particle in Joomla -- I'm fairly new to twig and I'm trying to list information based on a selection in vertical tabs. I have an on-click refresh for my li edit that makes a tab "selected" and creates my internal url:
{% for item in particle.items %}
<li>
<a href="/Joomla/about-the-library/locations#{{ loop.index }}">{{ item.title|e }}
<img src="{{ url(item.image)|e }}" alt="{{ item.title|e }}">
<div class="g-flexslider-carousel-item-image-preview-icon"></div>
</a>
</li>
{% endfor %}
This is all well and good, but I ran into an issue when trying to display the data associated with the selected item. I tried to create a variable to check my items against, but the variable doesn't seem to be coming back as an integer, and I've tried a few things:
{% set branch = app.request.pathinfo|trim('/Joomla/about-the-library/locations#') %}
{% if loop.index == branch %}
<div class="g-flexslider-showcase-item-content-container">
<div class="g-flexslider-showcase-item-image">
<img src="{{ url(item.image)|e }}" alt="{{ item.title|e }}">
</div>
Can anyone tell me what I'm doing incorrectly?
(I found that get current url in twig template? helped, but I'm not sure I'm using the answers provided correctly. I've also sifted through the Twig Documentation for a couple hours to no avail.)
[Nov 2016] - This is still what "my" code looks like for this section. It seems to just be a problem with this if statement, as the "else" statement (which I'm using for debugging purposes) keeps coming through.
{% for item in particle.items %}
{% if app.request.get('name') == item.URLname|e %}
<p>You have branched {{ item.title|e }} correctly. </p>

How to pass the current context to include in Twig?

Say I have the following headline.twig partial:
<h2>{{ headline }}</h2>
and I want to include it in two places, once as:
<% for article in teasers %>
{{ include('headline.twig') }}
<% endfor %>
And then simply:
{{ include('headline.twig') }}
Is it possible to pass an include tag or function its context, so that the include "knows" that in the first instance the headline variable is actually article.headline?
I'm looking for a systematic way to do this, not with something like
{{ include('headline.twig', {headline: article.headline}) }}
If you want headline to be in the main context of your included file in all cases, you can do something like this:
{% for article in teasers %}
{% set headline = article.headline %}
{{ include('headline.twig') }}
{% endfor %}
But this will overwrite any existing headline variable in your current context if you're re-setting it this way (and risk to repeat 2 times the last iteration of teasers.article.headline).
The best solution if you want to keep your current context AND overwrite headline variable is to use the merge filter:
{% for article in teasers %}
{{ include('headline.twig', _context|merge({headline: article.headline})) }}
{% endfor %}
By default whole context is passed to included template.
So it will work in headline.twig:
<h2>{{ article.headline }}</h2>
And then in main template you only call:
{% include('headline.twig') %}
But article variable must be defined in moment of calling include.

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