Advanced Filtering

Build dynamic pages that filter content by multiple tags or criteria

2 min read 420 words

Standard tag pages list content for one tag (e.g.,/tags/python/). But sometimes users want to find content that matches multiple criteria, like "Tutorials" AND "Python" AND "Beginner".

This guide shows how to build an advanced filter using Kida template set logic.

The Logic: Set Intersections

Kida (and Jinja2) allows us to treat lists of pages as mathematical sets.

  • Union: All unique items in A or B.
  • Intersection: Items that are in BOTH A and B.
  • Difference: Items in A but not in B.

Example: Building a "Recipe Finder"

Imagine a documentation site where you want to find "API Guides" for "v2.0".

1. Accessing the Data

Bengal exposessite.taxonomieswhich gives us lists of pages for each tag.

{% let api_pages = site.taxonomies.tags["api"].pages %}
{% let v2_pages = site.taxonomies.tags["v2"].pages %}

2. Finding the Intersection

Use the|> intersect()filter to find pages in both lists:

{% let results = api_pages |> intersect(v2_pages) %}

<h2>API v2 Guides ({{ results | length }})</h2>
<ul>
  {% for page in results %}
    <li><a href="{{ page.href }}">{{ page.title }}</a></li>
  {% end %}
</ul>

Tip

For more complex filtering, use|> where()with operators:

{% let results = site.pages
  |> where('tags', 'api', 'in')
  |> where('tags', 'v2', 'in') %}

Advanced: The "Filter Page" Layout

For a dynamic filter page (e.g.,/search/), we typically rely on client-side JavaScript because pre-rendering every combination of tags is expensive (combinatorial explosion).

However, for specific, high-value combinations, you can create dedicated pages.

Step 1: Create the Page

site/content/guides/python-tutorials.md:

---
title: Python Tutorials
variant: filter_page
filter_tags: ["python", "tutorial"]
---
Here are all our Python tutorials.

Step 2: Create the Layout

templates/filter_page.html:

{% extends "base.html" %}

{% block content %}
  <h1>{{ page.title }}</h1>

  {# Start with all pages, then filter by each required tag #}
  {% let matches = site.pages %}

  {% for tag in page.metadata.filter_tags %}
    {% let tag_pages = site.pages |> where('tags', tag, 'in') %}
    {% let matches = matches |> intersect(tag_pages) %}
  {% end %}

  {# Render Results #}
  <div class="results">
    {% for post in matches %}
      {% include "partials/card.html" %}
    {% else %}
      <p>No matches found.</p>
    {% end %}
  </div>

{% end %}

Summary

Use Set Intersections to build powerful "Topic Pages" that aggregate content from multiple dimensions without manually curating lists.

Seealso