Skip to content
Log in

Liquid tag options

On this page

Most StoreConnect Liquid tags take options: comma-separated key: value pairs written after the tag name. This article covers the option syntax they all share, and a change in v22 that affects any theme passing stored text into a tag option.

Option syntax

```liquid

{% render “product-card”, label: “Add to cart”, product: product, featured: true %} ```

An option value can be a quoted string, a variable, true or false, or a list:

```liquid

{% render “gallery”, items: [1, “2”, variable] %} ```

A string starting with t. is looked up as a translation key rather than printed:

```liquid

{% render “product-card”, label: “t.products.add_to_cart” %} ```

Markup in an option value

Liquid markup written directly in an option value is rendered:

```liquid

{% render “greeting”, label: “Hi {{ current_customer.firstname }}” %} ```

Markup renders only where you write it in the template. A variable is read for its value, and that value is treated as text, never as a template to run.

:::warning This is a change in v22, and it is the one breaking change v22 asks theme developers to act on. Before v22, a value arriving from a variable was executed as Liquid. A theme that passes stored markup into a tag option renders differently from v22 onward. :::

What no longer works

Say a merchant types Save {{ discount }}% into a custom text field on the product, and the theme passes that field to a tag:

```liquid

{% render “badge”, label: product.data[‘Badge_Text__c’] %} ```

From v22 the badge shows the literal text Save {{ discount }}%, braces and all. The stored markup is data, so it is printed rather than executed.

How to find affected templates

Whenever an option value’s text contains {{ or {% and is printed rather than executed, an error appears in the Liquid Console naming the option and showing the value. Work through your templates with the console open rather than reading them by eye. See Debugging and performance.

Each option and value is reported once, so a tag inside a loop over many records gives you one error rather than one per record. A page with several affected tags still reports each of them.

Two ways to rewrite it

Write the markup in the template, where you can see it:

```liquid

{% assign discount = 20 %} {% render “badge”, label: “Save {{ discount }}%” %} ```

To combine a merchant’s own text with markup, build the value first and pass the result:

```liquid

{% assign discount = 20 %} {% capture badge_label %}{{ product.data[‘Badge_Text__c’] }} - save {{ discount }}%{% endcapture %} {% render “badge”, label: badge_label %} ```

A capture holds text, so this puts the markup where you can see it. Note that a capture is a way to build a value, not a way to opt out of the change: a captured value, an assigned value, and a field read straight from a record are all treated the same way.

The same rule applies to {% update %}, which takes its options through the same parser.

The setting that restores the old behavior

A tenant can be set to execute markup that arrives from a variable, through the liquid_interpolate_tag_option_values tenant setting, or the SC_LIQUID_INTERPOLATE_TAG_OPTION_VALUES environment variable for every tenant that has not set its own value. A tenant’s own setting wins, so a tenant that sets it to false stays off even where the environment variable turns it on.

Neither is a store setting. The setting applies to every store in the tenant, and it cannot be turned on for one store and left off for another. StoreConnect holds this configuration, so ask support if you need it changed.

:::warning Turning this on is not recommended, and it is not only a formatting change. With the setting on, text a merchant or a customer has entered is executed as Liquid wherever a theme passes it to a tag option. Anyone who can type into a product description, a custom field, or a form submission can run template code on your storefront, with the same reach any theme code has: it can read records with {% query %} and make outbound HTTP requests with {% api %}. One string typed into a field can read customer records and send them to an address outside your store. HTML escaping does not prevent this, because it does not escape Liquid’s braces.

Treat it as a short-term measure while templates are updated, and have it turned off again afterward. :::

Markup you write in your own templates is unaffected either way, and so is printing a value with {{ ... }}. That text is printed, never executed, whichever way the setting is set. The setting changes only what happens to a value passed to a tag option.

Was this article helpful?

Was this article helpful?