Skip to content

Instantly share code, notes, and snippets.

@samhernandez
Created December 14, 2018 20:17
Show Gist options
  • Save samhernandez/54f8ab8cbd464d94ad77a2adeeaab6a8 to your computer and use it in GitHub Desktop.
Save samhernandez/54f8ab8cbd464d94ad77a2adeeaab6a8 to your computer and use it in GitHub Desktop.
Dependent category filter navs
{#
Assuming:
- this route is like: `/listing/[primary category slug]/[secondary category slug]`
- the secondary category nav should only show what is relevant to the primary category
#}
{% set slug1 = craft.app.request.segment(2) %}
{% set slug2 = craft.app.request.segment(3) %}
{% set primaryCat = craft.categories.group('primaryCategory').slug(slug1).one() %}
{% set secondaryCat = craft.categories.group('secondaryCategory').slug(slug2).one() %}
{#
It's probaby a good idea to cache this nav section so these queries
don't need to run on every page load. We'll handle the `.active` css
class with a `replace()` method on the cached content.
#}
{% set navs %}
{% cache using key slug1 ~ '/' ~ slug2 %}
{#
Primary category nav
- only show categories that have entries
- cache so these big queries don't need to happen every request
#}
{% set allProductIds = craft.entries.section('mySection').ids() %}
{% set primaryCatsToShow = craft.categories.group('primaryCategory').relatedTo(allProductIds).all() %}
<ul>
{% for cat in primaryCatsToShow %}
<li class="active-{{ cat.slug }}"><a href="/listing/{{ cat.slug }}/all">{{ cat.title }}</a></li>
{% endfor %}
</ul>
{#
Secondary category nav
- Only show categories that have entries related to
the primary category
#}
{% set filteredProductIds = craft.entries.section('mySection').relatedTo(primaryCat).ids() %}
{% set secondaryCatsToShow = craft.categories.group('secondaryCategory').relatedTo(filteredProductIds).all() %}
<ul>
{% for cat in secondaryCatsToShow %}
<li class="active-{{ cat.slug }}"><a href="/listing/{{ slug1 }}/{{ cat.slug }}">{{ cat.title }}</a></li>
{% endfor %}
</ul>
{% endcache %}
{% endset %}
{#
Now, on the cached content, we can replace `active-some-slug` with just `active`
for the current page slugs.
#}
{{ navs | replace('active-' ~ slug1, 'active') | replace('active-' ~ slug2, 'active') | raw }}
<hr>
{#
Build a `relatedTo` param (array)
- the first value should be 'and' so entries must have cat1 *and* cat2
(default behavior is an entry can match cat1 *or* cat2 - more results)
- then we'll pass elements as the remaining array items
- we won't assume either category was found
Example
```
[
'and',
{element: primaryCat},
{element: secondaryCat}
]
```
#}
{% set relatedToParam = ['and'] %}
{% if primaryCat %}
{% set relatedToParam = relatedToParam | merge([{element: primaryCat}]) %}
{% endif %}
{% if secondaryCat %}
{% set relatedToParam = relatedToParam | merge([{element: secondaryCat}]) %}
{% endif %}
{#
We'll use a criteria object for simplicity.
It could end up like this:
```
{
section: 'mySection',
relatedTo: [
'and',
{element: primaryCat},
{element: secondaryCat}
]
}
```
#}
{% set criteria = {section: 'mySection'} %}
{# Only if we have more than just `['and']` #}
{% if relatedToParam | length > 1 %}
{% set criteria = criteria | merge({relatedTo: relatedToParam}) %}
{% endif %}
{# The list #}
<ul>
{% for entry in craft.entries(criteria).all() %}
<li>{{ entry.title }}</li>
{% endfor %}
</ul>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment