Im building a store in shopify and Im fairly new at this.
I want to interpolate a collection.handle inside an interpolation, like this:
style="color: {{ settings.tomas_{{collection.handle}} }} !important;"
this is in order to create a dry formula to modify the css for every collection. Ive created my page colors in settings with this pattern:
tomas_example_collection: "FFF",
tomas_second: "F1F1F1"
And they work if I hard code them, but I dont know how to interpolate inside an interpolation.
What would you recommend?
Thanks!!!
You can't pass liquid inside liquid.
You need to generate the target string outside before passing it.
In your case:
{%- assign target = 'tomas_' | append: collection.handle -%}
style="color: {{ settings[target] }} !important;"
We create a variable that will hold the string and pass it using square brackets to the settings object.
Related
Using assignVar and getVar (Bigcommerce Handlebars helpers) I'm trying to create and insert a javascript variable like so:
<script>var exampleVar = "string";</script>
{{ assignVar "exampleVar" exampleVar}}
The result when using {{ getVar"exampleVar" }} is that it throws a "not a string error".
I tried {{ assignVar "exampleVar" "exampleVar"}} which outputs "exampleVar" (minus the quotes). I would like it to output "string" (minus the quotes).
Any thoughts?
You can't. Handlebars is already compiled in the server before it reaches the front end side. If the logic is done in javascript, then you should display the result via javascript too.
I'm new to using Hugo and Go Templates. How can I access a variable from a partial file that is defined in base file using Hugo?
For eg: I have an index.html file which contains code that reads the data stored in the events.json file in the data directory and stores it in a variable. How can I access that variable from another file?
index.html
{{ $events := .Site.Data.events }}
{{ partial "people" . }}
people.html
// access the events variable from the index.html
{{ $events }}
I really hope this makes sense. I can try and clarify more if needed.
0.15 introduced a map that can be used for this.
index.html
{{ $events := .Site.Data.events }}
{{ partial "people" (dict "events" $events) }}
people.html
// access the events variable from the index.html
{{ .events }}
You could use the dict func:
{{ partial "people" (dict "page" . "events" $events) }}
You will then address them like {{ .page.someVar }} and {{ .events.someVar }} in the partial.
An alternative in your case could maybe, in the partial (as the previous poster said), address the .Site.Data.events directly from the partial.
According to Hugo documentation:
... partial calls receive two parameters.
The first is the name of the partial and determines the file location to be read.
The second is the variables to be passed down to the partial.
This means that the partial will only be able to access those variables. It is isolated and has no access to the outer scope.
This means, the events variable is outside of the scope of people.html. Your people.html cannot "see" it. One solution would be pass it down, like:
{{ partial "people" . $events }}
If it does not work, try different notation ($ vs. .).
If that does not work, you can always call your data file again, without variable, just like in the examples, that is, use {{ .Site.Data.events }} in your people.html partial.
Let me know in the comments how it goes, I'll try to improve my answer if necessary. I know it's a pain to get out of Hugo boundaries into Go territory :)
I am looking for a way to add a class to a block, but not a custom class, a class from either the region name or the block machine name.
For example, with regions, this is possible:
{%
set classes = [ 'region-' ~ region|clean_class]
%}
And every divs would have the name of the region (defined in the info.yml file) as a class. I want to do the same thing with blocks. Either add the name of the region or the machine name as a class. The reason that I want a class is for CSS. It's better practice to target elements usings classes than IDs.
Does anyone know how to achieve that programmatically?
1) Twig on Drupal 8.x understands only variables and basic operations with variables. So in order to use custom variables (such as the block region) you need to pass the variables usually on a preprocess function and then use them inside Twig. Here is an example:
function MYTHEME_preprocess_block(&$variables, $hook) {
$block_id = $variables['elements']['#id'];
$block = \Drupal\block\Entity\Block::load($block_id);
// Add region as variable
$variables['region'] = $block->getRegion();
}
and then on block.html.twig file:
{%
set classes = ['region-'~region|clean_class]
%}
See the docs: https://www.drupal.org/docs/8/theming/twig/twig-best-practices-preprocess-functions-and-templates.
2) If you want to have custom block template suggestions (eg for a region) you can alter default theme suggestions using hook_theme_suggestions_alter().
function MYTHEME_theme_suggestions_block_alter(array &$suggestions, array $variables) {
if ($variables['elements']['#configuration']['region']) {
$suggestions[] = 'block__' . $variables['elements']['#configuration']['region'];
}
}
3) Notice that you are not able to use region specific Drupal block twig templates by default because this functionality removed on 8.x. See related post: https://www.drupal.org/node/2011434.
The easiest way would be to use a contributed module such as block_class
I wanted this too and came across this SO post and OPs Drupal forum post of the same question while looking for an answer. Seeing as I think this answers what we were asking I thought I'd link it here for posterity.
From the Drupal forum comments use this snippet by Jeff Burnz in your block twig template:
{%
set classes = [
'block',
'block-' ~ attributes.id,
'block-' ~ plugin_id|clean_class,
label ? 'block-label-' ~ label|clean_class,
]
%}
<div{{ attributes.addClass(classes) }}>
This gives you a few options for classes, attributes.id is the one I wanted, and if you use just that it outputs
<div id="blockID" class="block-blockId"...
I hate styling by ids so will add this to all subthemes I work on from now on. Hope this helps.
In my Drupal project I'm unable to access values of a field-collection. I can output all values by using:
{{ item.content }}
But I'm not able to get deeper nested values, which are objects.
For example I would like to get the value «field_interpret».
This things don't work:
{{ item.content['#field_collection_item'] }}
{{ item.content.#field_collection_item }}
{{ item.content.field_collection_item }}
Thank you for help.
After several days of searching and testing I ended up with a plain old and dirty sql-query which I included in the preprocess_field function.
My problem was, that I don't found a way to access the elements in a field-collection and I had to make some calculation based on the field values.
In messages.en.yml, I have
confirmed: Congrats %username%, your account is now activated.
But I want to 'bold' username to example ... how can I made this ?
confirmed: Congrats <span class='bold'>%username%</span>, your account is now activated.
Of course I could use two sentence in this example like
first: Congrats
second: , your account ...
and inside twig use the html tag but this seems very dirty.
Update 2
In such cases, I started to use like this:
confirmed: Congrats %start_link%%username%%end_link%, your account is now activated
Since separation of concerns is maintained, this way is strongly recommended.
Update
In YAML, I have used translations like this without any problem:
trans.key: click here to continue
Although translations and design should be kept separated there are always some situations that you must use html tags inside translation files as it is also seen in huge projects like Facebook and Twitter.
In such situations, you can use XLIFF format which is being recommended by Symfony. Inside translation file:
<trans-unit id="1">
<source>confirmed</source>
<target>Congrats <![CDATA[<span class='bold'>%username%</span>]]> , your account is now activated.</target>
</trans-unit>
Twig's Raw Filter
I don't know if this was an option back in 2013 but when using translation, you can apply the raw twig filter having this translation string:
confirmed: Congrats <span class='bold'>%username%</span>,
your account is now activated.
And use it in twig like this:
{{ 'confirmed'|trans|raw }}
This will not escape the html inside the string and will display the username as bold.
Update: I haven't seen the comment the first time, but Rvanlaak had proposed the raw filter solution in the first place.
Security issues
Note that the content of those translation strings must not be user provided, because it could open up your application to XSS attacks. Using the raw filter allows JavaScript to be executed if a malicious user is able to input custom data into the translation strings (Community based translations for example)
Separation of concerns
Using the raw filter does not comply with separation of concerns as the content and styling are bound together. As Ferhad mentioned, using his method, separation of concern will be maintained. But in my case, I preferred using a simple raw filter. I felt that for my case, Ferhad's method was a bit overkill for me, though it would be more recommended his way
My approach is although still ugly, but at least respects the separation of concerns. Escape filter is used to escape a variable, making the final result is pretty safe from XSS, because all other sources considered to be hard-coded.
translations.yml
points: You have %num% points left.
template.html.twig
{% set pointsFormatted = '<span class="points">' ~ num | escape ~ '</span>' %}
{{ 'pages.score.points' | trans({'%num%' : pointsFormatted}) | raw }}
I've just found something out, you can use this in your YAML file:
mind: >
<i>Mind is a nice thing to have</i>
So this ">" sign in the first row achieves it. I think this would be the preferred way, better than handling the escapes etc in TWIG.
I've looked it up now and it is actually a YAML feature. Check here :)
Also, there's an earlier question with similar subject: How can I get YAML to ignore raw HTML in same file.
some yml:
dashboard:
hello: Hello <b>%username%</b>
+
{{ 'dashboard.hello'|trans({'%username%': app.user.username}, 'General') | raw }}
this | raw part worked for me
In my opinion, this is the best solution today:
'key'|trans({'%username%': '<strong>' ~ suspiciousVar|escape ~ '</strong>'})|raw
The only risk here is stored XSS in your translation files.
Holding HTML stuff in translations is wrong, because translators usually break it. But if you really need it:
Twig:
{% trans %}confirmed{% endtrans %}
Yaml translation file:
confirmed: 'Congrats <span class="bold">%username%</span>, your account is now activated.'
Discussion about this:
https://github.com/symfony/symfony/issues/2713
We could use separate twig snippets for different languages if situation requires heavy formatting differences. I wrote a little blog on this.
{# templates/translations/user_message.pl.html.twig #}
{{ 'msg.my_favourite_language_is' }}<b>{{ 'langnames.elfic_language' | trans | lower }}</b>!
{# templates/translations/user_message.en.html.twig #}
{{ 'msg.my_favourite_language_is' }}<i>{{ 'langnames.elfic_language' | trans | ucfirst }}</i>!
{# templates/pages/index.html.twig #}
{% set locale=app.request.locale[:2] %}
{% include 'translations/calculator_message.' ~ locale ~ '.html.twig' %}
Translation files are for translations, design and layout is part of the view layer (namely: template engine (twig)). You can split it into two pieces: congrats and account.activated.