for loop in TWIG with string concatenation? - twig

How can I output this HTML block with a nested TWIG counter variable {{ i }} like: eco-item-2.jpg, eco-item-3.jpg and eco.benefits.item.header.2, eco.benefits.item.header.3 and so on…?
{% for i in 0..3 %}
<section class="eco-benefits">
<img src="{{ asset ('img/eco-item-1.jpg') }}" class="th">
<dl>
<dt>
{% trans from 'eco' %}
eco.benefits.item.header.1
{% endtrans %}
</dt>
<dd>
{% trans from 'eco' %}
eco.benefits.item.text.1
{% endtrans %}
</dd>
</dl>
</section>
{% endfor %}

You can concatenate strings using the ~ operator:
{% for i in 0..3 %}
<section class="eco-benefits">
<img src="{{ asset ('img/eco-item-' ~ (i + 1) ~ '.jpg') }}" class="th">
<dl>
<dt>{{ ('eco.benefits.item.header.' ~ (i + 1))|trans(domain = 'eco') }}</dt>
<dd>{{ ('eco.benefits.item.text.' ~ (i + 1))|trans(domain = 'eco') }}</dd>
</dl>
</section>
{% endfor %}

Related

How to merge string to an array?

I tried to merge string into twig array but it will show the last same value for all index. What's the proper way to merge a string to an array?
{% set projectArray = [] %}
{% set projectTitleArray = [] %}
{% set projectQuery = entries('projects', 'projects').where('enabled', 1).orderBy('sort_order').get() %}
TITLE - URL:
{% for project in projectQuery %}
{% set projectArray = projectArray|merge([project.main_image.make.url()]) %}
{% set projectTitleArray = projectTitleArray|merge([project.title]) %}
<ul>
<li>{{project.title}} - {{project.main_image.make.url()}}</li>
</ul>
{% endfor %}
<hr/>
TITLE:
{% for title in projectTitleArray %}
<ul>
<li>{{title}}</li>
</ul>
{% endfor %}
URL:
{% for title in projectArray %}
<ul>
<li>{{title}}</li>
</ul>
{% endfor %}
<div class="py-6 bg-slate-100">
<div class="container my-10 mx-auto">
<h1 class="section-title-1">
Projects
</h1>
</div>
<div class="xl:pl-[5rem]">
<product-projects :title="{{projectTitleArray|json_encode(constant('JSON_PRETTY_PRINT'))}}" :projects="{{projectArray|json_encode(constant('JSON_PRETTY_PRINT'))}}"></product-projects>
</div>
</div>
Output

Uneven gallery with a repeated loop

