Pointers to filter by grouped tags / categories

I’m a bit lost following tutorials and other post about filters, and maybe someone can give me some pointers.

At home.php, I’m listing my posts grouped by tags/categories in sections. So each section contains posts using that tag. This, I managed to do, researching other examples:

            <?php $groups = page('list-design')->children()->listed()->filterBy('category', '!=', '') ?>
            $categories = $groups->groupBy('category');
            foreach($categories as $category => $items): ?>
                <div class="single-list">
                    <h2><?= $category ?></h2>
                        <?php foreach($items as $item) : ?>
                            <li><?= $item->title() ?><div class="icon"></div></li>
                        <?php endforeach; ?>
            <?php endforeach ?>

What I would like to do, is that each group (and its children) “dissapears” when a filter is applied.
I had something like this from a previous project in the controller folder, but was however just used for ungrouped posts:


return function($page) {

    $filterBy = get('filter');
    $unfiltered = page('list-design')->children()->sortBy('date', 'desc');

    $posts = $unfiltered
        ->when($filterBy, function($filterBy) {
            return $this->filterBy('category', $filterBy);
    $filters = $unfiltered->pluck('category', ',', true);

    return [
        'filterBy' => $filterBy,
        'unfiltered' => $unfiltered,
        'posts' => $posts,
        'filters' => $filters


I’ve been struggling to adapt what is in controller to filter a whole tag group, and not individual posts. Even so when right now it doesn’t appear to do anything at all, despite my attempts at trying different possibilities and researching on the filter compedium documentation.

Has anyone had to do anything like this before?

The controls tha apply the filter are:

                <a href="<?= $page->url()?>" class="<?= $posts === $unfiltered ? 'active' : '' ?>"><div class="icon"></div>All</a>
                <?php foreach ($filters as $filter): ?>
                    <a href="<?= $page->url() ?>?filter=<?= $filter ?>" class="<?= $filterBy === $filter ? 'active' : '' ?>"><div class="icon"></div><?= $filter ?></a>
                <?php endforeach ?>

The problem is that you have a controller and then you have additional logic in the template.

This will all fall into place if you do everything in your controller, filter first if needed, then group.

Thanks for your reply! I decided to adapt your examples from the Filter collections by tags page, and made it work.

I still need to refine some parts of my part of the code to make it more elegant, but this is what I have so far in case that it can help others.



return function($page) {

    // fetch the basic set of pages
    $articles = page('list-design')->children()->listed();
    // fetch all tags
    $tags = $articles->pluck('tags', ',', true);
    // set the tag filter
    $tag = param('tag');
    // add the tag filter
    if($tag) {
      $articles = $articles->filterBy('tags', $tag, ',');

    $groups = $articles->groupBy('tags');
    return compact('articles', 'tags', 'tag', 'groups');

Then the loop in home.php

<?php foreach($groups as $tag => $articles): ?>
    <h2><?= $tag ?></h2>
        <?php foreach($articles as $article): ?>
            <li><?= $article->title() ?></li>
        <?php endforeach ?>
<?php endforeach ?>

And this controls what’s filtered, with some classes to mark the active item, and one option to show all and reset the filters.

<ul class="filters">

    <li <?php if(empty($tag)): ?>class="active"<?php endif; ?>>
        <a href="<?= $page->url()?>"><div class="icon all"></div>All</a>

    <!-- Tags loop -->
    <?php foreach($tags as $tagItem): ?>
        <li <?php if($tagItem === $tag): ?>class="active"<?php endif; ?>>
            <a href="<?= url($page->url(), ['params' => ['tag' => $tagItem]]) ?>">
                <?= html($tagItem) ?>
    <?php endforeach ?>