Find-and-replace with Liquid, adding classes to blog article images

50 2 15

Hey guys! Here's something I learned recently, and wanted to share, since I searched the forums for similar solutions without finding much.


While the Shopify blog editor gives you a simple WYSIWYG interface for composing the contents of posts, and the ability to add simple HTML markup, I was unsatisfied with the necessity of manually wrapping images and iframe elements (YouTube embeds) in responsive classes (the theme in question uses Bootstrap CSS for layout). It seemed like this was something the theme itself should do. Additionally, I had a storefront with many pages of posts, and I wasn’t about to retroactively wrap every post element in HTML for responsive display.


Using the split and join filters, I was able to parse through the string generated by article.content, outputting HTML with the divs and classes needed to display the blog content properly on mobile devices!


I condensed my experience into a post, and a GitHub gist, which I hope others find useful! Also, see code below, which I have currently implemented in article.liquid.


{% assign split_by_img = article.content | split:'<img' %}
{% assign article_content = split_by_img | join: '<img class="img-fluid"' %}

{% assign split_by_iframe = article_content | split:'<iframe' %}
{% assign article_content = split_by_iframe | join: '<iframe
  class="embed-responsive-item"' %}

{% assign split_by_iframe = article_content | split:'<iframe' %}
{% assign article_content = split_by_iframe | join: '<div
  class="embed-responsive embed-responsive-16by9"><iframe' %}

{% assign split_by_iframe = article_content | split:'</iframe>' %}
{% assign article_content = split_by_iframe | join: '</iframe></div>' %}


<div class="rte">
  {{ article_content }}
13 1 3

Good stuff, did you manage to test this out for performance? Since we're making liquid calls to the server to split/join elements on load.

Need shopify help? Drop us an email
50 2 15
Great question! I did some profiling this morning, and decided to update my post with the results.
I created a blog article with 80 iframe element and 80 images. The iframes were empty, and the images were identical 616 x 411 jpgs displayed at their original resolution. To measure load times, I used the Chrome DevTools Network tab and refreshed the page. The page was hosted locally in the Slate environment.
To make sure the page was not being cached, I removed article.content from the page between tests, made sure the page was clear, then added in the processing code and hit refresh. I did this three times for each technique.
In addition to the split/join code I shared, I tested the results of chaining multiple replace filters together to achieve the same result. This did not improve performance, and while the code is more compact, it's far less readable. See below.
Outputting article.content on the page with no processing:
  • Load times: 3.68s 3.78s 3.23s
  • Average 3.56s
Split-join filters:
  • Load times: 3.34s 3.57s 3.36s
  • Average 3.42s
Replace filter chain:
  • Load times: 3.07s 3.81s 4.16s
  • Average: 3.68s

Code for replace chain:

{% assign article_content = article.content | replace: '<img', '<img class="img-fluid"' | replace: '<iframe', '<div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item"' | replace: '</iframe>','</iframe></div>' %}
16 1 4

Such a great post, thank you so much for sharing. A rare gem on here!

New Member
2 0 1

Nice. This looks like a great way to add lazyloading to blog images as well!


    {% assign split_by_img = article.content | split:'<img' %}
    {% assign article_content = split_by_img | join: '<img class="lazyload image--fade-in"' %}