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 productos
Traduçõ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".