Visión general
Es común que las tiendas de moda unifiquen productos por talla y también por color, lo que puede reducir visualmente las opciones en las categorías. Para mejorar la usabilidad e incentivar la compra rápida, podemos desglosar por color en la vitrina vía Twig, exhibiendo por ejemplo “Remera básica blanca”, “Remera básica negra”, etc., aunque sea el mismo producto con variaciones.
Objetivo
- Crear en el Admin la opción para activar/desactivar el recurso.
- Agregar la lógica en
snipplets/product_grid.tpl
para separar el producto por color.
Configuración en el Admin (config/settings.txt)
En config/settings.txt
, en la sección “Listado de productos”, agrega:
title
title = Separación de productos por color
checkbox
name = separation_products_by_color
description = Separa los productos en la ventana de visualización de categorías por color.
Traducciones (config/translations.txt)
Agrega las claves i18n para título y descripción:
es "Separación de productos por color"
pt "Separação de produtos por cor"
en "Separation of products by color"
es_mx "Separación de productos por color"
es "Separa los productos en la ventana de visualización de categorías por color."
pt "Separa os produtos na visualização de categorias por cor."
en "Separates products in the category view by color."
es_mx "Separa los productos en la ventana de visualización de categorías por color."
Lógica en la vitrina (snipplets/product_grid.tpl)
Sustituye el bucle estándar del grid por un modo avanzado que separa por color cuando el recurso esté activo.
Antes
{% if products and pages.is_last %}
<div class="last-page" style="display:none;"></div>
{% endif %}
{% for product in products %}
{% include 'snipplets/grid/item.tpl' %}
{% endfor %}
Después
{# Exibe marcador de última página quando existem produtos e a paginação está na última página #}
{% if products and pages.is_last %}
<div class="last-page" style="display:none;"></div>
{% endif %}
{# Loop principal: percorre os produtos da página atual #}
{% for product in products %}
{# Flag de controle: se o modo avançado renderizar itens, evitamos duplicar no fallback #}
{% set show_advanced_mode = false %}
{# Modo avançado: separar por cor usando variants_object (somente se existir variação de "Cor") #}
{% if settings.separation_products_by_color and product.variations %}
{# 1) Checa se há uma variação cujo nome é Cor/Color e guarda seu índice (0,1,2) #}
{% set color_index = null %}
{% for variation in product.variations %}
{% if variation.name | lower in ['color', 'cor'] and color_index is null %}
{% set color_index = loop.index0 %}
{% endif %}
{% endfor %}
{# 2) Se encontrou variação de cor, percorre variants_object e rende um item por cor única #}
{# Obs.: o "product.variants_object > 1" funciona como uma checagem rápida para evitar cenários sem múltiplas variantes #}
{% if color_index is not null and product.variants_object > 1 %}
{% set rendered_colors = [] %}
{# Percorre todas as variantes (cada combinação de opções) #}
{% for variante in product.variants_object %}
{# Renderiza somente variantes disponíveis e visíveis #}
{% if variante.available and variante.is_visible %}
{# Extrai o nome da cor desta variante usando o índice da variação de cor (option0/1/2) #}
{% set color_name = attribute(variante, 'option' ~ color_index) | default('') %}
{# Garante cor válida e evita duplicar a mesma cor (dedupe) #}
{% if color_name and (color_name not in rendered_colors) %}
{% set variant_color_name = color_name %}
{# Inclui o cartão de produto passando a variante específica e o nome da cor #}
{% include 'snipplets/grid/item.tpl' with { special_variant: variante, variant_color_name: variant_color_name } %}
{# Marca a cor como já renderizada para não repetir #}
{% set rendered_colors = rendered_colors | merge([color_name]) %}
{# Sinaliza que o modo avançado foi utilizado (impede fallback abaixo) #}
{% set show_advanced_mode = true %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{# Fallback: renderiza o item padrão somente se o modo avançado NÃO foi acionado #}
{% if not show_advanced_mode %}
{% include 'snipplets/grid/item.tpl' %}
{% endif %}
{% endfor %}
Sugerencia de depuración (json_encode)
Para inspeccionar objetos en Twig, usa el filtro json_encode
dentro de una etiqueta segura:
<textarea>{{ product.variations | json_encode }}</textarea>
Ejemplo de salida
[
{
"id": 0,
"name": "Cor",
"options": [
{ "id": "Preto", "name": "Preto", "custom_data": "#000000" },
{ "id": "Azul", "name": "Azul", "custom_data": "#0000DC" }
]
},
{
"id": 1,
"name": "Tamanho",
"options": [
{ "id": "PP", "name": "PP", "custom_data": null },
{ "id": "P", "name": "P", "custom_data": null },
{ "id": "M", "name": "M", "custom_data": null },
{ "id": "G", "name": "G", "custom_data": null },
{ "id": "GG", "name": "GG", "custom_data": null }
]
}
]
Ajustes en el ítem de la vitrina (snipplets/grid/item.tpl)
Al inicio del archivo, define variables opcionales con default(null)
para no alterar el comportamiento estándar:
{% set variant_color_name = variant_color_name | default(null) %}
{% set special_variant = special_variant | default(null) %}
Seleccionando la variante en la URL
Basate en la variable existente product_url_with_selected_variant
y, si se envió una
special_variant
, fuerza el parámetro variant
:
{% set product_url_with_selected_variant = has_filters ? ( product.url | add_param('variant', product.selected_or_first_available_variant.id)) : product.url %}
{% if special_variant %}
{% set product_url_with_selected_variant = (product.url | add_param('variant', special_variant.id)) %}
{% endif %}
Imagen de la variante seleccionada
Recupera la imagen principal y, si hay special_variant
, sustitúyela por los datos de la imagen vinculada a esa variante. Desactiva la imagen secundaria para no confundir al usuario.
{% set item_img_width = product.featured_image.dimensions['width'] %}
{% set item_img_height = product.featured_image.dimensions['height'] %}
{% set item_img_srcset = product.featured_image %}
{% set item_img_alt = product.featured_image.alt %}
{% if special_variant %}
{% for image in product.other_images %}
{% if image.id == special_variant.image %}
{% set item_img_width = image.dimensions['width'] %}
{% set item_img_height = image.dimensions['height'] %}
{% set item_img_srcset = image.image %}
{% set item_img_alt = image.alt %}
{% set show_secondary_image = false %}
{% endif %}
{% endfor %}
{% endif %}
{% set item_img_spacing = item_img_height / item_img_width * 100 %}
Render del bloque de la imagen
<div class="js-product-item-image-container-private {% if show_secondary_image %}js-product-item-private-with-secondary-images{% endif %} product-item-image-container item-image{% if columns == 1 %} item-image-big{% endif %}">
<div style="padding-bottom: {{ item_img_spacing }}%;" class="js-item-image-padding position-relative d-block" data-store="product-item-image-{{ product.id }}{{variant_color_name}}">
<a href="{{ product_url_with_selected_variant }}" title="{{ product.name }}" aria-label="{{ product.name }}">
<img alt="{{ item_img_alt }}" src="{{ 'images/empty-placeholder.png' | static_url }}" 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, {{ item_img_srcset | product_image_url('huge')}} 640w, {{ item_img_srcset | product_image_url('original')}} 1024w" class="{{ image_classes }} product-item-image-featured item-image-featured" width="{{ item_img_width }}" height="{{ item_img_height }}" data-expand="{{ data_expand}}" sizes="(max-width: 768px) {{ mobile_image_viewport_space }}vw, (min-width: 769px) {{ desktop_image_viewport_space }}vw" />
{% if show_secondary_image %}
<img alt="{{ item_img_alt }}" data-sizes="auto" src="{{ 'images/empty-placeholder.png' | static_url }}" data-srcset="{{ product.other_images | first | product_image_url('small')}} 240w, {{ product.other_images | first | product_image_url('medium')}} 320w, {{ product.other_images | first | product_image_url('large')}} 480w, {{ product.other_images | first | product_image_url('huge')}} 640w, {{ product.other_images | first | product_image_url('original')}} 1024w" class="{{ image_classes}} js-product-item-secondary-image-private product-item-image-secondary item-image-secondary" sizes="(min-width: 768px) {{ desktop_image_viewport_space }}vw, {{ mobile_image_viewport_space }}vw" />
{% endif %}
<div class="placeholder-fade"></div>
</a>
</div>
</div>
Nombre del producto con el color
Después de imprimir {{ "{{ product.name }}" }}
, añade el sufijo con el nombre del color cuando exista:
{{ product.name }}
{% if variant_color_name %}
- {{ variant_color_name }}
{% endif %}
Ocultando el selector de colores
Si estás exhibiendo un ítem de color específico, oculta el componente de variaciones de color:
Antes
{% if settings.product_color_variants and not reduced_item %}
{% include 'snipplets/grid/item-colors.tpl' %}
{% endif %}
Después
{% if settings.product_color_variants and not reduced_item and not special_variant %}
{% include 'snipplets/grid/item-colors.tpl' %}
{% endif %}
