Uno de los puntos que más preocupa a los clientes de una tienda online es el tiempo de entrega de los productos. Algunos necesitan recibir su pedido en 24 horas, mientras que otros pueden esperar 48/72 horas o incluso 5 días si compensa en precio. Para responder a esta necesidad, he desarrollado un filtro específico que permite seleccionar los productos en función de su plazo de entrega.
El reto
El cliente quería ofrecer a los usuarios la posibilidad de filtrar productos por tiempos de entrega. El problema era que cada plazo de entrega está directamente relacionado con varios proveedores distintos, y había que conseguir que la selección fuese clara, rápida y sencilla para el usuario final.
La solución
Implementé un sistema de presets de entrega que agrupa automáticamente los provider_id
según los plazos establecidos:
- 24 horas : proveedores con entregas ultrarrápidas.
- 48/72 horas : proveedores estándar, excluyendo los de 24h y 5d.
- 5 días : proveedores con entregas más largas.
El sistema detecta qué opción está activa, genera los inputs ocultos correspondientes y actualiza el filtro de forma dinámica. De esta forma, el usuario solo tiene que elegir un radio button (Todos, 24h, 48/72h o 5d), y la lógica del filtro se encarga de enviar los proveedores adecuados en la búsqueda.
Beneficio para el e-commerce
Gracias a este filtro, la experiencia de compra mejora notablemente:
- El cliente final encuentra más rápido lo que necesita.
- Se reducen devoluciones y abandonos por plazos de entrega inesperados.
- El e-commerce transmite confianza y transparencia.
En definitiva, este desarrollo convierte una necesidad técnica compleja (relacionar proveedores y plazos de entrega) en una experiencia simple y clara para el comprador.
Parte técnica: cómo está implementado
Para los que quieran ver la parte técnica, aquí dejo el código completo y un desglose de cómo funciona cada bloque.
{# === PRESETS DE ENTREGA === #}
{% set providersIdsAll = db().select('provider_id').where('status', '1').get('provider').result_array_key('provider_id')%}
{% set providersIdsAll = providersIdsAll|sort|values %}
{# definimos los que van fijos #}
{% set ids24h = ['8'] %}
{% set ids5d = ['26','12','13'] %}
{# la lista de 48/72 son todos los providers menos los de 24h y 5d #}
{% set ids48_72 = providersIdsAll|map(v => v|string)|filter(v => v not in ids24h and v not in ids5d) %}
{% set deliveryPresets = {
'48_72': { 'label': '48/72 horas', 'ids': ids48_72 },
'24h': { 'label': '24 horas', 'ids': ids24h },
'5d': { 'label': '5 días', 'ids': ids5d }
} %}
{# === LEER provider[] DE REQUEST Y NORMALIZAR === #}
{% if isPost() %}
{% set _prov = post('provider') ?: [] %}
{% else %}
{% set _uriProv = uri_value('provider') ?: [] %}
{% if _uriProv is iterable %}
{% set _prov = _uriProv|values %}
{% else %}
{% set _prov = _uriProv ? _uriProv|split('::') : [] %}
{% endif %}
{% endif %}
{% set providerIdsSelected = _prov|map(v => v|string) %}
{% set providerIdsSelected = providerIdsSelected|sort|values %}
{# === DETERMINAR PRESET ACTIVO === #}
{% set selectedPreset = '' %}
{% for key,p in deliveryPresets %}
{% if providerIdsSelected|length > 0 and (providerIdsSelected|sort == p.ids|sort|values) %}
{% set selectedPreset = key %}
{% endif %}
{% endfor %}
{% set isAllSelected = providerIdsSelected|length == 0 %}
{# === UI === #}
<div class="filterBlock{{ (not isAllSelected) ? ' opened opened2' : ' opened' }}">
<p class="group JStriggerSlide" aria-controls="delivery-options" aria-expanded="true">
Entrega
<i class="fa fa-angle-right"></i>
<i class="fa fa-angle-down"></i>
</p>
<ul id="delivery-options">
<li class="radio">
<input id="delivery_all"
type="radio"
class="JS_check JSprovider"
name="delivery"
form="detachedRadios"
value="all"
{{ isAllSelected ? 'checked="checked"' : '' }}>
<label for="delivery_all">Todos</label>
</li>
{% for key,p in deliveryPresets %}
{% set rid = 'delivery_' ~ key %}
<li class="radio">
<input id="{{ rid }}"
type="radio"
class="JS_check JSprovider"
name="delivery"
form="detachedRadios"
value="{{ key }}"
{{ (selectedPreset == key) ? 'checked="checked"' : '' }}>
<label for="{{ rid }}">{{ p.label }}</label>
</li>
{% endfor %}
</ul>
{# Inputs REALES (se habilitan solo si el preset corresponde) #}
<div id="JSdeliveryHiddenSets" style="display:none;">
{% for key,p in deliveryPresets %}
<div class="JSpreset" data-preset="{{ key }}">
{% for id in p.ids %}
<input type="hidden"
name="provider[]"
value="{{ id }}"
{{ (selectedPreset == key) ? '' : 'disabled' }}>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
Explicación del código
- Presets de entrega: primero se cargan todos los proveedores activos desde base de datos. Después se definen los grupos fijos (24h y 5d) y se calcula el grupo dinámico (48/72h = resto de proveedores).
- Normalización de la request : se leen los parámetros
provider[]
ya sea por POST o desde la URL, y se convierten en un array ordenado y limpio. - Determinación del preset activo: si los proveedores seleccionados coinciden con alguno de los grupos definidos, se marca ese preset como activo. Si no hay selección, se interpreta como “Todos”.
- UI: se construye el bloque de filtros con radio buttons (Todos, 24h, 48/72h, 5d). Cuando el usuario selecciona uno, el sistema activa los inputs ocultos correspondientes al preset, para que al enviar la búsqueda solo se incluyan los provider_id correctos.
Parte JavaScript: activación dinámica
Para complementar el filtro, añadí un pequeño script en jQuery que se encarga de habilitar y deshabilitar los inputs hidden
según el preset elegido en el filtro. Así garantizamos que solo se envíen al servidor los proveedores correspondientes al tiempo de entrega seleccionado.
$(document)
.on('change', '.JSprovider', function() {
var val = $(this).val();
$('#JSdeliveryHiddenSets .JSpreset input').prop('disabled', true);
if(val !== 'all') {
$('#JSdeliveryHiddenSets .JSpreset[data-preset="'+val+'"] input').prop('disabled', false);
}
})
Explicación del código
- Evento change: escuchamos los cambios en cualquier radio con clase
.JSprovider
. - Deshabilitar todo: cada vez que cambia la selección, se deshabilitan todos los inputs ocultos.
- Activar el preset correcto: si la opción seleccionada no es
all
, se buscan los inputs del preset correspondiente y se habilitan.
De este modo conseguimos una lógica clara y mantenible: el usuario ve un filtro sencillo de tiempos de entrega, y por debajo se gestiona automáticamente la complejidad de los proveedores.
