How to use Twig_Markup object type in an If statement - twig

I want to reuse pretty heavy logic only code a few times, in php I would use a function, but in twig I went with a solution from this old question.
In short, I use a macro like that:
{% import _self as test %}
{% macro check() %}
{{ test }}
{% endmacro %}
{% set v = test.check() %}
{% if v == 'test' %}
this should display
{% endif %}
Here is a fiddle: https://twigfiddle.com/kyv3zr/2
The problem is that v is a Twig_markup object. It doesn't seem to have any public properties. Running dump on it gives me this:
object(Twig_Markup)#1244 (2) { ["content":protected]=> string(13) " 1 " ["charset":protected]=> string(5) "UTF-8" }
How do I use it in an if statement?
Or is there a better way of storing a logic only code for reuse across templates?

If the object is called v then the dump seems to show it has a content value, so try:
{% if v.content == '1' %}
{# do something here #}
{% endif %}
not certain though, but try it.
EDIT #2 - based on comments question.
So I guess if you want to use v in an if statement, you would use it like so:
{% if v == '1' %}
{# do something here #}
{% endif %}
This presumes it does equal to "1".

Related

Check if all elements in one array are contained by another | JS Array.every() equivalent

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

Twig strip textarea and create array

I'm trying to strip some text from a value and afterwards create an array from it with the stripped values.
I'm having troubles to strip the text value.
I can only do this on the frontend since I have no access to the backend (SaaS platform)
In below example value.value (originally a textarea) returns the following text:
[185047078]1x something - Type 1
[415533322]1x something - something
[152890667]1x something 500x500 mm
I want to strip the text so I have [185047078], [415533322], [152890667] left or without the brackets.
Normally in JS you would do something like:
hide_ids = txt.match(/[^\]\[]+(?=\])/g)
However it need to be done in Twig.
Afterwards I want to push the values into an array hide_ids.
{% set hide_ids = [] %}
{% if product.custom %}
{% for custom in product.custom %}
{% if 'Some title' in custom.title %}
{% for value in custom.values %}
{% set hide_this_id = value.value %}
{% if hide_this_id matches '{/[^\]\[]+(?=\])/g}' %}
{% set hide_ids = hide_ids | merge([hide_this_id]) %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% set hidden = false %}
{% if id in hide_ids %}
{% set hidden = true %}
{% endif %}
What is the equivalent of match in Twig? I also tried replace but I just can't get that text stripped.
Any help greatly appreciated!
You could go with some simple string functions.
{% for id in ids %}
{{ id | split(']', 2)[0] | replace({'[': '',}) }}
{% endfor %}
demo
split is the explode of twig. This will separate your string in chased based on the ] character. The 2nd parameter (2) ensures there will only be maximum 2 parts in the array.
replace is just str_replace
If you wanted to solve this with regex you would either need to write a function/filter with preg_match or install an extension like this

TWIG / GravCMS: Use loop-variable of for-loop inside modular template

Here is my current code:
{% for module in page.collection() %}
{% set index = loop.index %}
{{ module.content|raw }}
{% endfor %}
I'd like to access index inside the module.html.twig, or even better, the entire loop variable.
How do I do that?
I found it myself:
{% for module in page.collection() if not module.header.visible is same as(false) %}
{% include module.template ~ '.html.twig' with {'page':module, 'loop':loop} %}
{% endfor %}
This loop willautomatically grab the template which is linked to the modular page and pass the required variables down. Also, the loop will only include modular subpages which are not hidden. Great, isn't it?

NUNJUCKS: How to access a variable set inside a macro outside it?

I am passing something to a macro and performing some operations on it. I am storing the result in a variable. Now I want to access this variable outside the macro.
Is there a way we can do this?
Example:
{% macro setexpression() %}
{% set expression = "Hello World!" %}
{% endmacro %}
I call the macro and expression should be available outside.
{{ setexpression() }}
{{ expression }} // This should return Hello World!
I found a hacky way to do this.
{% macro returnSomething() %}
{% set returnVar = "Hello there" %}
{{returnVar}}
{% endmacro %}
And then, the calling code will be:
{% set returned = returnSomething() %}
{{returned}} // this will have 'Hello there' in it
Is there a better way in which I can achieve the same?

Twig replace part of string with chosen character

I want to replace part of string characters with asterisks in Twig.
For example:
SomePartlyVisibleStringHere
I want to change every letter after 4th in this string with asterisks, to have result like that:
Some*********************
Is it possible to do without defining new Twig helper?
You could make a macro (a function in Twig) and call it whenever you want to do this.
{% macro redact(topSecret) %}
{% set length = topSecret|length - 4 %}
{{ topSecret|slice(0, 3) }}{% for i in 0..length %}*{% endfor %}
{% endmacro %}
{# You have to import from _self if the macro is declared in the same file. #}
{% import _self as sharpie %}
{{ sharpie.redact('Top secret information') }}
{# => Top******************* #}
Example: https://twigfiddle.com/aobt8s
This worked for me:
{% set string = 'SomePartlyVisibleStringHere' %}
{% set starCount = string|length - 4 %}
{{ string[:4] }}{% for i in 1..starCount %}*{% endfor %}
If you have to do it more than once I would suggest making a custom filter, then you can just do:
{% set string = 'SomePartlyVisibleStringHere' %}
{{ string|customFilterName }}

Resources