Snipplet, include y embed

Usando o Twig, podemos incluir snipplets, que são os arquivos “.tpl” dentro da pasta com o mesmo nome, de três maneiras.

Isso nos dá a possibilidade de reutilizar o mesmo componente em mais de um lugar, otimizando o código e facilitando sua manutenção.

Podemos incluir snipplets usando:

  • {%  snipplet %}
  • {%  include %}
  • {%  embed %}

{% snipplet %}

Se precisarmos apenas chamar um snipplet sem nenhum parâmetro extra ou condicional, então este caminho é indicado.

{% if settings.ad_bar and settings.ad_text %}
    {% snipplet "header/header-advertising.tpl" %}
{% endif %}

No exemplo, simplesmente chamamos o snippet header-advertising.tpl dentro da pasta  header, apenas para mostrar uma mensagem acima da navegação.

Como estamos usando {% snipplet%} não é necessário esclarecer que a pasta de cabeçalho está dentro da pasta snipplets.

{% include %}

Include é uma maneira um pouco mais complexa de chamar snipplets, onde podemos usar certas condições dentro do próprio snipplet ao usá-lo, vamos ver um exemplo.

No tema Base temos um snipplet chamado notifications.tpl onde temos o HTML para todas as notificações do Storefront, que até agora são duas:

Adicionar ao carrinho

Seguir os detalhes do pedido:

Dentro do snipplet nós temos algo parecido com isto:

