Twig - if object contains one element - symfony

I want to use an if statement in my twig for cycle - if object(variable) contains one element(row) - then add this html code snippet,
And here's what I'm trying,
{% for course in courses %}
<a href="{{ course.courseLink }}"class="courses">
<div class="picture"><img src="{{ asset('/bundles/dproc/assets/images/courses- example.jpg') }}" alt="news-1" title="news-1" /></div>
<div class="title"><h2>{{ course.courseTitle }}</h2></div>
<div class="info">
{{ course.courseContent }}
</div>
</a>
{% endfor %}
at the moment courses contains only one element. My task is to add a div element if it contains only one element.
How can I do that in twig?

You can use this function to check the length of an array
{% if courses|length == 1 %}
{# print div#}
{% endif %}

Related

For loop in Timber Twig file returns three copies of same image (should be 3 different images)

I'm building my first Timber Wordpress theme and using the timber-starter-theme. I have a custom content type with custom fields (fields added using WCK plugin). I haven't touched single.php file, just building the twig template. 'team_church_slide' is a repeating field to add images to go into a Slick carousel. My template section is:
{% set slickSlider = post.team_church_slideshow %} {# the field group #}
{% set slickSlide = post.get_image('team_church_slide') %} {# the field #}
{% if slickSlider %}
<div class="slick-slider">
<ul>
{% for slides in slickSlider %}
<li><img src="{{ slickSlide.src }}" alt="{{ slickSlide.alt }}"></li>
{% endfor %}
</ul>
</div>
{% endif %}
This returns the image correctly, but three copies of the first image, not the three different images which are uploaded. If I remove an uploaded image, two copies of the first image are shown.
Is there something to change in the twig to get all the images?
Figured this out thanks to something in this post:
Get first row from ACF Repeater using Timber
Here's my final working template section:
{% set slickSlider = post.team_church_slideshow %}
{% if slickSlider %}
<div class="slick-slider">
<ul>
{% for slides in slickSlider %}
{% set slickSlide = TimberImage(slides.team_church_slide) %}
<li class="slide">
<img src="{{ slickSlide.src }}" alt="{{ slickSlide.alt }}">
</li>
{% endfor %}
</ul>
</div>
{% endif %}
The only real change was 'post.get_image' to 'TimberImage' & moving the set inside the for-loop.

3 Level Deep Timber menu (Wordpress)

I'm not familiar with timber at all, but am helping a friend finish up a project that was built with it. So any help would go a long way please!
I have only the first two tiers showing up. Is there a way to call on the child of a child?
I'm using the code here, and added to it another tier under child https://timber.github.io/docs/guides/menus/
{% if menu %}
<div class="header-menu-items">
<div class="header-menu-item mod-title">
<a href="{{ site.url }}" class="" rel="home">
<div class="header-item-logo">
<div class="sitelogo">{{ site.name }}</div>
</div>
</a>
</div>
{% for item in menu.get_items() %}
<div class="header-menu-item {{ item.current ? 'is-active' : '' }}">
<div class="header-menu-item-link">
<a target="{{ item.target }}" href="{{ item.link }}">{{ item.title }}</a>
</div>
<div class="header-menu-item-triangle"></div>
<div class="header-menu-item-mega {{ item.section_colour ? " mod-#{item.section_colour}" : '' }}">
{% if item.master_object.thumbnail %}
<div class="mega-image mod-image" style="background-image: url( {{item.master_object.thumbnail.src('thumbnail') }} )">
{% else %}
<div class="mega-image">
{% endif %}
{{ item.title }}
</div>
<div class="mega-items">
{% for child in item.children %}
<div class="mega-item">
<a target="{{ child.target }}" href="{{ child.link }}">
<span class="mega-item-title">{{ child.title }}<br /></span>
<span class="mega-item-excerpt">Mega menu description lorem ipsum dolores</span>
</a>
</div>
{% for child in child.children %}
Just testing to see if it'll even show up first before applying style<br />
{{ child.title }}<br />
{% endfor %}
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
You can access menus several layers deep by nesting for loops inside of one another. Here is a code snippet that I have tested and works.
{% for item in menu__main.items %} {# This is the top level #}
<p>{{ item }}</p>
{% if item.children %}
{% for child in item.children %} {# 2nd Level #}
<p><em>{{ child }}</em></p>
{% if child.children %}
{% for third in child.children %} {# 3rd Level #}
<p><strong>{{ third }}</strong></p>
{% endfor %} {# for third in child.children #}
{% endif %} {# if child.children #}
{% endfor %} {# for child in item.children #}
{% endif %} {# if item.children #}
{% endfor %} {# for item in menu__main.items #}
I have added comments to the end of the lines to hopefully make this more clear. So at the top, you are looping through item in menu__main.items
Then to get the children inside of these, you loop through item.children since item is the variable that represents each nav item at the top/main level. You loop through item.children to get to the next level or the children inside of the main/top level.
Then to get inside of the third level, you loop through child.children since child is the variable that represents the 2nd level. We want to loop through the children of this 2nd level. so we do third in child.children. third is the variable that represents the items 3 levels down.
I hope you can see the pattern here and you can continue this even further if you have items at even deeper levels, although at some point it will probably get ridiculous. Like if you have items nested 5 or 6 levels deep.
Let me know if that makes sense and if not I will be more than happy to try and explain it another way if you still have questions.
Cheers

Twig batch and loop index

I have a Twig for loop using the batch filter to wrap every 2 elements in a container div. I want to add a classname to every 3rd and 4th div in this for loop. However it seems you can't use loop.index when using the batch filter. Is that correct? How do you access the index then when using the batch filter?
What I tried is this:
{% for batch in blog.articles | limit(6) | batch(2) %}
<div class="blog-art-wrap row-eq-height">
{% for article in batch %}
<div class="article {% if loop.index == 3 or loop.index == 4 %}some-class{% endif %}">...... </div>
{% endfor %}
</div>
{% endfor %}
I also tried it with loop.index3 etc... But it just seems to ignore this.
Or is this because of the batches are in 2? So there's actually no index 3 and 4?? If so how do you access every 2nd batch then?
You could use the parent loop variable in order to refer to the parent context. As example:
{% for batch in blog.articles | batch(2) %}
<div class="blog-art-wrap row-eq-height">
{% for article in batch %}
<div class="article {% if loop.parent.loop.index == 3 or loop.parent.loop.index == 4 %}some-class{% endif %}">...... </div>
{% endfor %}
</div>
{% endfor %}
Try in this working twigfiddle.
Hope this help
try this:
{% set className = '' %}
{% if loop.index is divisibleby(3) or loop.index is divisibleby(4) %}
{% set className = 'some-class' %}
{% endif %}
<div class="article {{ className }}">...... </div>

Drupal 8 remove style element in views custom text

I encounter a problem with the way Drupal renders Global Custom text.
I need to use Custom text field in my view to wrap fields. The body field has some "style" element inside the HTML but they are removed.
{% if field_titre_rubrique is defined and field_titre_rubrique|length %}
<div class="ancre" id="{{ field_ordre_rubrique }}">
<h1 class="ancreMenu">{{field_titre_rubrique}}</h1>
<div>
{% if body is defined %}
{{body}}
{% endif %}
{% if field_pdf is defined %}
{{field_pdf}}
{% endif %}
</div>
</div>
<div>{{ edit_node }}</div>
{% endif %}
Do I have a solution to keep "style" elements ?
You can use {{ body|raw }} but be sure that you can do this safely.
More about this topic: https://www.drupal.org/node/2296163

Symfony2, Twig, change twig after include

I have such hierarchy of twig files
my main (for controller) twig
{% extends "MainSiteBundle::layout.html.twig" %}
{% block footer_moderator_buttons %}
some buttons
{% endblock %}
{% block content_body %}
<p>hello moderator</p>
{{ include ('MainBlogBundle:_parts:postList.html.twig', {'postList': aPostDraft}) }}
{% endblock %}
postList.html.twig
<div class="post-list">
{% for postSingle in postList %}
{{ include ('MainBlogBundle:_parts:postSingle.html.twig', {'postSingle': postSingle}) }}
{% endfor %}
</div>
postSingle.html.twig
<div class="post">
<div class="post-header">
<a class="title" href="3">{{ postSingle.title }}</a>
</div>
<div class="post-meta">
<div>Date: {{ postSingle.date|date('D M Y') }}</div>
<div>Category: {{ postSingle.getCategory.getTitle }}</div>
<div>Author: {{ postSingle.getUser.username }}
</div>
</div>
<div class="post-body">
<div class="content">
<img width="450" height="200" src="#">
<div class="text">{{ postSingle.content }}</div>
</div>
</div>
<div class="post-footer">
{% block footer_moderator_buttons %}f{% endblock %}
<div>Views: 152</div>
<div>Comments: 1231</div>
<div>
<a class="link" href="#">More... </a>
</div>
</div>
</div>
As you can see last (postSingle.html.twig) has block "footer_moderator_buttons", so how can i change it from main twig (first one) ? Current is not working, what I need change \ do ?
In Twig 1.8 there is embed tag (http://twig.sensiolabs.org/doc/tags/embed.html).
You would have to remove the postList.html.twig file or work around it.
{% embed "MainBlogBundle:_parts:postSingle.html.twig" with {'postSingle': postSingle} %}
{% block footer_moderator_buttons %}
custom buttons here
{% endblock %}
{% endembed %}
So, you question is actually "I want to understand how\what twig can". Well, the answer to that question is: "It can't overwrite blocks from "main" to the smaller ones."
If you want to use twig, you have to stop thinking in php include() way where you make new files and you "PUT" components in them over and over again, components such as header, footer, menu etc.
In twig, you define main twig file with blocks which can be imagined as empty spaces which can, but do not have to, be overwritten. Surely, it still means you can have postList.html.twig as include in some file that extends MainSiteBundle::layout.html.twig. The same goes for postSingle.html.twig.
I think you catch the logic of twig except don't try to overwrite blocks from the wrong side - in this case, from MainSiteBundle::layout.html.twig to it's smaller portions.
how about this:
{% extends "MainSiteBundle::layout.html.twig" %}
....
{% block footer_moderator_buttons %}
{{ parent() }}
{% endblock %}
woops didnt put parent..
the {{ parent() }} will inherit {% block footer_moderator_buttons %}{% endblock %} from extended twig.

Resources