11

I would like to be able to filter my entries list by multiple categories on the front end. For example, if I first click a category button "lunge" then the results would show entries which are categorized as "lunge". If I click a second category button labeled "dumbbell" then the results would be filtered more and show only entries that are categorized as both "lunge" and "dumbbell".

I found some similar threads but haven't been able to get the suggestions to work for me. I believe I need to pass the categories into a URL query string like this:

www.website.com/training/exercise-list?q=lunge,dumbbell

where q is my search query parameter and lunge and dumbbell are the categories that were clicked.

  • Section is called exercisesDb
  • Category Group is calledtrainingCategoryGroup
  • Category Field in the section is called trainingCategory

Thanks so much!

2 Answers 2

10

First, I would use something like training in your query string. It's a little more readable and you aren't searching for the words lunge and dumbbell anywhere in those entries, just entries related to those category slugs.

{# First you would find any training categories in the URL query string. #}
{% set trainingQuery = craft.request.getParam('training') %}

{# Then find categories that match the slugs in your query string. #}
{% set trainingCategories = craft.categories.group('trainingCategoryGroup').slug(trainingQuery) %}

{# setup your search parameters #}
{% set searchParams = {
  relatedTo:  trainingCategories,
  section: 'exercisesDb'
} %}

{# Find your entries #}
{% set entries = craft.entries(searchParams).order('score') %}

Your search form just needs to have the checkbox's input name as training[]. If it's on the same page, test to see if the category slug is in the trainingQuery array so it can be marked as checked or not. Create this by finding all the categories in the trainingCategoryGroup group.

<form action="http://www.website.com/training/exercise-list">  

  {% for category in craft.categories.group('trainingCategoryGroup') %}
    <label><input type="checkbox" name="training[]" value="{{ category.slug }}" {{ category.slug in trainingQuery ? 'checked'}}>{{ category.title }}</label><br>
  {% endfor %}

  <button type="submit">Search</button>  
</form>

Then output your list of entries. This is a simple example.

{% if entries | length %}
  <ol>
    {% for entry in entries %}
      <li>
        <a href="{{ entry.url }}">{{ entry.title }}</a><br />
      </li>
    {% endfor %}
  </ol>
{% else %}
  <p>No results</p>
{% endif %}

If the query string is blank, this will show all of your entries. If you want to restrict that, you can wrap the previous code block in this...

{% if trainingQuery %}
  ... (entries) ...
{% endif %}

This is an inclusive search that will match entries in ANY selected categories. If you want an exclusive search instead (category AND category), you have to do it a little differently.

{# Get search parameters from the URL query string #}
{% set trainingQuery = craft.request.getParam('training') %}

{# Start an array of search parameters (relationParam) with 'and' to match ALL categories #}
{% set relationParam = ['and'] %}

{# Find categories that match the slugs in your query string... #}
{% for querySlug in trainingQuery %}
  {% set trainingCategory = craft.categories.group('trainingCategoryGroup').slug(querySlug) %}

  {# And merge them into the relationParam array. #}
  {% set relationParam = relationParam|merge([{ targetElement: trainingCategory }]) %}
{% endfor %}

{# Avoid passing an array with `['and']` only #}
{% if relationParam|length < 2 %}
  {% set relationParam = '' %}
{% endif %}

{% set searchParams = {
  relatedTo:  relationParam,
  section: 'exercisesDb'
} %}
14
  • Thank you Alex! I wasn't able to get the checkbox working so I manually typed in the query into my browser to test so maybe I have the query string incorrect when adding parameters. When I use the query string http://www.website.com/training/exercise-list?training=lunge&training=dumbbell it shows me all entries that contain either "lunge" or "dumbbell" categories. I'd like it to first filter by "lunge" which outputs say 3 entries, then filter those 3 entries by the second query "dumbbell" which would bring it to show only 1 entry that is categorized as both "lunge" and "dumbell".
    – Lori
    Apr 8, 2015 at 14:37
  • Hmm. You may need to use name="training" on your checkboxes then instead of name="training[]". I'll add and example of doing a combined search (cat AND cat).
    – Alex Roper
    Apr 9, 2015 at 2:10
  • Alex, I can't seem to get the new "cat AND cat" code to work. I can't get all my code in the this comments field because it's too many characters. Here are your variables and mine. toolTypeQuery = trainingQueryrelationParam = relationParam querySlug = querySlug toolType = trainingCategoriescollaborationToolTypes = trainingCategoryGroupcollaborationTools = exercisesDb • My URL looks like this: http://www.website.com/training/exercise-list?training=lunge&training=dumbbell (I'm manually typing in URL so maybe my string is incorrect?)
    – Lori
    Apr 11, 2015 at 1:29
  • Sorry, my new example had the wrong variable names specific to my projects. I updated them with your variables names. Try it now. If you still have trouble, you can edit your original question and add your code, or send the complete code with a Github Gist or Pastebin snippet.
    – Alex Roper
    Apr 11, 2015 at 9:01
  • Hi Alex. Darn, still can't get the code to work. I pasted my trimmed down code into Pastebin as you suggested. In addition to your code I also included the entries loop in case that's incorrect. pastebin.com/raw.php?i=vxxszY62
    – Lori
    Apr 11, 2015 at 14:08
1

For both Craft 2 and 3, there are Facated Navigation plugins that handle this for you.

For Craft 3 For Craft 2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.