Neste tutorial, vamos ver como visualizar as cores de um produto na listagem, sem precisar inserir nos detalhes do produto.

HTML
1. A primeira coisa que vamos fazer é adicionar um novo snipplet chamado item-colors.tpl dentro da pasta snipplets/grid com o seguinte código:
{% if product.variations %}
{% set own_color_variants = 0 %}
{% set custom_color_variants = 0 %}
{% for variation in product.variations %}
<div class="js-color-variant-available-{{ loop.index }} {% if variation.name in ['Color', 'Cor'] %}js-color-variant-active{% endif %}" data-value="variation_{{ loop.index }}" data-option="{{ loop.index0 }}" >
{% if variation.name in ['Color', 'Cor'] %}
{% if variation.options | length > 1 %}
<div class="item-colors">
<a href="{{ product_url_with_selected_variant }}" class="item-colors-bullet item-colors-bullet-text d-md-none w-auto px-2">{{ variation.options | length }} {{ 'colores' | translate }}</a>
<div class="d-none d-md-block">
{% for option in variation.options | take(5) if option.custom_data %}
<span title="{{ option.name }}" data-option="{{ option.id }}" class="js-color-variant item-colors-bullet {% if product.default_options[variation.id] == option.id %}selected{% endif %}" style="background: {{ option.custom_data }}"></span>
{% endfor %}
{% for option in variation.options %}
{% if option.custom_data %}
{# Quantity of our colors #}
{% set own_color_variants = own_color_variants + 1 %}
{% else %}
{# Quantity of custom colors #}
{% set custom_color_variants = custom_color_variants + 1 %}
{% endif %}
{% endfor %}
{% set more_color_variants = (own_color_variants - 5) + custom_color_variants %}
{% if own_color_variants and custom_color_variants %}
<a href="{{ product_url_with_selected_variant }}" class="item-colors-bullet w-auto" title="{{ 'Ver más colores' | translate }}">
{% if own_color_variants > 5 %}
+{{ more_color_variants }}
{% else %}
+{{ custom_color_variants }}
{% endif %}
</a>
{% elseif own_color_variants > 5 %}
<a href="{{ product_url_with_selected_variant }}" class="item-colors-bullet w-auto" title="{{ 'Ver más colores' | translate }}">+{{ own_color_variants - 5 }}</a>
{% elseif custom_color_variants %}
<a href="{{ product_url_with_selected_variant }}" class="item-colors-bullet item-colors-bullet-text w-auto px-2" title="{{ 'Ver más colores' | translate }}">{{ custom_color_variants }} {{ 'colores' | translate }}</a>
{% endif %}
</div>
</div>
{% endif %}
{% endif %}
</div>
{% endfor %}
{% endif %}2. Depois vamos procurar o snipplet item.tpl dentro da pasta snipplets/grid, pode ser que em seu layout esse snipplet seja chamado single_product.tpl, e usamos o seguinte código:
{% set slide_item = slide_item | default(false) %}
{% set columns = settings.grid_columns %}
{% set has_color_variant = false %}
{% if settings.product_color_variants %}
{% for variation in product.variations if variation.name in ['Color', 'Cor'] and variation.options | length > 1 %}
{% set has_color_variant = true %}
{% endfor %}
{% endif %}
<div class="js-item-product {% if slide_item %}swiper-slide{% else %}col{% if columns == 2 %}-6 col-md-3{% else %}-12 col-md-4{% endif %}{% endif %} item item-product{% if not product.display_price %} no-price{% endif %}" data-product-type="list" data-product-id="{{ product.id }}" data-store="product-item-{{ product.id }}">
{% if settings.product_color_variants %}
<div id="quick{{ product.id }}{% if slide_item and section_name %}-{{ section_name }}{% endif %}" class="js-product-container js-quickshop-container {% if product.variations %}js-quickshop-has-variants{% endif %}" data-variants="{{ product.variants_object | json_encode }}">
{% endif %}
{% set product_url_with_selected_variant = has_filters ? ( product.url | add_param('variant', product.selected_or_first_available_variant.id)) : product.url %}
{% if has_color_variant %}
{# Item image will be the first avaiable variant #}
{% set item_img_spacing = product.featured_variant_image.dimensions['height'] / product.featured_variant_image.dimensions['width'] * 100 %}
{% set item_img_srcset = product.featured_variant_image %}
{% set item_img_alt = product.featured_variant_image.alt %}
{% else %}
{# Item image will be the first image regardless the variant #}
{% set item_img_spacing = product.featured_image.dimensions['height'] / product.featured_image.dimensions['width'] * 100 %}
{% set item_img_srcset = product.featured_image %}
{% set item_img_alt = product.featured_image.alt %}
{% endif %}
<div class="item-image mb-2">
<div style="padding-bottom: {{ item_img_spacing }}%;" class="p-relative" data-store="product-item-image-{{ product.id }}">
<a href="{{ product_url_with_selected_variant }}" title="{{ product.name }}">
<img alt="{{ item_img_alt }}" data-sizes="auto" data-expand="-10" src="{{ 'images/empty-placeholder.png' | static_url }}" data-srcset="{{ item_img_srcset | product_image_url('small')}} 240w, {{ item_img_srcset | product_image_url('medium')}} 320w, {{ item_img_srcset | product_image_url('large')}} 480w" class="js-item-image lazyautosizes lazyload img-absolute img-absolute-centered fade-in" />
<div class="placeholder-fade"></div>
</a>
{% if settings.product_color_variants %}
{% include 'snipplets/labels.tpl' with {color: true} %}
{% include 'snipplets/grid/item-colors.tpl' %}
{% else %}
{% include 'snipplets/labels.tpl' %}
{% endif %}
</div>
</div>
{% if settings.product_color_variants and product.variations %}
{% for variation in product.variations if variation.name in ['Color', 'Cor'] and variation.options | length > 1 %}
{# Hidden product form to update item image and variants #}
<div class="js-item-variants hidden">
<form id="product_form" class="js-product-form" method="post" action="{{ store.cart_url }}">
{% if product.variations %}
{% include "snipplets/product/product-variants.tpl" with {quickshop: true} %}
{% endif %}
{% set state = store.is_catalog ? 'catalog' : (product.available ? product.display_price ? 'cart' : 'contact' : 'nostock') %}
{% set texts = {'cart': "Agregar al carrito", 'contact': "Consultar precio", 'nostock': "Sin stock", 'catalog': "Consultar"} %}
{# Add to cart CTA #}
<input type="submit" class="js-addtocart js-prod-submit-form {{ state }}" value="{{ texts[state] | translate }}" {% if state == 'nostock' %}disabled{% endif %} />
</form>
</div>
{% endfor %}
{% endif %}
<div class="item-description" data-store="product-item-info-{{ product.id }}">
<a href="{{ product_url_with_selected_variant }}" title="{{ product.name }}" class="item-link">
<div class="item-name mb-1" data-store="product-item-name-{{ product.id }}">{{ product.name }}</div>
{% if product.display_price %}
<div class="item-price-container mb-1" data-store="product-item-price-{{ product.id }}">
<span class="js-compare-price-display price-compare" {% if not product.compare_at_price or not product.display_price %}style="display:none;"{% else %}style="display:inline-block;"{% endif %}>
{{ product.compare_at_price | money }}
</span>
<span class="js-price-display item-price">
{{ product.price | money }}
</span>
</div>
{% endif %}
</a>
</div>
{% include 'snipplets/payments/installments.tpl' %}
{# Structured data to provide information for Google about the product content #}
{% include 'snipplets/structured_data/item-structured-data.tpl' %}
{% if settings.product_color_variants %}
</div>
{% endif %}
</div>3. No snipplet labels.tpl, pode ser que em seu layout esteja diretamente dentro do snipplet single_product.tpl, utilizamos o seguinte código:
{% if product.compare_at_price > product.price %}
{% set price_discount_percentage = ((product.compare_at_price) - (product.price)) * 100 / (product.compare_at_price) %}
{% endif %}
{% if color %}
{% set show_labels = settings.product_color_variants %}
{% else %}
{% set show_labels = not product.has_stock or product.free_shipping or product.compare_at_price or product.promotional_offer %}
{% endif %}
{% if show_labels %}
<div class="labels">
{% if not product.has_stock %}
<div class="{% if product_detail %}js-stock-label {% endif %}label label-default">{{ "Sin stock" | translate }}</div>
{% else %}
{% if product_detail or color %}
<div class="js-stock-label label label-default" {% if product.has_stock %}style="display:none;"{% endif %}>{{ "Sin stock" | translate }}</div>
{% endif %}
{% if product.compare_at_price or product.promotional_offer %}
<div class="{% if not product.promotional_offer and product %}js-offer-label{% endif %} label label-primary" {% if (not product.compare_at_price and not product.promotional_offer) or not product.display_price %}style="display:none;"{% endif %}>
{% 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 %}
{{ "Promo" | translate }} {{ product.promotional_offer.script.type }}
{% endif %}
{% else %}
<span {% if product_detail or color %}class="js-offer-percentage"{% endif %}>{{ price_discount_percentage |round }}</span>% OFF
{% endif %}
</div>
{% endif %}
{% if product.free_shipping %}
<div class="label label-secondary">{{ "Envío gratis" | translate }}</div>
{% endif %}
{% endif %}
</div>
{% endif %}4. No snipplet installmets.tpl dentro da pasta snipplets/payments, para atualizar as informações de parcelas ao alterar uma cor, substituímos esta linha de código:
<div class="{% if product_detail %}js-max-installments-container js-max-installments text-center text-md-left{% else %}item-installments{% endif %}">Pela seguinte:
<div class="js-max-installments-container js-max-installments {% if product_detail %}text-center text-md-left{% else %}item-installments{% endif %}">5. Por úlitmo, no snipplet product-variants.tpl dentro da pasta snipplets/product, usamos:
<div class="js-product-variants{% if quickshop %} js-product-quickshop-variants text-left{% endif %} form-row">
{% for variation in product.variations %}
<div class="js-product-variants-group {% if variation.name in ['Color', 'Cor'] %}js-color-variants-container{% endif %} {% if loop.length == 3 %} {% if quickshop %}col-4{% else %}col-12{% endif %} col-md-4 {% elseif loop.length == 2 %} col-6 {% else %} col {% if quickshop %}col-md-12{% else %}col-md-6{% endif %}{% endif %}" data-variation-id="{{ variation.id }}">
{% 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_data_value: '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 %}
</div>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.Adicione os estilos no arquivo static/style-critical.tpl
Se em seu layout você usar um stylesheet para o CSS crítico, precisaremos do seguinte código dentro dele.
.item-colors {
position: absolute;
bottom: 0;
z-index: 9;
width: 100%;
padding: 5px 0;
}
.item-colors-bullet {
display: inline-block;
min-width: 18px;
height: 18px;
margin: 0 3px;
font-size: 10px;
text-transform: uppercase;
line-height: 19px;
vertical-align: top;
border-radius: 18px;
cursor: pointer;
opacity: 0.8;
-webkit-transition: all 0.4s ease;
-ms-transition: all 0.4s ease;
-moz-transition: all 0.4s ease;
-o-transition: all 0.4s ease;
transition: all 0.4s ease;
}
.item-colors-bullet:hover,
.item-colors-bullet.selected {
opacity: 1;
}2. Adicionamos o seguinte SASS de cores em style-colors.scss.tpl (ou 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:
.item-colors {
background: rgba($main-foreground, .6);
&-bullet {
color: $main-foreground;
}
&-bullet-text {
color: $main-background;
}
}JS
⚠️ A partir do dia 30 de janeiro de 2023, a biblioteca jQuery será removida do código de nossas lojas, portanto, a função "$" não poderá ser utilizada.
1. O JavaScript deve ser adicionado no arquivo store.js.tpl (ou onde você tem suas funções JS). O código de que precisamos é o seguinte:
{% if settings.product_color_variants %}
{# Product color variations #}
jQueryNuvem(document).on("click", ".js-color-variant", function(e) {
e.preventDefault();
$this = jQueryNuvem(this);
var option_id = $this.data('option');
$selected_option = $this.closest('.js-item-product').find('.js-variation-option option').filter(function(el) {
return el.value == option_id;
});
$selected_option.prop('selected', true).trigger('change');
var available_variant = jQueryNuvem(this).closest(".js-quickshop-container").data('variants');
var available_variant_color = jQueryNuvem(this).closest('.js-color-variant-active').data('option');
for (var variant in available_variant) {
if (option_id == available_variant[variant]['option'+ available_variant_color ]) {
if (available_variant[variant]['stock'] == null || available_variant[variant]['stock'] > 0 ) {
var otherOptions = getOtherOptionNumbers(available_variant_color);
var otherOption = available_variant[variant]['option' + otherOptions[0]];
var anotherOption = available_variant[variant]['option' + otherOptions[1]];
changeSelect(jQueryNuvem(this), otherOption, otherOptions[0]);
changeSelect(jQueryNuvem(this), anotherOption, otherOptions[1]);
break;
}
}
}
$this.siblings().removeClass("selected");
$this.addClass("selected");
});
function getOtherOptionNumbers(selectedOption) {
switch (selectedOption) {
case 0:
return [1, 2];
case 1:
return [0, 2];
case 2:
return [0, 1];
}
}
function changeSelect(element, optionToSelect, optionIndex) {
if (optionToSelect != null) {
var selected_option_attribute = element.closest('.js-item-product').find('.js-color-variant-available-' + (optionIndex + 1)).data('value');
var selected_option = element.closest('.js-item-product').find('#' + selected_option_attribute + " option").filter(function(el) {
return el.value == optionToSelect;
});
selected_option.prop('selected', true).trigger('change');
}
}
LS.registerOnChangeVariant(function(variant){
{# Show product image on color change #}
var current_image = jQueryNuvem('.js-item-product[data-product-id="'+variant.product_id+'"] .js-item-image');
current_image.attr('srcset', variant.image_url);
});
{% endif %}2. Também precisamos adicionar o JS que atualiza os preços, estoque e rótulos correspondentes, como estoque e descontos, ao alterar as variantes.
Para isso, devemos procurar a seguinte função:
$(document).on("change", ".js-variation-option", function(e) {
LS.changeVariant(changeVariant, '#single-product');
(...)
});E substituí-la pela seguinte:
jQueryNuvem(document).on("change", ".js-variation-option", function(e) {
var $parent = jQueryNuvem(this).closest(".js-product-variants");
var $variants_group = jQueryNuvem(this).closest(".js-product-variants-group");
var $quickshop_parent_wrapper = jQueryNuvem(this).closest(".js-quickshop-container");
{# If quickshop is used from modal, use quickshop-id from the item that opened it #}
if($quickshop_parent_wrapper.hasClass("js-quickshop-modal")){
var quick_id = jQueryNuvem(".js-quickshop-opened .js-quickshop-container").data("quickshopId");
}else{
var quick_id = $quickshop_parent_wrapper.data("quickshopId");
}
if($parent.hasClass("js-product-quickshop-variants")){
var $quickshop_parent = jQueryNuvem(this).closest(".js-item-product");
{# Target visible slider item if necessary #}
if($quickshop_parent.hasClass("js-item-slide")){
var $quickshop_variant_selector = '.js-swiper-slide-visible .js-quickshop-container[data-quickshop-id="'+quick_id+'"]';
}else{
var $quickshop_variant_selector = '.js-quickshop-container[data-quickshop-id="'+quick_id+'"]';
}
LS.changeVariant(changeVariant, $quickshop_variant_selector);
{% if settings.product_color_variants %}
{# Match selected color variant with selected quickshop variant #}
if(($variants_group).hasClass("js-color-variants-container")){
var selected_option_id = jQueryNuvem(this).find("option").filter((el) => el.selected).val();
if($quickshop_parent.hasClass("js-item-slide")){
var $color_parent_to_update = jQueryNuvem('.js-swiper-slide-visible .js-quickshop-container[data-quickshop-id="'+quick_id+'"]');
}else{
var $color_parent_to_update = jQueryNuvem('.js-quickshop-container[data-quickshop-id="'+quick_id+'"]');
}
$color_parent_to_update.find('.js-color-variant, .js-insta-variant').removeClass("selected");
$color_parent_to_update.find('.js-color-variant[data-option="'+selected_option_id+'"], .js-insta-variant[data-option="'+selected_option_id+'"]').addClass("selected");
}
{% endif %}
} else {
LS.changeVariant(changeVariant, '#single-product');
}
{# Offer and discount labels update #}
var $this_product_container = jQueryNuvem(this).closest(".js-product-container");
if($this_product_container.hasClass("js-quickshop-container")){
var this_quickshop_id = $this_product_container.attr("data-quickshop-id");
var $this_product_container = jQueryNuvem('.js-product-container[data-quickshop-id="'+this_quickshop_id+'"]');
}
var $this_compare_price = $this_product_container.find(".js-compare-price-display");
var $this_price = $this_product_container.find(".js-price-display");
var $installment_container = $this_product_container.find(".js-product-payments-container");
var $installment_text = $this_product_container.find(".js-max-installments-container");
var $this_add_to_cart = $this_product_container.find(".js-prod-submit-form");
// Get the current product discount percentage value
var current_percentage_value = $this_product_container.find(".js-offer-percentage");
// Get the current product price and promotional price
var compare_price_value = $this_compare_price.html();
var price_value = $this_price.html();
// Calculate new discount percentage based on difference between filtered old and new prices
const percentageDifference = window.moneyDifferenceCalculator.percentageDifferenceFromString(compare_price_value, price_value);
if(percentageDifference){
$this_product_container.find(".js-offer-percentage").text(percentageDifference);
$this_product_container.find(".js-offer-label").css("display" , "table");
}
if ($this_compare_price.css("display") == "none" || !percentageDifference) {
$this_product_container.find(".js-offer-label").hide();
}
if ($this_add_to_cart.hasClass("nostock")) {
$this_product_container.find(".js-stock-label").show();
}
else {
$this_product_container.find(".js-stock-label").hide();
}
if ($this_price.css('display') == 'none'){
$installment_container.hide();
$installment_text.hide();
}else{
$installment_text.show();
}
});Configurações
No arquivo config/settings.txt, adicionaremos um checkbox que ativa a funcionalidade na seção "Lista de produtos".
title
title = Variantes de color
checkbox
name = product_color_variants
description = Mostrar variantes de color en listado de productosTraduções
Nesta etapa, adicionamos os textos para as traduções no arquivo config/translations.txt.
es "colores" pt "cores" en "colors" es_mx "colores" es "Ver más colores" pt "Ver mais cores" en "See more colors" es_mx "Ver más colores" es "Variantes de color" pt "Variações de cor" en "Color variants" es_mx "Variantes de color" es "Mostrar variantes de color en listado de productos" pt "Mostrar variações de cores na lista de produtos" en "Show color variants in product list" es_mx "Mostrar variantes de color en listado de productos"
Ativação
Por último, você pode ativar funcionalidade no Administrador Nuvem, na seção ‘Personalizar seu layout atual’ dentro de ‘Lista de produtos’:


Lembre-se, para que o produto funcione, ele deve ter pelo menos 2 opções da variante "Cor".