{# Order notification #}

{% if order_notification %}
    content
{% endif %}

{# Add to cart notification #}

{% if add_to_cart %}
    content
{% endif %}

Podemos ver duas condições, uma para mostrar a mensagem "Seguir pedido" com a condição "order_notification"; e outra para a mensagem “Produto adicionado ao carrinho” com a condição “add_to_cart”.

Ambas as condições são personalizadas, ou seja, são nomes que definimos arbitrariamente e não dependem de uma alteração no PHP.

Usamos essas condições ao chamar o arquivo notification.tpl para escolher qual notificação queremos exibir.

Por exemplo, se quisermos mostrar os dois no mesmo lugar (falando em termos de posição no HTML), fazemos o seguinte:

{% include "snipplets/notification.tpl" with {order_notification: true, add_to_cart: true} %}

Se precisarmos mostrar mais de uma notificação, podemos fazer isso chamando o mesmo snipplet em lugares diferentes:

{% include "snipplets/notification.tpl" with {order_notification: true} %}
...
{% include "snipplets/notification.tpl" with {add_to_cart: true} %}

No primeiro exemplo, mostramos apenas a notificação "Seguir seu pedido" e, abaixo, usamos o mesmo snipplet apenas para mostrar a notificação "Produto adicionado ao carrinho".

Usamos o include também para mostrar todos os ícones SVG do tema.

Nossos ícones estão em arquivos ".tpl" que contêm um código SVG como qualquer outro:

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M508.5 468.9L387.1 347.5c-2.3-2.3-5.3-3.5-8.5-3.5h-13.2c31.5-36.5 50.6-84 50.6-136C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c52 0 99.5-19.1 136-50.6v13.2c0 3.2 1.3 6.2 3.5 8.5l121.4 121.4c4.7 4.7 12.3 4.7 17 0l22.6-22.6c4.7-4.7 4.7-12.3 0-17zM208 368c-88.4 0-160-71.6-160-160S119.6 48 208 48s160 71.6 160 160-71.6 160-160 160z"/></svg>

Só que deixamos a classe CSS dentro de um parâmetro com em Twig:

<svg class="{{ svg_custom_class }}"

Fazemos isso para escolher a classe que precisamos quando usamos o include, substituindo o que está entre chaves, então queremos:

{% include "snipplets/svg/search.tpl" with {svg_custom_class: "icon-inline svg-icon-text"} %}

Para fechar, é importante notar que precisamos especificar que o arquivo está na pasta “snipplets”, diferente de quando usamos {% snipplet%} onde não é necessário.

{% embed %}

O embeded é muito semelhante ao include, porém um pouco mais complexo. Vamos ver isso com um exemplo:

No tema Base, usamos o embeded para o componente “select” (entre muitos outros).

O snipplet é form-select.tpl e seu código é o seguinte:

<div class="form-group {{ select_group_custom_class }}">
    {% if select_label %}
        <label {% if select_label_id%}id="{{ select_label_id }}"{% endif %} class="form-label {{ select_label_custom_class }}" {% if select_for %}for="{{ select_for }}"{% endif %}>{{ select_label_name }}</label>
    {% endif %}
    <select 
        {% if select_id %}id="{{ select_id }}"{% endif %}
        class="form-select {{ select_custom_class }} {% if select_inline %}form-control-inline{% endif %}"
        {% if select_name %}name="{{ select_name }}"{% endif %}>
        {% block select_options %}
        {% endblock select_options %}
    </select>
    <div class="form-select-icon">
        {% include "snipplets/svg/chevron-down.tpl" with {svg_custom_class: "icon-inline icon-w-14 icon-lg svg-icon-text"} %}
    </div>
</div>

Neste arquivo, usamos classes às quais passamos parâmetros quando eles são incluídos (como no exemplo de SVGs com um include).

<div class="form-group {{ select_group_custom_class }}">

Também usamos condições personalizadas como na inclusão.

{% if select_label %}
    <label {% if select_label_id%}id="{{ select_label_id }}"{% endif %} class="form-label {{ select_label_custom_class }}" {% if select_for %}for="{{ select_for }}"{% endif %}>{{ select_label_name }}</label>
{% endif %}

Mas a diferença com o include está no uso de um "block"

<select 
    {% if select_id %}id="{{ select_id }}"{% endif %}
    class="form-select {{ select_custom_class }} {% if select_inline %}form-control-inline{% endif %}"
    {% if select_name %}name="{{ select_name }}"{% endif %}>
    {% block select_options %}
    
    {% endblock select_options %}
</select>

O block nos permite deixar um espaço vazio ao qual podemos adicionar o conteúdo que precisamos ao usar o snipplet.

No caso do select, nós o usamos para adicionar as opções de que precisamos, pois podem ser duas ou mais.

Um exemplo de como chamar form-select.tpl usando embed é a seguinte:

{% embed "snipplets/forms/form-select.tpl" with{select_label: false, select_custom_class: 'js-sort-by'} %}
    {% block select_options %}
        <option value="1">{{ 'texto 1' | translate }}</option>
        <option value="2">{{ 'texto 2' | translate }}</option>
        <option value="3">{{ 'texto 3' | translate }}</option>
        <option value="4">{{ 'texto 4' | translate }}</option>
    {% endblock select_options%}
{% endembed %}

Neste caso, mostramos um select sem um label (já que tem a condição select_label: false) com uma classe customizada “js-sort-by” e dentro do block tem quatro opções estáticas.

Outro exemplo é o componente para as variantes de um produto:

{% for variation in product.variations %}
    <div class="col-12">
        {% embed "snipplets/forms/form-select.tpl" with{select_label: true, select_label_name: '' ~ variation.name ~ '', select_for: 'variation_' ~ loop.index , select_id: 'variation_' ~ loop.index, select_name: 'variation' ~ '[' ~ variation.id ~ ']', select_custom_class: 'js-variation-option js-refresh-installment-data'} %}
            {% block select_options %}
                {% for option in variation.options %}
                    <option value="{{ option.id }}" {% if product.default_options[variation.id] == option.id %}selected="selected"{% endif %}>{{ option.name }}</option>
                {% endfor %}
            {% endblock select_options%}
        {% endembed %}
    </div>
{% endfor %}

Aqui há muito mais propriedades, mas a maior diferença está dentro do block em que não temos mais conteúdo estático, mas usamos um for para iterar sobre as propriedades de cada variante.

Para fechar, devemos esclarecer que o snipplet está dentro da pasta snipplets, da mesma forma que fazemos em um include.

Tip:

Se precisarmos usar texto estático em um embeded (e em um include também), podemos fazer da seguinte maneira

select_label_name: 'text' | translate,

Se quisermos um texto dinâmico, fazemos desta maneira:

select_label_name: '' ~ variation.name ~ '',