Skip to main content

Multiple dropdown filters

Demo

Ananas

Brun
Jaune
Fruits

Avocat

Vert
Fruits

Banane

Jaune
Fruits

Brocoli

Vert
Légumes

Celeri

Vert
Légumes

Citron

Jaune
Fruits

Filet mignon

Gris
Viande

Lime

Vert
Fruits

Patate

Brun
Jaune
Légumes

Pomme

Rouge
Fruits

Salade

Vert
Légumes

Steak

Rouge
Viande

Installation

Importez la fonction dans votre projet

import { MultipleFilters } from "@overdog/fn"
Note : Vous devez combiner les filtres avec l'élément dropdown pour avoir le look de ce démo. Vos forms se retrouveront dans des dropdowns.

Instance et initialisation

new MultipleFilters("#filter-wrapper-multiple-dropdown", {
   divIds: ["listing"]
}).init()

Twig template Code

{# --------------------- SET RELATEDTO ARRAY #}

{% set relatedTo = [] %}

{# --------------------- CATEGORY GROUP 1 - COLORS #}

{% set colorsUrlQueryName = 'colors'|t %} {# variable also used in the form name #}
{% set colorsUrlQueryValue = craft.app.request.getQueryParam(colorsUrlQueryName)|split(',')|filter %}
{% if colorsUrlQueryValue %}
  {% set relatedTo = relatedTo|merge([{
    targetElement: craft.categories({ group: 'groupFoodColors', slug: colorsUrlQueryValue }).ids()
  }]) %}
{% endif %}

{# --------------------- CATEGORY GROUP 2 - TYPES #}

{% set typesUrlQueryName = 'types'|t %} {# variable also used in the form name #}
{% set typesUrlQueryValue = craft.app.request.getQueryParam(typesUrlQueryName)|split(',')|filter %}
{% if typesUrlQueryValue %}
  {% set relatedTo = relatedTo|merge([{
    targetElement: craft.categories({ group: 'groupFoodTypes', slug: typesUrlQueryValue }).ids()
  }]) %}
{% endif %}

{# --------------------- MERGE THE CATEGORIES FOR THE RELATEDTO #}

{% if relatedTo|length > 1 %}
  {% set relatedTo = ['and']|merge(relatedTo) %}
{% endif %}

{# --------------------- MAIN QUERY - with eager loading the categories #}

{% set foodQuery = craft.entries()
  .section('structureFood')
  .orderBy('title')
  .relatedTo(relatedTo ? relatedTo : null)
  .with(['structureFoodColors', 'structureFoodTypes'])
  .all()
%}

{# --------------------- FETCH CATEGORIES GROUP TO POPULATE FILTERS #}

{# categories group #}
{% set typesCatGroup = craft.categories().group('groupFoodTypes').all() %}
{% set colorsCatGroup = craft.categories().group('groupFoodColors').all() %}


{# --------------------- FILTERS LAYOUT #}

{# ID is used by Javascript #}
<div id="filter-wrapper-multiple-dropdown" class="grid grid-cols-1 md:grid-cols-3 gap-half mb-half">

  {# TYPES FORM - Dropdown filter multiple choices #}
  {% if typesCatGroup|length %}
    <div class="filter-dropdown relative">
      <button 
         class="flex items-center border-b border-[#a5adb9] h-[50px] justify-between text-left w-full"
         aria-expanded="false"
         aria-controls="form-type"
      >        
      <span>{{ 'Filter by type'|t }}</span>
         {# caret #}
         <span class="
            border-b-0 border-x-transparent border-x-[0.3em] border-t-[0.3em] border-t-slate-600
            transition-all ease-linear duration-200
            parent-is-open:rotate-180
            ">
         </span>
      </button>
      <div 
         id="form-types" {# only for aria-controls - not used by JS #}
         class="absolute hidden left-0 p-4 bg-white rounded-b-md shadow-md overflow-hidden w-full z-10
         parent-is-open:block"
      >
        <form data-fn-filter-group="{{ typesUrlQueryName }}">
          <fieldset>
            <legend class="sr-only">{{ 'Filter by type'|t }}</legend>
            {% for category in typesCatGroup %}
              <div class="flex items-center relative py-1">
                  <input 
                     id="{{ category.slug }}" 
                     class="inset-0 opacity-0 absolute -z-1 peer" 
                     type="checkbox"
                     name="{{ category.slug }}" 
                     value="{{ category.slug }}" {{(category.slug in typesUrlQueryValue) ? 'checked' }}
                  />
                  <label
                     class="cursor-pointer flex items-center w-full
                     peer-checked:before:bg-black
                     before:bg-[#c4cad2] before:cursor-pointer before:inline-block before:h-4 before:w-4 before:mr-4 before:shrink-0" 
                     for="{{ category.slug }}"
                  >
                     {{ category.title }}
                  </label>
              </div>
            {% endfor %}
          </fieldset>
        </form>
      </div>
    </div>
  {% endif %}

  {# COLORS FORMS - Dropdown filter fake select single choice #}
  {% if colorsCatGroup|length %}
    <div class="filter-dropdown relative">
      <button 
         class="flex items-center border-b border-[#a5adb9] h-[50px] justify-between text-left w-full"
         aria-expanded="false"
         aria-controls="form-colors"
      >        
      <span data-fn-dropdown-text>{{ 'Filter by colors'|t }}</span>
      {# caret #}
      <span class="
         border-b-0 border-x-transparent border-x-[0.3em] border-t-[0.3em] border-t-slate-600
         transition-all ease-linear duration-200
         parent-is-open:rotate-180
         ">
      </span>
   </button>
      <div
         id="form-colors" {# only for aria-controls - not used by JS #}
         class="absolute hidden left-0 bg-white rounded-b-md shadow-md overflow-hidden w-full z-10
         parent-is-open:block"
      >
        <form data-fn-filter-group="{{ colorsUrlQueryName }}">
          <fieldset>
            <legend class="sr-only">{{ 'Filter by colors'|t }}</legend>
            <div>
               <input 
                  id="all" 
                  class="absolute inset-0 opacity-0 -z-1"
                  type="radio" 
                  name="cat-radio" 
                  value=""
               />
              <label class="cursor-pointer block px-3.5 py-1.5 w-full hover:bg-[#e7edee]" for="all">{{ 'All colors'|t }}</label>
            </div>
            {% for category in colorsCatGroup %}
              {# name must be the same for radio button #}
              <div>
                  <input 
                     id="{{ category.slug }}"
                     class="absolute inset-0 opacity-0 -z-1" 
                     type="radio" 
                     name="cat-radio" 
                     value="{{ category.slug }}" {{(category.slug in colorsUrlQueryValue) ? 'checked' }}
                  />
                <label class="cursor-pointer block px-3.5 py-1.5 w-full hover:bg-[#e7edee]" for="{{ category.slug }}">{{ category.title }}</label>
              </div>
            {% endfor %}
          </fieldset>
        </form>
      </div>
    </div>
  {% endif %}

</div>


{# --------------------- LAYOUT WIH LOOP FOR CARDS #}

{# ID is used by Javascript #}
<div id="listing" class="grid grid-col-1 md:grid-cols-3 gap-third">
   {% if foodQuery|length %}
    {{ include('_lib-fn/_card', { queryName: foodQuery }, ignore_missing = true )}}
  {% else %}
    <div>{{ ('There is no content matching your criteria.')|t }}</div>
  {% endif %}
</div>