Mensagens de frete grátis a partir de um valor mínimo

Neste tutorial, vamos melhorar a visibilidade do frete grátis quando ele é a partir de um valor mínimo, da seguinte forma:

  • Exibindo uma etiqueta de "Frete Grátis" quando o preço do produto (ou variante) excede o valor mínimo para frete grátis
  • Através de uma mensagem no detalhe do produto que exibe qual é o mínimo para ter frete grátis.
  • Mostrando uma mensagem que incentiva a adição do produto ao carrinho para obter frete grátis.
  • Com uma barra de progresso no carrinho que mostra o valor restante para chegar ao frete grátis.


Essas mensagens serão exibidas sempre que o frete grátis não tenha restrições de região ou categoria.

HTML

1. O primeiro que vamos fazer é adicionar o seguinte código ao arquivo layout.tpl que será usado para que o JS privado da Nuvemshop faça os cálculos que permitem a alteração das mensagens ao ultrapassar o valor mínimo para frete grátis.

{% if cart.free_shipping.cart_has_free_shipping or cart.free_shipping.min_price_free_shipping.min_price %}

    {# Minimum used for free shipping progress messages. Located on header so it can be accesed everywhere with shipping calculator active or inactive #}

    <span class="js-ship-free-min hidden" data-pricemin="{{ cart.free_shipping.min_price_free_shipping.min_price_raw }}"></span>
    <span class="js-cart-subtotal hidden" data-priceraw="{{ cart.subtotal }}"></span>
    <span class="js-cart-discount hidden" data-priceraw="{{ cart.promotional_discount_amount }}"></span>
{% endif %}

2. Vamos criar o seguinte arquivo shipping-free-rest.tpl dentro da pasta snipplets/shipping que servirá tanto para a barra de progresso do carrinho de compras quanto para a mensagem que incentiva a adição de um produto ao carrinho para ter frete grátis.

{% if product_detail %}
    
    {% if not product.free_shipping %}
        {# Wording to notice that adding one more product free shipping is achieved #}

        <div class="js-shipping-add-product-label full-width-container mb-4 text-center text-md-left h6" style="display: none;">
            <span class='js-fs-add-this-product'>{{ "¡Agregá este producto y " | translate }}</span>
            <span class='js-fs-add-one-more' style='display: none;'>{{ "¡Agregá uno más y " | translate }}</span>
            <strong class='text-accent'>{{ "tenés envío gratis!" | translate }}</strong>
        </div>
    {% endif %}
{% else %}
    <div class="js-fulfillment-info js-allows-non-shippable" {% if not cart.has_shippable_products %}style="display: none"{% endif %}>

        {# Free shipping progress bar #}
        <div class="js-ship-free-rest">
            <div class="js-bar-progress bar-progress">
                <div class="js-bar-progress-active bar-progress-active transition-soft"></div>
            </div>
            <div class="js-ship-free-rest-message ship-free-rest-message">
                <div class="ship-free-rest-text bar-progress-success h5 text-accent transition-soft">
                    {{ "¡Genial! Tenés envío gratis" | translate }}
                </div>
                <div class="ship-free-rest-text bar-progress-amount h6 transition-soft">
                    {{ "¡Estás a <strong class='js-ship-free-dif h5'></strong> de tener <strong class='text-accent'>envío gratis</strong>!" | translate }}
                </div>
                <div class="ship-free-rest-text bar-progress-condition transition-soft">
                    <strong class="text-accent">{{ "Envío gratis" | translate }}</strong> {{ "superando los" | translate }} <span>{{ cart.free_shipping.min_price_free_shipping.min_price }}</span>
                </div>
            </div>
        </div>
    </div>
{% endif %}

3Agora vamos alterar o arquivo labels.tpl que contém as etiquetas promocionais para poder exibir a mensagem “Frete Grátis” não só quando o produto o possui intrinsecamente, mas também quando o preço do produto (ou variante) for maior que o valor mínimo. A mudança que precisamos adicionar é a seguinte:

{% set has_product_available = product.available and product.display_price %}
{% set store_has_free_shipping = not product.is_non_shippable and (product.free_shipping or (has_product_available and (cart.free_shipping.cart_has_free_shipping or cart.free_shipping.min_price_free_shipping.min_price))) %}
{% set product_price_above_free_shipping_minimum = cart.free_shipping.min_price_free_shipping and (product.price >= cart.free_shipping.min_price_free_shipping.min_price_raw) %}

Estas condiciones permiten mostrar el cartel dentro del grupo de carteles con el siguiente código (revisar la parte {% if store_has_free_shipping %})

Estas condições permitem que a etiqueta seja exibida dentro do grupo de etiquetas com o seguinte código (verifique a parte {% if store_has_free_shipping %})

<div class="{% if product.video_url and product %}js-labels-group{% endif %} labels" data-store="product-item-labels">
  {% if show_labels %}
    <div class="js-stock-label label label-default" {% if product.has_stock %}style="display:none;"{% endif %}>{{ "Sin stock" | translate }}</div>
    {% if product.compare_at_price or product.promotional_offer %}
      <div class="{% if not product.promotional_offer and product %}js-offer-label{% endif %} label label-accent" {% if (not product.compare_at_price and not product.promotional_offer) or not product.display_price %}style="display:none;"{% endif %} data-store="product-item-{% if product.compare_at_price %}offer{% else %}promotion{% endif %}-label">
        {% if product.promotional_offer.script.is_percentage_off %}
          {{ product.promotional_offer.parameters.percent * 100 }}% OFF
        {% elseif product.promotional_offer.script.is_discount_for_quantity %}
          <div>{{ product.promotional_offer.selected_threshold.discount_decimal_percentage * 100 }}% OFF</div>
          <div class="label-small p-right-quarter p-left-quarter">{{ "Comprando {1} o más" | translate(product.promotional_offer.selected_threshold.quantity) }}</div>
        {% elseif product.promotional_offer %}
          {% if store.country == 'BR' %}
            {{ "Leve {1} Pague {2}" | translate(product.promotional_offer.script.quantity_to_take, product.promotional_offer.script.quantity_to_pay) }}
          {% else %}
            {{ product.promotional_offer.script.type }} 
          {% endif %}
        {% else %}
          <span class="js-offer-percentage">{{ price_discount_percentage |round }}</span>% OFF
        {% endif %}
      </div>
    {% endif %}
    {% if store_has_free_shipping %}
      <div class="{% if not product.free_shipping %}js-free-shipping-minimum-label {% endif %}label label-accent" {% if not (product.free_shipping or product_price_above_free_shipping_minimum) %}style="display: none;"{% endif %}>{{ "Envío gratis" | translate }}</div>
    {% endif %}
  {% endif %}
</div>
<span class="hidden" data-store="stock-product-{{ product.id }}-{% if product.has_stock %}{% if product.stock %}{{ product.stock }}{% else %}infinite{% endif %}{% else %}0{% endif %}"></span>

Por fim, no arquivo item.tpl, que representa os produtos da lista, vamos procurar o elemento que contém o preço do produto com a classe "js-price-display" e adicionar a ele o seguinte atributo:

data-product-price="{{ product.price }}"

4. Agora vamos alterar o formulário do produto para poder exibir as mensagens.

Primeiro incluímos o arquivo shipping-free-rest.tpl dentro do arquivo product-form.tpl sob o botão de compra para a mensagem que incentiva a adição de um produto para obter frete grátis, que também muda para outra mensagem quando o frete grátis já foi alcançado.

{# Free shipping visibility message #}

{% set free_shipping_minimum_label_changes_visibility = has_free_shipping and cart.free_shipping.min_price_free_shipping.min_price_raw > 0 %}

{% set include_product_free_shipping_min_wording = cart.free_shipping.min_price_free_shipping.min_price_raw > 0 %}

{% if not product.is_non_shippable and show_product_quantity and has_free_shipping and not has_product_free_shipping %}

    {# Free shipping add to cart message #}

    {% if include_product_free_shipping_min_wording %}


        {% include "snipplets/shipping/shipping-free-rest.tpl" with {'product_detail': true} %}

    {% endif %}

    {# Free shipping achieved message #}

    <div class="{% if free_shipping_minimum_label_changes_visibility %}js-free-shipping-message{% endif %} text-accent font-weight-bold mb-4 text-center text-md-left h6" {% if not cart.free_shipping.cart_has_free_shipping %}style="display: none;"{% endif %}>
        {{ "¡Genial! Tenés envío gratis" | translate }}
    </div>
{% endif %}

Assim como já fizemos no item produto, vamos fazer o mesmo procurando o elemento que contém o preço do produto com a classe “js-price-display” e adicionando a ele o seguinte atributo:

data-product-price="{{ product.price }}"

Continuamos adicionando o seguinte código acima onde começa o formulário do produto. Esta mensagem indicará a condição de frete grátis acima de um determinado mínimo.

{# Product availability #}

{% set show_product_quantity = product.available and product.display_price %}

{# Free shipping minimum message #}

{% set has_free_shipping = cart.free_shipping.cart_has_free_shipping or cart.free_shipping.min_price_free_shipping.min_price %}
{% set has_product_free_shipping = product.free_shipping %}

{% if not product.is_non_shippable and show_product_quantity and (has_free_shipping or has_product_free_shipping) %}
    <div class="free-shipping-message mb-4 pb-2">
        <span class="d-inline-block">
            {% include "snipplets/svg/truck.tpl" with {svg_custom_class: "icon-inline icon-w-18 icon-lg svg-icon-accent mr-2"} %}
        </span>
        <span class="d-inline-block">
            <strong class="text-accent">{{ "Envío gratis" | translate }} </strong>
            <span {% if has_product_free_shipping %}style="display: none;"{% else %}class="js-shipping-minimum-label"{% endif %}>
                {{ "superando los" | translate }} <span>{{ cart.free_shipping.min_price_free_shipping.min_price }}</span>
            </span>
        </span>
    </div>
{% endif %}

 5. Em seguida, adicionamos o arquivo shipping-free-rest.tpl ao carrinho, neste caso em seu formato pop-up dentro do arquivo cart-panel.tpl abaixo da lista de produtos. Se o seu layout tiver um carrinho em formato de página, você precisará adicioná-lo no arquivo cart.tpl

{# Check if store has free shipping without regions or categories #}

{% set has_free_shipping = cart.free_shipping.cart_has_free_shipping or cart.free_shipping.min_price_free_shipping.min_price %}

{% if has_free_shipping and cart.free_shipping.min_price_free_shipping.min_price_raw > 0 %}
  
  {# includes free shipping progress bar: only if store has free shipping with a minimum #}
  
  {% include "snipplets/shipping/shipping-free-rest.tpl" %}
{% endif %}

6. En caso de tener el label del calculador de envíos "dinámico", es decir que si este cambiaba de texto en base a si el envío gratis es alcanzado o no. Necesitamos limpiar esta parte de código dejando simplemente un texto fijo, ya que ahora todos los mensajes de envío gratis se encontrarán por fuera del calculador. Para esto necesitamos remover todas las condiciones de visibilidad de twig y las clases de tipo "js-" dentro del archivo shipping-calculator.tpl en la carpeta shipping. Dejando algo como esto:

Se você possui o label da calculadora de frete "dinâmica", ou seja, se ela altera seu texto dependendo se o frete grátis foi alcançado ou não. Precisamos limpar essa parte do código simplesmente deixando um texto fixo, pois agora todas as mensagens de frete grátis ficarão fora da calculadora. Para isso, precisamos remover todas as condições de visibilidade do twig e classes do tipo "js-" dentro do arquivo shipping-calculator.tpl na pasta de shipping. Deixando algo assim:

<span>{{ 'Medios de envío' | translate }}</span>

7. Por último para la parte de HTML, necesitamos agregar una carpeta SVG dentro de la carpeta snipplets. Acá vamos sumar los SVGs para el icono de envíos con el nombre truck.tpl

Finalmente, para a parte HTML, precisamos adicionar uma pasta SVG dentro da pasta snipplets. Aqui vamos adicionar o SVGs para o ícone de frete com o nome truck.tpl

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M624 368h-16V251.9c0-19-7.7-37.5-21.1-50.9L503 117.1C489.6 103.7 471 96 452.1 96H416V56c0-30.9-25.1-56-56-56H56C25.1 0 0 25.1 0 56v304c0 30.9 25.1 56 56 56h8c0 53 43 96 96 96s96-43 96-96h128c0 53 43 96 96 96s96-43 96-96h48c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16zm-464 96c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm208-96H242.7c-16.6-28.6-47.2-48-82.7-48s-66.1 19.4-82.7 48H56c-4.4 0-8-3.6-8-8V56c0-4.4 3.6-8 8-8h304c4.4 0 8 3.6 8 8v312zm48-224h36.1c6.3 0 12.5 2.6 17 7l73 73H416v-80zm64 320c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-100.9c-17.2-25.9-46.6-43.1-80-43.1-24.7 0-47 9.6-64 24.9V272h144v91.1z"/></svg>

CSS

Requisito:

Ter adicionado helper classes em seu layout. Você pode seguir este pequeno tutorial para fazer isso (é só copiar e colar algumas classes, não leva mais que 1 minuto).

1. Adicionamos o seguinte SASS de cores em style-colors.scss.tpl (ou na stylesheet do seu layout que possui as cores e fontes da loja). Lembre-se de que as variáveis de cores e fontes podem variar em relação ao seu layout:

.bar-progress {
  background: rgba($accent-color, 0.1);
  &-active {
    background: $accent-color;
  }
}

2. Adicione os estilos no arquivo static/style-async.tpl

Se em seu layout você usar um stylesheet CSS assíncrono, precisaremos do seguinte código dentro dela, do contrário, você pode unificar todo no mesmo CSS.

/* // Progress bar */

.bar-progress {
  position: relative;
  height: 7px;
  .bar-progress-active {
    width: 0%;
    height: 7px;
  }
}

.ship-free-rest-message {
  position: relative;
  height: 45px;
  .ship-free-rest-text {
    position: absolute;
    top: -5px;
    width: 100%;
    text-align: center;  
    line-height: 36px;
    opacity: 0;
  }
  &.success .bar-progress-success,
  &.amount .bar-progress-amount,
  &.condition .bar-progress-condition {
    top: 0;
    opacity: 1;
  }
}

JS

⚠️ A partir del día 30 de enero de 2023, la librería jQuery será removida del código de nuestras tiendas, por lo tanto la función "$" no podrá ser utilizada.

1. O JavaScript precisa ser adicionado no arquivo store.js.tpl (ou onde você tem suas funções JS).

Primeiro procuramos a função changeVariant e dentro dela ao final adicionamos o seguinte código que nos permite atualizar as mensagens de frete grátis quando as variantes mudam nos detalhes do produto

{% if cart.free_shipping.min_price_free_shipping.min_price %}
    {# Updates free shipping bar #}

    LS.freeShippingProgress(true, parent);

{% endif %}

Então procuramos a próxima linha

parent.find('.js-price-display').attr("content", variant.price_number).data('productPrice', variant_price_raw);

E nós substituímos pela seguinte

parent.find('.js-price-display').attr("content", variant.price_number).data('productPrice', variant.price_number_raw);

E por fim adicionamos este código onde temos o JS relacionado ao carrinho para atualizar a barra de progresso ao carregar a página

{# /* // Free shipping bar */ #}

{% if cart.free_shipping.min_price_free_shipping.min_price %}

    {# Updates free progress on page load #}

    LS.freeShippingProgress(true);

{% endif %}

Traduções

Nesta etapa, adicionamos os textos para as traduções no arquivo config/translations.txt

es "Medios de envío"
pt "Meios de envio"
en "Shipping Methods"
es_mx "Opciones de envío"

es "Envío gratis"
pt "Frete grátis"
en "Free shipping"
es_mx "Envío gratis"

es "superando los"
pt "a partir de"
en "buying more than"
es_mx "superando los"

es "¡Genial! Tenés envío gratis"
pt "Sucesso! Você tem frete grátis"
en "You have free shipping"
es_mx "¡Genial! Tienes envío gratis"

es "tenés envío gratis!"
pt "tenha frete grátis!"
en "you have free shipping!"
es_mx "tienes envío gratis!"

es "¡Agregá este producto y "
pt "Adicione este produto e "
en "Add this product and "
es_mx "¡Agrega este producto y "

es "¡Agregá uno más y "
pt "Adicione mais um e "
en "Add one more and "
es_mx "¡Agrega uno más y "

es "¡Estás a <strong class='js-ship-free-dif h5'></strong> de tener <strong class='text-accent'>envío gratis</strong>!"
pt "<strong class='text-accent'>Ganhe frete grátis</strong> com mais <strong class='js-ship-free-dif h5'></strong>"
en "You need <strong class='js-ship-free-dif h5'></strong> to have <strong class='text-accent'>free shipping</strong>"
es_mx "¡Estás a <strong class='js-ship-free-dif h5'></strong> de tener <strong class='text-accent'>envío gratis</strong>!"

Pronto! Já tem a funcionalidade aplicada. Parabéns!

Ativação

Para poder activar el envío gratis a partir de un mínimo en tu administrador tenes que ir a la sección de Marketing > Envío gratis y crear una "Opción de envío gratis".

Para ativar o frete grátis com mínimo em seu administrador você deve ir até a seção Marketing > Frete grátis e criar uma "opção de frete grátis".