liquid
liquid copied to clipboard
{% liquid %} tag template literals
We have been transitioning over to using the new liquid tags both in our premium themes and with our Shopify Plus clients and have seen an improvement in performance and code maintainability.
When using capture inside the liquid tags it currently requires a mess of multiple lines of echo commands to combine strings and standard Liquid objects. Introducing the concept of template literals would be incredibly beneficial and make things more straight forward.
A current basic example of ugly "string interpolation"
{%- liquid
capture media_id
echo 'FeaturedMedia-'
echo section.id
echo '-'
echo media.id
endcapture
-%}
{{ media_id }}
Using the concept of ES6 template literals with String ${var}
would clean things up. Even using the Ruby style version of interpolation would be amazing.
{%- liquid
capture media_id
echo "FeaturedMedia-#{section.id}-#{media.id}"
endcapture
-%}
{{ media_id }}
I have a different kind of ugly:
echo 'FeaturedMedia-' | append: section.id | append: '-' | append: media.id
// or
echo 'FeaturedMedia-\1-\2' | replace: '\1', section.id | replace: '\2', media.id
😆
This wouldn't have been so much of a problem if the liquid
tag allowed regular Liquid code in the middle. But as of now, it enforces closing all opened tags before it closes itself.
Anyway depending on your situation, you could just use the regular tags or you could use include
and put that in another file.
I have a different kind of ugly:
Oh man. I did end up adopting this for my use case, which is outputting json 🤮
echo '{"variant_id": ' | append: variant | append: ', "threshold": ' | append: threshold | append: ', "countries": "' | append: countries | append: '" }'
This is what I had originally assumed would work but of course the {{ }} don't do anything inside an echo
statement
echo '{"variant_id": {{ variant }}, "threshold": {{ threshold }}, "countries": "{{ countries }}" }'
@dgpokl haha yes, the second one won't work because you're making a tag when you're technically already inside another tag. You could throw that into a snippet and call it using render
(or include
) but that's overkill! Before you know it, you'll be filling up the snippets folder with a bunch of tiny files.
@dylanahsmith wouldn't it be nice if echo can evaluate strings for {{ }}
and substitute them with the variables and their filters? Could be non-default with a filter or parameter called evaluate
for example:
assign name = " world "
echo "Hello {{ name | upcase | strip }}."
echo "Hello {{ name | upcase | strip }}." | evaluate
echo "Hello {{ name | capitalize | strip }}!", evaluate
Output:
Hello {{ name | upcase | strip }}. Hello WORLD. Hello World!
Any updates on this? 👀
@tmmgrafikr At this moment, your best choices are the append
hack or the replace
hack.
To me the amazing convenience of the liquid
tag is reason enough to bear with the status quo.
@dgpokl haha yes, the second one won't work because you're making a tag when you're technically already inside another tag. You could throw that into a snippet and call it using
render
(orinclude
) but that's overkill! Before you know it, you'll be filling up the snippets folder with a bunch of tiny files.@dylanahsmith wouldn't it be nice if echo can evaluate strings for
{{ }}
and substitute them with the variables and their filters? Could be non-default with a filter or parameter calledevaluate
for example:assign name = " world " echo "Hello {{ name | upcase | strip }}." echo "Hello {{ name | upcase | strip }}." | evaluate echo "Hello {{ name | capitalize | strip }}!", evaluate
Output:
Hello {{ name | upcase | strip }}. Hello WORLD. Hello World!
A evaluate filter would be immensely useful for our use case. We are Shopify app developers transitioning into the new theme extension framework where writing to templates directly seems to be a no-no. It seems to be recommended that we use metafields instead to save user data.
All good, except when we need user to input liquid code e.g. for app integration purposes so if we store it here -
{{ shop.metafields.app.integration_code }}
which for e.g. evaluates to the judgeme widget code -
'{% render 'judgeme_widgets', widget_type: 'judgeme_review_widget', concierge_install: false, product: product %}'
In the 'old' way, we would write this directly into the template so that this is evaluated directly. Our ideal scenario would be to have this -
{{ shop.metafields.app.integration_code | evaluate }}
Thinking of solutions right now and would be immensely grateful if anyone has any ideas. Thanks!
@hellovoidworks We are running into this exact scenario when trying to update our app to use the theme extension framework. App extension seem great, but not being able to render liquid code that is saved in metafields is a huge problem, especially in terms of creating an upgrade path for existing users.
Have you (or anyone else) figured out a way to handle this?
@hellovoidworks We are running into this exact scenario when trying to update our app to use the theme extension framework. App extension seem great, but not being able to render liquid code that is saved in metafields is a huge problem, especially in terms of creating an upgrade path for existing users.
Have you (or anyone else) figured out a way to handle this?
We do have a less than ideal workaround, but at least it works for the time being i.e. to ask the user to copy and paste any needed liquid code into a 'Custom liquid' section in their theme customisation interface.
Thanks @hellovoidworks. I don't think that will work in our case, but at least it's good to know that we're not the only ones going through growing pains!
@hellovoidworks it seems like you are talking about a completely different issue. The original issue was about adding string interpolation to echo
as a convenience feature for making use of the {% liquid %}
tag less verbose.
still no news for this?
Need this in cases of building HTML, such as brute forcing <style></style>
tags with liquid echo tags due a theme update that moved code from standard _{% for %}_loop to have it's render output inside a liquid tag.
This is what's done now with time available, not perfect refactors
Crude simplified example of previous
{% for block in section.blocks %}
<li>
<style type="text/css">
{%- if block.settings.button_color.alpha != 0.0 -%}
#slideshow-{{section.id}} li:nth-child({{forloop.index}}) { background-color:{{block.settings.button_color}}; }
{%- endif -%}
......
</style>
</li>
...
Converted to an echo output, a valid string, but non-working internal liquid that makes non-working CSS
echo '<style type="text/css">'
...
if block.settings.button_color.alpha != 0.0
echo '#slideshow-{{section.id}} li:nth-child({{forloop.index}}) { background-color:{{block.settings.button_color}}; }'
endif
...
echo '</style>'
The style rule output converted to an echo & replace tactic.
# using square brackets as custom template keys
echo '#slideshow-[[SECTIONID]] li:nth-child([[FORLOOPINDEX]]) { background-color:{{block.settings.button_color}}; }' | replace:'[[SECTIONID]]', section.id | replace:'[[FORLOOPINDEX]]',forloop.index
append & prepend can work sometimes but make for string builders that get complicated real fast.
An alternative is using a capture & replace approach, thought that still leads to having to create a custom template convention, i.e. [[INDEX]] and doing text-to-value substitutions with replace or other filters. And in the case of forloops also needing to place the captured string-placeholder elsewhere in the code to avoid the perf hit of every loop capturing&replacing versus just replacing. Capturing a render snippet inside the liquid tag is another method, though you might as well just parametrize it and for this stuff if there's enough of it in the code just chuck it all into a utils.liquid with function like behavior using case/when statements. Also the method of capture in a liquid tag with many many echos then using newline stripping to build the output.
Though now that I think of it I need to check if there's an echo>endecho behavior? An issue I think runs through this problem is no multiline strings with echo/capture/render. For render I'm noticing themes are starting to make very LOOOOONG render statements inside {% liquid %} tags , 100s-1000s of characters long because the {% liquid %} tag led them to try and consolidate everything. This is because they can't put the template parameters on multiple lines like can be done using the {% render %} tag.