En este tutorial, vamos a implementar la promoción de cross selling al agregar un producto al carrito.
HTML
1. Vamos a crear un nuevo snipplet llamado snipplets/cross-selling.tpl dentro de la carpeta snipplets. En este archivo, utilizaremos el componente privado cross-selling-form.
El código correspondiente es el siguiente:
{# Cross selling promotion form #} {% if promotion %} {{ component( 'promotions/cross-selling-form', { css_classes: { main_container: 'm-auto', image_container: 'position-relative', discount_percentage_label: 'label label-accent position-absolute label-top-left', image: 'img-fluid w-100 lazyload product-image-limited', form_container: 'px-4 py-3', product_name: 'font-big text-center mb-2', prices_container: 'price-container text-center mb-3', price_wrapper: 'd-inline-block', original_price: 'price-compare font-weight-normal mb-0', promo_price: 'text-primary mb-0', variant_selection_group: 'form-group px-2 mb-2', variant_selection_label: 'form-label', variant_select: 'form-select', variant_select_icon_container: 'form-select-icon', add_to_cart_button: 'btn btn-primary btn-block mt-3 mb-1' }, icon_config: { use_svg_icon: false, use_custom_icon: true, custom_icon_markup: include("snipplets/svg/chevron-down.tpl", { svg_custom_class: "icon-inline icon-w-12 icon-md mr-3" }) }, content: { button_placeholder: include('snipplets/placeholders/button-placeholder.tpl', { custom_class: 'btn-block mt-3 mb-1' }) } }) }} {% endif %}
2. Hacia el final del archivo snipplets/header/header.tpl, es necesario agregar el siguiente extracto de código:
{# Cross selling promotion notification on add to cart #}
{% embed "snipplets/modal.tpl" with {
modal_id: 'js-cross-selling-modal',
modal_class: 'bottom modal-bottom-sheet h-auto overflow-none modal-body-scrollable-auto',
modal_header: true,
modal_header_class: 'm-0 w-100',
modal_position: 'bottom',
modal_transition: 'slide',
modal_footer: true,
modal_width: 'centered-md m-0 p-0 modal-full-width modal-md-width-400px'
} %}
{% block modal_head %}
{{ '¡Descuento exclusivo!' | translate }}
{% endblock %}
{% block modal_body %}
{# Promotion info and actions #}
<div class="js-cross-selling-modal-body" style="display: none"></div>
{% endblock %}
{% endembed %}
3. Ahora bien, para que el modal pueda abrirse y mostrar la promoción correctamente es necesario que en snipplets/modal.tpl contemos con el parámetro {{ modal_header_class }}
. En caso de no tenerlo es necesario modificar el componente. Para ello, debemos buscar la siguiente línea en ese archivo:
<div class="js-modal-close {% if modal_mobile_full_screen %}js-fullscreen-modal-close{% endif %} modal-header">
Y reemplazarla por esta:
<div class="js-modal-close {% if modal_mobile_full_screen %}js-fullscreen-modal-close{% endif %} modal-header {{ modal_header_class }}">
4. Es necesario ajustar el resumen del carrito para mostrar el descuento aplicado por cross selling. Para ello, en snipplets/cart-totals.tpl, debemos buscar la siguiente línea, que debería aparecer dos veces:
<span class="js-promo-in" style="display:none;">{{ "en" | translate }}</span>
Y justo encima de esa línea, agregar lo siguiente:
<span class="js-promo-discount" style="display:none;"> {{ "Descuento" | translate }}</span>
Posteriormente, debemos buscar:
{% elseif promotion.isBuyXPayY %}
{{ promotion.buy }}x{{ promotion.pay }}
Y debajo incorporar:
{% elseif promotion.isCrossSelling %}
{{ "Descuento" | translate }}
Ambos cambios deberían aparecer dos veces en el mismo archivo.
CSS
Requisito:
Tener agregados en tu diseño las clases helpers. Puedes seguir este este pequeño tutorial para hacerlo (simplemente es copiar y pegar algunas clases, no tomará más de 1 minuto).
1. Para que los estilos se apliquen correctamente, es necesario ubicarlos en el lugar adecuado. Todos los cambios se realizarán en static/css/style-async.scss.tpl.
Buscamos el selector .modal
que está fuera de los media queries. Luego, dentro de esta, buscamos el selector &-centered
, y allí insertamos lo siguiente:
&-md.modal-show {
left: 50%;
transform: translateX(-50%);
&.modal-bottom-md,
&.modal-bottom {
top: 50%;
bottom: auto;
left: 50%;
height: fit-content;
transform: translate(-50%, -50%);
}
}
2. Luego, debemos agregar estos estilos, verificando que no queden dentro de ninguna media query:
.modal-full-width {
width: 100%;
max-width: 100%;
}
.modal-body-scrollable-auto .modal-body {
max-height: calc(100vh - 100px);
overflow-y: auto;
}
.label-top-left {
top: 25px;
left: 25px;
z-index: 2;
}
.product-image-limited {
max-height: 320px;
max-width: 100%;
object-fit: contain;
}
3. Por último, en la sección de media queries agregamos lo siguiente:
{# /* // Max width 767px */ #}
@media (max-width: 767px) {
.product-image-limited {
max-height: 210px;
}
}
4. Dentro de la misma sección, debemos buscar la media query de min-width: 768px
y, dentro de ella, localizar la definición de .modal
, como antes, pero esta vez para la versión desktop. En este caso, lo que debemos agregar es lo siguiente:
&-centered-md.modal-show {
left: initial;
transform: none;
&.modal-bottom {
top: 50%;
}
}
Y, más abajo:
&-md-width-400px {
width: 400px;
max-width: 90vw;
}
JS
1. Es necesario modificar la función de callback que se ejecuta al agregar un producto al carrito. Para ello, debemos ir al archivo base/static/js/store.js.tpl y buscar la siguiente línea:
var callback_add_to_cart = function(html_notification_related_products){
Luego, reemplazarla por:
var callback_add_to_cart = function(html_notification_related_products, html_notification_cross_selling) {
2. Dentro del mismo callback, agregamos el siguiente código al final de la función:
{# Display cross-selling promotion modal #}
if (html_notification_cross_selling != null) {
jQueryNuvem('.js-cross-selling-modal-body').html("");
modalOpen('#js-cross-selling-modal');
jQueryNuvem('.js-cross-selling-modal-body').html(html_notification_cross_selling).show();
}
{
# Change prices on cross-selling promotion modal #
}
const crossSellingContainer = document.querySelector('.js-cross-selling-container');
if (crossSellingContainer) {
LS.fillCrossSelling(crossSellingContainer);
}
3. Para habilitar correctamente la funcionalidad de compra vía AJAX, es necesario realizar las siguientes modificaciones en el código:
Primero, identificar el siguiente comentario en el archivo:
{# Define if event comes from quickshop or product page #}
Y reemplazarlo por:
{# Define if event comes from quickshop, product page or cross selling #}
Luego, debajo de la línea:
var isQuickShop = $productContainer.hasClass('js-quickshop-container');
Agregar lo siguiente:
var isCrossSelling = $productContainer.hasClass('js-cross-selling-container');
A continuación, ubicar la siguiente estructura:
if (!isQuickShop) {
// ...
}
Y reemplazarla por:
{# Add item information for notification #}
if (isCrossSelling) {
var imageSrc = $productContainer.find('.js-cross-selling-product-image').attr('src');
var quantity = $productContainer.data('quantity')
var name = $productContainer.find('.js-cross-selling-product-name').text();
var price = $productContainer.find('.js-cross-selling-promo-price').text();
var addedToCartCopy = $productContainer.data('add-to-cart-translation');
} else if (!isQuickShop) {
Por último, al final de la función callback_add_to_cart
(modificada previamente), agregar lo siguiente:
{# Automatically close the cross-selling modal by triggering its close button #}
if (isCrossSelling) {
jQueryNuvem('#js-cross-selling-modal .js-modal-close').trigger('click');
}
Traducciones
En este paso agregamos los textos para las traducciones en el archivo config/translations.txt:
es "¡Descuento exclusivo!"
pt "Desconto exclusivo!"
en "Exclusive discount!"
es_mx "¡Descuento exclusivo!"
es "Descuento"
pt "Desconto"
en "Discount"
es_mx "Descuento"
Activación
Para activar la funcionalidad, accede al administrador de la tienda y dirígete a la sección Descuentos > Promociones. Desde allí, crea una nueva promoción, configura los parámetros según sea necesario y guarda los cambios.