Introduce a new concept to conditionally render block of content
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 11.9k
- Forks
- 1.5k
- Avg merge
- 17h 55m
- Merged PRs (30d)
- 3
Description
Hi :),
This is a proposal for a new Liquid feature that aimed to simplify code for complex templates. With increased complexity of themes, and new features such as dynamic metafield sources, writing DOM that stays clean requires more and more boilerplate code that does not scale well and can be error-prone.
Problem
Imagine you have a heading and subheading setting. In order to avoid generating useless elements in the DOM, one common approach is to wrap them around a condition:
{% if section.settings.title != blank or section.settings.subheading != blank %}
<div class="section-header">
{% if section.settings.title %}
<h2>{{ section.settings.title }}</h2>
{% endif %}
{% if section.settings.subheading %}
<h2>{{ section.settings.subheading }}</h2>
{% endif %}
</div>
{% endif %}
Another approach is to capture the content and then output it if not empty:
{% capture header %}
{% if section.settings.title %}
<h2>{{ section.settings.title }}</h2>
{% endif %}
{% if section.settings.subheading %}
<h2>{{ section.settings.subheading }}</h2>
{% endif %}
{% endcapture %}
{% if header != blank %}
<div class="section-header">
{{ header }}
</div>
{% endif %}
None of those approach are optimal.
However, with the addition of dynamic source, it can be extremely complex to do that accurately. For instance, imagine a section with three "testimonial" block, each bound with a metafield.
In the past we could use the number of blocks to know if we should render things or not. However, now that we have metafields, one product may have one testimonial while another one may have three. This therefore becomes extremely complex to generate clean HTML.
Solution
I wish Liquid would have a native way to handle this specific use case. I think the Twig engine has a pretty nice abstraction around that: https://twig.symfony.com/doc/3.x/functions/block.html
Here is how it may look in Liquid (I have replaced the "block" word to "part", as block has specific meaning in context of Shopify). Here is how the previous example could be rewrite:
{% if part('header') != blank %}
<div class="section-header">
{% part 'header' %}
{% if section.settings.title %}
<h2>{{ section.settings.title }}</h2>
{% endif %}
{% if section.settings.subheading %}
<h2>{{ section.settings.subheading }}</h2>
{% endif %}
{% endpart %}
</div>
{% endif %}
With metafield, here is how it would block:
{% if part('products') != blank %}
{% part 'products' %}
{% for block in section.blocks %}
{% assign product = block.settings.product %}
{% if product != empty %}
{% render 'product', product: product %}
{% endif %}
{% endfor %}
{% endpart %}
{% endif %}
The language could have a built-in syntax for loops to make the syntax more concise:
{% for block in section.blocks as "products"%} // Would render into a "products" part
The main benefit would be to move the display logic outside of the parent, and allow to remove a lot of complex conditions to check before a specific element should be rendered or not.
This is something that is becoming increasingly important with metafields.
To show a slightly more complex example, here is a section that would show how this new syntax would help writing a more concise, metafields friendly section, that would render no useless DOM content:
{% if section.blocks.size > 0 %}
{% if part('testimonials') !== blank %}
<div class="section">
{% if part('header') !== blank %}
<div class="section-header">
{% part 'header' %}
{% if section.settings.title != blank %}
<h2>{{ section.settings.title }}</h2>
{% endif %}
{% if section.settings.subtitle != blank %}
<h3>{{ section.settings.subtitle }}</h3>
{% endif %}
{{ section.settings.content }}
{% endpart %}
</div>
{% endif %}
// Either this syntactic sugar, or by wrapping it with a part
{% for block in section.blocks as 'testimonials' %}
{% if block.settings.testimonial %}
<p>{{ block.settings.testimonial }}</p>
{% endif %}
{% endfor %}
</div>
{%- endif -%}
{% else %}
// Show on-boarding section experience
{% endif %}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No files, tests, or entry points are identified. Start by reviewing the proposed part syntax, its interaction with loops and metafields, and the Twig reference linked in the issue. Done would require an agreed design for conditionally rendered content that avoids empty DOM elements.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- web-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100