How to merge string to an array? - twig

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

Related

Multiple Load More OOB Button Sprig

I am trying to create multiple dynamic load more oob buttons using Sprig plugin in Craft CMS and they are appearing properly. But the issue comes up when one button is due to be swapped with the hidden one, it results to all the load more buttons disappearing.
Here is the for loop code that I have tested:
{% for city in cities %}
{% set articleOffset = articleOffset ?? 0 %}
{% set articlesQuery = cityArticles[loop.index0].offset(articleOffset).limit(articleLimit) %}
{% set articles = articlesQuery.all() %}
<div class="filtered-bookmark mb-5">
<span> {{ city.title }}</span>
<div class="row" id="container-{{ city.slug }}">
{% for article in articles %}
{% set featureImage = article.articleFeaturedImage.one().url ?? "" %}
{% set categorySlug = article.channelsCategory.one().channel.one().slug %}
<section class="col-12 col-sm-6 col-xl-4 mb-4">
{#article card template here#}
</section>
{% endfor %}
</div>
{% if articlesQuery.count() > articles|length + articleOffset %}
<button id="{{city.slug}}-oob" sprig
s-val:articleOffset="{{ articleOffset + articleLimit }}"
s-target="#container-{{ city.slug }}"
s-select="#container-{{ city.slug }} section"
s-swap="beforeend"
{{ sprig.trigger == city.slug ~ '-oob' ? 's-swap-oob="true"' }}> View More </button>
{% else %}
<button id="{{ city.slug }}-oob" s-swap-oob="true" style="display: none"></button>
{% endif %}
</div>
{% endfor %}
Asked the question on PutYourLightsOn's Sprig GitHub and got a response. This did the trick:
<button id="{{ city.slug }}-oob" {{ sprig.trigger == city.slug ~ '-oob' ? 's-swap-oob="true"' }} style="display: none"></button>
GitHub link for reference:
https://github.com/putyourlightson/craft-sprig/issues/247

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 %}

Jekyll pagination with data files

I was looking to try to do pagination with the _data files. Here is the code that I was coming up with but it doesn't work. Trying to make it work for a project I am working on right now for a nonprofit client I have.
{% if page.layout == "events" %}
{% for events in paginator.events %}
<div class="card card-posts">
<img src="{{ events.image }}" class="card-img-top" alt="...">
<div class="card-body">
<h1 class="card-title my-3">{{ events.title }}</h1>
<div class="meta-info">
<ul class="list-inline">
{% if events.start %}
<li class="list-inline-item">
<i class="fas fa-calendar-alt"></i> {{ events.start | date_to_long_string }}
</li>
{% endif %}
</ul>
</div>
<p class="card-text">{{ events.summary }}</p>
</div>
</div>
{% endfor %}
{% if paginator.total_pages > 1 %}
<!--pagination-->
<div class="pagination bot-element">
<div class="pr-bg pr-bg-white"></div>
<div class="container">
{% if paginator.previous_page %}
<i class="fal fa-long-arrow-left"></i>
{% endif %}
{% if paginator.page_trail %}
{% for trail in paginator.page_trail %}
{{ trail.num }}
{% endfor %}
{% endif %}
{% if paginator.next_page %}
<i class="fal fa-long-arrow-right"></i>
{% endif %}
</div>
</div>
<!--pagination end-->
{% endif %}
{% endif %}
Can someone see if this is a way possible that might have done this? If it is would it be ideal to do it for an events page to show an archive of events or no?

Jinja2 list index variable - list_name[variable]

I'm trying to pass on the variable, prod_number, to the index of a list, products.
<div class="container">
{% for i in range(lenProducts) %}
<ul class="row product-grid">
{% for j in range(0, 3) %}
<br>
<p class="text-primary"> {% set prod_number = i*3+j %} </p>
<li class="col-md-4 product-wrapper card">
{{ products[prod_number].id }}
</li>
{% endfor %}
</ul>
{% endfor %}
{{ products[prod_number].id }} This line makes the page load forever
How can I fix this? I've isolated the problem and I'm 100% sure it's from that line.
I think this would work :
<div class="container">
{% for i in range(lenProducts) %}
<ul class="row product-grid">
{% for j in range(0, 3) %}
<br>
<p class="text-primary"> {% set prod_number = (i*3)+j %} </p>
<li class="col-md-4 product-wrapper card">
{{ products[prod_number]['id'] }}
</li>
{% endfor %}
</ul>
{% endfor %}
The problem was that the prod_number exceeded the products length and it caused my page to load forever.
prod_number went from 0 to 17 and products had only 6 elements in it.

Using Twig to declare template and pass in additional content between the parent template's block

I have the following code that I repeat multiple times in my layout:
<div id="hi">
<div class="howAreYou">
<p class="fineTYForAsking">
<!-- additional HTML logic goes here -->
</p>
</div>
</div>
How can I put in the above html into a single Twig template, and then use that template and put in my additional specific html in the <!-- additional HTML logic goes here --> section?
You could just define blocks and embed the template where ever you want
partial.twig.html
<div id="{{ id | default('hi') }}">
<div class="howAreYou">
<p class="fineTYForAsking">
{% block content %}
{% endblock %}
</p>
</div>
</div>
template.twig.html
{% embed "partial.html.twig" with { 'id' : 'foo' } %}
{% block content %}
Lorem Ipsum
{% endblock %}
{% endembed %}
You could also use an embed in a for-loop. Variables known inside the loop, are also know in the embedded file, e.g.
item.html.twig
<div{% if item.id|default %} id="{{ item.id }}"{% endif %}>
<div class="howAreYou">
<p class="fineTYForAsking">
{% block title %}
{% if item.title is defined %}
<h1>{{ item.title }}</h1>
{% endif %}
{% endblock %}
{% block content %}
{% if item.content is defined %}
<p>{{ item.content }}</p>
{% endif %}
{% endblock %}
</p>
</div>
</div>
template.html.twig
{% for item in items %}
{% embed "item.twig" %}
{% endembed %}
{% endfor %}
demo

Resources