I'm looping over a collection of blog posts (Twig for loop) which appearance depends on tags given.
Here a quick example: I want to display all blog posts that have the tags "foo" and "bar". It seems pretty easy to check if a post has one of the tags. However it seems that checking if both tags are contained by a blog post isn't trivial. What I want to accomplish is what the array.every() method in javascript does.
That's my current solution which works as expected but feels kinda fiddly and overcomplicated:
{% set given_tags_array = data.tags|split(',') %}
{% for post in posts %}
{% set post_categories_array = post.categories|map(category => category.name) %}
{% set bool_buffer_array = [] %}
{# push comparison result in bool array #}
{% for tag in given_tags_array %}
{% set bool_buffer_array = bool_buffer_array|merge([tag in post_categories_array]) %}
{% endfor %}
{# only display posts where all tags match #}
{% if false in bool_buffer_array %}
{% else %}
{# post data goes here #}
{% endif %}
{% endfor %}
As you can see inside the posts loop I'm checking if every given tag (i.e. "foo" and "bar") is part of the post categories array. I'm pushing the comparison result (boolean) to an empty array to check for any false values afterwards. Why an array? I tried using a simple boolean variable but if any of the given tags is in the post categories array it resolves to true, which isn't exactly what I want.
So something like that doesn't work for me unfortunately:
{% for post in posts %}
{% set post_categories_array = post.categories|map(category => category.name)|sort|join('') %}
{% if given_tags_array|filter(given_tag => given_tag in post_categories_array) %}
{# post data goes here #}
{% endif %}
{% endfor %}
With this method I'm always doing an or comparison instead of an and comparison...
So...am I missing something and is there a simpler way to do that twig only?
Using the code you've already provided:
{% set temp = given_tags_array|filter(given_tag => given_tag in post_categories_array) %}
The filter filter
returns a new array, this means temp
should contain as many elements as your given_tags_array
, if they are all inside the post_categories_array
.
So if I'm not mistaken you could change your check to the following
{% for post in posts %}
{% set post_categories_array = post.categories|map(category => category.name)|sort|join('') %}
{% set temp = given_tags_array|filter(given_tag => given_tag in post_categories_array) %}
{% if temp|length == given_tags_array|length %}
{# display post #}
{% endif %}
{% endfor %}