Escaping Liquid tags

by Taylor Fausak on

Every so often, I post code samples that contain things that look like Liquid tags, so I have to escape them. This turned out to be harder than I thought. I went through four tries, each better than the last.

The Ugly

The first method works by using Liquid to output a string, and then using that to break up the thing that needs to be escaped so that Liquid won’t parse it. Outputting a string with Liquid is easy:

{{ "thing" }}
# => thing

Then you can use that to separate the opening tag from the closing tag:

{{ "{% thing " }}%}
# => {% thing %}
{{ "{{ thing " }}}}
# => {{ thing }}

I find this method to be ugly and non-obvious, so I don’t recommend it. It is, however, pretty clever. And it works with all versions of Liquid.

The Bad

If you’re outputting something that looks like Liquid output, you can escape it by assigning it to a variable, then outputting the variable.

{% assign thing = "{{ thing }}" %}
# => {{ thing }}

This does not work if you want to output a Liquid tag like {% thing %} because the closing tag trips up Liquid’s parser. And of course this method gets annoying if you need to escape a lot of things. For those reasons, I can’t recommend it either.

The Good

Finally we arrive at a reasonable solution. Liquid 2.2.2 added support for the {% literal %} tag, making escaping anything a piece of cake. It behaves exactly like you’d expect it to:

{% literal %}{% thing %}{% endliteral %}
# => {% thing %}
{% literal %}{{ thing }}{% endliteral %}
# => {{ thing }}

This would be perfect, but Liquid removed support for it somewhere along the line. For some reason, GitHub Pages still supports this syntax. If you never test your site locally and only deploy to GitHub Pages, this should work for you. That being said, I can’t recommend it because the next method is just as good and it works everywhere.

Il Buono

The final and best method is the {% raw %} tag. It’s just like the {% literal %} tag, except it works with Liquid 2.4.1, which is what GitHub Pages uses.

{% raw %}{% thing %}{% endraw %}
# => {% thing %}
{% raw %}{{ thing }}{% endraw %}
# => {{ thing }}

This is the recommended way to escape Liquid tags. It’s straightforward and supported everywhere. The only time you can’t use this method is when you need to escape a literal {% endraw %}, since that will trip up the Liquid parser. If you need to do that, I suggest the following:

{{ "{% endraw " }}%}
# => {% endraw %}

What’s really going to bake your noodle later on is, how did I write this blog post? Check out the source for that.