I need to make an uneven gallery, where the user can upload an infinite number of images. The gallery is composed of a pattern of 7 images that is repeated indefinitely.
The website mainly uses Paragraphs, so I created a Paragraph Gallery, where the user can directly upload the media. I set up three image styles: small, tall, and big.
I also prepared a simple CodePen with the style solution. But now I’m struggling with the Twig template. I tried some solutions from previous discussions, but they either failed or didn’t generate the images.
{% block content %}
{% for image in content.field_images['#items'] %}
{% if image %}
<div class="gallery">
<div class="gallery-left">
<div class="inner-wrapper">
<div class="inner-left">
{% if loop.first %}
<div class="field__item">
<img src="{{ image|file_uri|image_style('tall') }}" alt="{{ image.alt }}">
</div>
{% endif %}
{% if loop.index == 2 %}
<div class="field__item">
<img src="{{ image|file_uri|image_style('small') }}" alt="{{ image.alt }}">
</div>
{% endif %}
</div>
<div class="inner-right">
{% if loop.index == 3 %}
<div class="field__item">
<img src="{{ image|file_uri|image_style('tall') }}" alt="{{ image.alt }}">
</div>
{% endif %}
{% if loop.index == 4 %}
<div class="field__item">
<img src="{{ image|file_uri|image_style('small') }}" alt="{{ image.alt }}">
</div>
{% endif %}
</div>
</div>
</div>
<div class="gallery-right">
{% if loop.index == 5 %}
<div class="field__item">
<img src="{{ image|file_uri|image_style('small') }}" alt="{{ image.alt }}">
</div>
{% endif %}
{% if loop.index == 6 %}
<div class="field__item">
<img src="{{ image|file_uri|image_style('tall') }}" alt="{{ image.alt }}">
</div>
{% endif %}
</div>
<div class="bottom">
{% if loop.index % 7 == 0 or loop.last %}
<div class="field__item">
<img src="{{ image|file_uri|image_style('big') }}" alt="{{ image.alt }}">
</div>
{% endif %}
</div>
</div>
{% endif %}
{% endfor %}
{% endblock %}
Based on #WPhil's idea with batch I would do it like it is proposed below.
Things to note:
Image uri can be retrieved from file entity and not from media nor field reference list item this is why content.field_images['#items'].0 is not enaugh and it should be something like content.field_images['#items'].0.entity.field_media_image.entity
batch filter has three arguments and within loops like this is important to reset the index so this is why the third arggument is FALSE
Gallery paragraph file
{% import "_impression_image.html.twig" as impression %}
{% block content %}
{% for impressions_gallery_batch in content.field_images['#items']|batch(7, NULL, FALSE) %}
{# Define all image file entities for given batch of image items #}
{% set image_entities = {} %}
{% for impressions_gallery_batch_item in impressions_gallery_batch %}
{% set image_entities = image_entities|merge([
impressions_gallery_batch["#{loop.index0}"].entity.field_media_image.entity,
]) %}
{% endfor %}
<div class="impressions-gallery">
<div class="impressions-left">
<div class="inner-wrapper">
{% if image_entities.0 %}
<div class="inner-left">
{{ impression.image(image_entities.0, 'impressions_small') }}
{{ impression.image(image_entities.1, 'impressions_tall') }}
</div>
{% endif %}
{% if image_entities.2 %}
<div class="inner-right">
{{ impression.image(image_entities.2, 'impressions_small') }}
{{ impression.image(image_entities.3, 'impressions_tall') }}
</div>
{% endif %}
</div>
</div>
{% if image_entities.4 %}
<div class="impressions-right">
{{ impression.image(image_entities.4, 'impressions_tall') }}
{{ impression.image(image_entities.5, 'impressions_small') }}
</div>
{% endif %}
{% if image_entities.6 %}
<div class="impressions-bottom">
{{ impression.image(image_entities.6, 'impressions_big') }}
</div>
{% endif %}
</div>
{% endfor %}
{% endblock %}
Image item macro function (_impression_image.html.twig)
{% macro image(image_entity_item, image_style) %}
{% if image_entity_item %}
<div class="field__item">
<img src="{{ image_entity_item.uri.value|image_style(image_style) }}" alt="{{ image_entity_item.alt }}">
</div>
{% endif %}
{% endmacro %}
Try something along the lines of the below, I have used the batch and splice filters to break up the image array into blocks and then conditional checks to determine the appropriate image size.
{% block content %}
{% for gallery_block in content.field_images['#items']|batch(7) %}
<div class="gallery">
<div class="gallery-left">
<div class="inner-wrapper">
<div class="inner-left">
{% for image in gallery_block|slice(0,3) %}
{% if image %}
<div class="field__item">
{% set size = ( loop.index is even ) ? 'small' : 'tall' %}
<img src="{{ image|file_uri|image_style(size) }}" alt="{{ image.alt }}">
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
<div class="gallery-right">
{% for image in gallery_block|slice(4,5) %}
{% if image %}
<div class="field__item">
{% set size = image.first ? 'small' : 'tall' %}
<img src="{{ image|file_uri|image_style(size) }}" alt="{{ image.alt }}">
</div>
{% endif %}
{% endfor %}
<div>
{% set bottom_image = gallery_block|last %}
{% if bottom_image %}
<div class="bottom">
<div class="field__item">
<img src="{{ bottom_image|file_uri|image_style('big') }}" alt="{{ bottom_image.alt }}">
</div>
</div>
{% endif %}
</div>
{% endfor %}
{% endblock %}

Is it possible to replace the social media icons in HubSpot's codebase?

I am new to this platform and the syntax. We have custom social media icons in our theme. Example:
<a href="{{ module.link_sharetw }}" class="share-button twitter">
<img src="{{ get_asset_url('/greenpeace_p4_theme/assets/twitter.svg') }}" />
</a>
I would like to replace the default icons used in the social sharing module here. Is it possible?
{% set size = "24px" %}
{% set borderRadius = "3px" %}
{% set linkStyle = "width:"~size~";border-width:0px;border:0px;text-decoration:none;" %}
{% set imgStyle = "height:"~size~";width:"~size~";border-radius:"~borderRadius~";border-width:0px;border:0px;" %}
{% macro render_social_icon(networkName) %}
{% set network = module[networkName] %}
{% if (networkName == "pinterest" and network.pinterest_media and network.enabled) or (networkName != "pinterest" and network.enabled) %}
{% if networkName == "pinterest" %}
{% set pinterest_media = module.pinterest.pinterest_media.src %}
{% endif %}
{% set logo = networkName ~'-color.png' %}
{% set urlOperator = "&" if "?" in page_meta.canonical_url else "&" %}
{% if module.link %}
{% set social_link_url = module.link ~ urlOperator ~ "utm_medium=social&utm_source="|safe ~ networkName %}
{% elif content.email_type.blogRssChild %}
{% set social_link_url = content.rss_email_url %}
{% else %}
{% set social_link_url = page_meta.canonical_url ~ urlOperator ~ "utm_medium=social&utm_source="|safe ~ networkName %}
{% endif %}
<a href="{{ network.custom_link_format }}" target="_blank" rel="noopener" style="{{ linkStyle }}" >
<img src="{{ module_asset_url(logo) }}" class="hs-image-widget hs-image-social-sharing-24" style="{{ imgStyle }}" width="{{ size }}" hspace="0" alt='{{ "Share on " ~ networkName }}' />
</a>
{% endif %}
{% endmacro %}
<div class="hs_cos_wrapper hs_cos_wrapper_widget hs_cos_wrapper_type_social_sharing" data-hs-cos-general-type="widget" data-hs-cos-type="social_sharing">
{{ render_social_icon('facebook') }}
{{ render_social_icon('linkedin') }}
{{ render_social_icon('share_twitter') }}
{{ render_social_icon('pinterest') }}
{{ render_social_icon('email') }}
</div>
I know there is a way to replace social media icons in the module inspector but it only takes pngs.
On line 12 you have a
{% set logo = networkName ~'-color.png' %}
which is defining the name expected for the icon. Change .png to .svg and it should render just fine.

twig attrbutes.addclass nesting issue

Apologies if this has been asked before, but I'm on my first week working with Drupal and Twig.
I have the following code:
{%
set container_classes = [
'paragraph',
'paragraph--type--' ~ paragraph.bundle|clean_class,
view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
not paragraph.isPublished() ? 'paragraph--unpublished',
'container'
]
%}
{% set image_classes = [
'col-12'
]
%}
{% block paragraph %}
{% block content %}
<div{{ attributes.addClass(container_classes) }}>
<div class='row'>
<div{{ attributes.addClass(image_classes) }} data-type='image'>
{{ content.field_two_column_image }}
</div>
<div class='col-12 col-lg-auto' data-type='copy'>
{{ content.field_two_column_copy }}
</div>
</div?>
</div>
{% endblock %}
{% endblock paragraph %}
My issue is the nested attributes.addClass. When I look at the HTML, I'm also seeing the container_classes classes, which is not what I'm looking for.
So how can I separate the two?
You can Create Attributes in Twig.
Something like this should work.
{# attributes for container #}
{% set container_attributes = create_attribute() %}
{%
set container_classes = [
'paragraph',
'paragraph--type--' ~ paragraph.bundle|clean_class,
view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
not paragraph.isPublished() ? 'paragraph--unpublished',
'container'
]
%}
{% set container_attributes = container_attributes.addClass(container_classes) %}
{# attributes for image #}
{% set image_attributes = create_attribute() %}
{% set image_classes = [
'col-12'
]
%}
{% set image_attributes = image_attributes.addClass(image_classes) %}
{% block paragraph %}
{% block content %}
<div{{ container_attributes }}>
<div class='row'>
<div{{ image_attributes }} data-type='image'>
{{ content.field_two_column_image }}
</div>
<div class='col-12 col-lg-auto' data-type='copy'>
{{ content.field_two_column_copy }}
</div>
</div?>
</div>
{% endblock %}
{% endblock paragraph %}

Don't know what I am doing wrong in below code in twig for counter

Counter always printing 1
{% if label_hidden %}
{% if multiple %}
{% for item in items %}
{{ item.content }}
{% endfor %}
{% else %}
/* counter set below for incriment */
{% set counter = 1 %}
{% for item in items %}
{{ counter }}
/* condition check*/
{% if counter == 2 %}
<div class="spectra-promo col-md-6 spectra-offer-info">
<h3>{{ item.content }}</h3>
{% endif %}
/* condition check*/
{% if counter == 3 %}
<h5>{{ item.content }}</h5>
<div class="choose-offer">
<div class="left-sec">
{% endif %}
/* condition check*/
{% if counter == 4 %}
<p>{{ item.content }}</p>
<div class="right-sec">
<p><i class="fa fa-angle-right" aria- hidden="true"></i></p>
</div>
</div>
</div>
{% endif %}
/* counter increment below */
{% set counter = counter + 1 %}
{% endfor %}
{% endif %}
{% endif %}
Instead of creating a counter, you can directly use the loop variable:
{% if label_hidden %}
{% if multiple %}
{% for item in items %}
{{ item.content }}
{% endfor %}
{% else %}
{% for item in items %}
{{ loop.index }}
/* condition check*/
{% if loop.index == 2 %}
<div class="spectra-promo col-md-6 spectra-offer-info">
<h3>{{ item.content }}</h3>
{% endif %}
/* condition check*/
{% if loop.index == 3 %}
<h5>{{ item.content }}</h5>
<div class="choose-offer">
<div class="left-sec">
{% endif %}
/* condition check*/
{% if loop.index == 4 %}
<p>{{ item.content }}</p>
<div class="right-sec">
<p><i class="fa fa-angle-right" aria- hidden="true"></i></p>
</div>
</div>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endif %}

Resources