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.

Ejemplo del filtro de entregas aplicado en el e-commerce
Vista del filtro de entregas funcionando en la tienda online.