Adding filter (Tutorial)

Hey there,

I am new to programming and am currently having problems finding a solution to activate multiple filters. I have done the tutorial from Bastian and currently have the following code. However, only the “genre” filter works.

Another problem is, that I get the label as well as the value listed.
Bildschirmfoto 2022-12-09 um 12.39.25

Can anyone help me with this?

You can use the when method, see example here: $pages->when() | Kirby CMS

As for your second question, please post a bit more context, not just that one loop.

And welcome to Kirby and the forum!

One little request: Please post code as code within three backticks before and after the block for easy copy&pasting, not as screenshots. Thanks!

Thank you for the reply!

I tried to use the when method, but the filter still doesn’t work. Any idea what goes wrong?

Also the genre filter doesn’t work with the multiple when method anymore

You are using the same filter all the time and please, no screenshots! I don’t want to type out everything to correct your code. Please look at the example again.

I tried to replace the filters, but still not workling

  $bereich  = get('bereich', ',', true);
  $tatigkeit = get('tatigkeit', ',', true);
  $genre   = get('genre', ',', true);


    $filterBy = get('filter'); /* erzeugt query parameter, damit der filter fuunktioniert */
    $unfiltered = page('projects')
                 ->children()
                 ->listed()
                 ->sortBy('year', 'desc');
    $projects = $unfiltered
                ->when($genre, function($genre) {
                  return $this->filterBy('genre', $genre);
                })
                ->when($tatigkeit, function($tatigkeit) {
                  return $this->filterBy('tatigkeit', $tatigkeit);
                })
                ->when($bereich, function($bereich) {
                  return $this->filterBy('bereich', $bereich);
                })
                ;


    $filtersgenre = $unfiltered->pluck('genre', ',', true);
    $filterstatigkeit = $unfiltered->pluck('tatigkeit', ',', true);
    $filtersbereich = $unfiltered->pluck('bereich', ',', true);

Could you please post both your controller and template in full? Thank you!

<?php
/*
  We always use an if-statement to check if a page exists to
  prevent errors in case the page was deleted or renamed before
  we call a method like `children()` in this case
*/
?>

<?php snippet('header') ?>


<div class="filter-menu" id="filter-menu">
      <nav class="nav-1">
        <ul class="tags">
          <li class="filter-category">
            <a>Genre</a>
          </li>
          <?php foreach ($filtersgenre as $filtergenre): ?>
            <li>
              <a class="tags-each" href="<?= $page->url()?>?filter=<?= $filtergenre ?>"><?= $filtergenre ?></a>
            </li>
          <?php endforeach ?>
        </ul>
      </nav>

      <nav class="nav-2">
        <ul class="tags">
          <li class="filter-category">
            <a>Tätigkeit</a>
          </li>
          <?php foreach ($filterstatigkeit as $filtertatigkeit): ?>
            <li>
              <a class="tags-each" href="<?= $page->url()?>?filter=<?= $filtertatigkeit ?>"><?= $filtertatigkeit ?></a>
            </li>
          <?php endforeach ?>
        </ul>
      </nav>

      <nav class="nav-3">
        <ul class="tags">
          <li class="filter-category">
            <a>Bereich</a>
            <a class="all" href="<?= $page->url()?>?filter=">Alle anzeigen</a>
          </li>

          <?php foreach ($filtersbereich as $filterbereich): ?>
            <li>
              <a class="tags-each" href="<?= $page->url()?>?filter=<?= $filterbereich ?>"><?= $filterbereich ?></a>
            </li>
          <?php endforeach ?>
        </ul>
      </nav>

</div>




<div class="home-list">
      <div class="detailsGroup">

        <?php $key=1; ?>
        <?php $array1=1; ?>
        <?php $array2=1; ?>


        <?php foreach ($projects
                        as $project): ?>


          <div class="linie"></div>

          <details class="list-item" id="project-<?php print($key)?>">

            <summary class="project-info">

                <div class="details-1">
                  <div class="project-info-title"><?= $project->projecttitle()->html() ?></div>
                </div>

                <div class="details-2">
                  <div class="project-info-category"><?= $project->category()->html() ?></div>
                  <div class="project-info-client"><?= $project->client()->html() ?></div>
                  <div class="project-info-year"><?= $project->year()->html() ?></div>
                </div>

                <div class="details-3">
                  <div class="project-info-thumb">
                    <?php if($image = $project->image()): ?>
                    <img src="<?= $image->url() ?>" alt="">
                    <?php endif ?>
                  </div>
                </div>

            </summary>

            <div class="more">
                <div class="more-details-1">

                  <table border="1">

                  <tr>
                  <td >Genre </td>
                  <td>
                    <?php foreach ($project->genre()->split('|') as $genreeinzeln): ?>
                    <?= $genreeinzeln ?> 
                    <?php endforeach ?>
                  </td>
                  </tr>

                  <tr>
                  <td>Tätigkeit </td>
                  <td>
                    <?php foreach ($project->tatigkeit()->split('|') as $tatigkeiteinzeln): ?>
                    <?= $tatigkeiteinzeln ?> 
                    <?php endforeach ?>
                  </td>
                  </tr>

                  <tr>
                  <td>Bereich </td>
                  <td>
                    <?php foreach ($project->bereich()->split('|') as $bereicheinzeln): ?>
                    <?= $bereicheinzeln ?> 
                    <?php endforeach ?>
                  </td>
                  </tr>

                  </table>




                  <p><?= $project->text()->html()->kirbyText() ?></p>
                  <div class="more-credit-info"><?= $project->credits()->html()->kirbyText() ?></div>

                </div>


                <div class="more-details-2">
                      <div class="container">
                        <?php if($image = $project->image()): ?>
                        <img id="mainImage-<?= $project->num() ?>" src="<?= $image->url() ?>" alt="">
                        <?php endif ?>


                        <iframe class="iframe-video" name="iframe-<?= $project->num() ?>" id="iframe-<?= $project->num() ?>" width="1000" height="563" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen ></iframe>


                      </div>

                </div>

                <div class="more-details-3">
                  <div class="row">

                    <div class="column" onmouseover="changeImage<?= $project->num() ?>(event)">
                        <?php foreach($project->images() as $image): ?>

                          <div class="column-thumb">
                            <img src="<?= $image->url() ?>" data-src="<?= $image->url() ?>">

                            <?php echo '<script type="text/javascript">',
                                        'function changeImage'.$project->num().'(event) {',
                                          'event = event || window.event;',
                                          'var targetElement = event.target || event.srcElement;',
                                          'if (targetElement.tagName == "IMG") {',
                                            'document.getElementById("mainImage-'.$project->num().'").src = targetElement.getAttribute("data-src");',
                                          '}',
                                          '}',
                                        '</script>';
                                        ?>
                          </div>
                        <?php endforeach ?>



                        <?php if ($video = $project->vimeolinks()): ?>
                          <?php foreach($project->vimeolinks()->toStructure() as $vimeovid): ?>

                            <?php echo $vimeovid->oembed([
                               'lazyvideo' => true,
                               'autoload' => true,
                               'thumb' => '',
                             ]); ?>

                            <?php $videoID = $vimeovid->vimeovid();?>

                              <div class="column-thumb">
                                <a onmouseover="click();openiframe();" onmousedown="closeiframe();click();" href="https://player.vimeo.com/video/<?= $videoID ?>?autoplay=1&loop=1&title=0&byline=0&portrait=0" target="iframe-<?= $project->num() ?>" >
                                  <img id="videothumb" src="https://vumbnail.com/<?= $videoID ?>.jpg" alt=""></img>
                                </a>
                                <?php echo '<script type="text/javascript">',
                                            'function changeImage'.$project->num().'(event) {',
                                              'event = event || window.event;',
                                              'var targetElement = event.target || event.srcElement;',
                                              'if (targetElement.tagName == "IMG") {',
                                                'document.getElementById("mainImage-'.$project->num().'").src = targetElement.getAttribute("data-src");',
                                              '}',
                                              '}',
                                            '</script>';
                                            ?>
                              </div>
                          <?php endforeach ?>



                        <?php endif ?>
                    </div>

                  </div>
                </div>


            </div>
          </details>


          <?= js(['assets/js/popup.js', '@auto']) ?>


        <?php $key=$key+1; ?>
        <?php $array1=$array1+1; ?>
        <?php $array2=$array2+1; ?>
        <?php endforeach ?>


      </div>
</div>

<?php

return function () {

  $bereich  = get('bereich', ',', true);
  $tatigkeit = get('tatigkeit', ',', true);
  $genre   = get('genre', ',', true);


    $filterBy = get('filter'); /* erzeugt query parameter, damit der filter fuunktioniert */
    $unfiltered = page('projects')
                 ->children()
                 ->listed()
                 ->sortBy('year', 'desc');
    $projects = $unfiltered
                ->when($filterBy, function($filterBy) {
                  return $this->filterBy('genre', $filterBy, ',');
                })
                ;
/*
                $projects = $unfiltered
                            ->when($genre, function($genre) {
                              return $this->filterBy('genre', $genre);
                            })
                            ->when($tatigkeit, function($tatigkeit) {
                              return $this->filterBy('tatigkeit', $tatigkeit);
                            })
                            ->when($bereich, function($bereich) {
                              return $this->filterBy('bereich', $bereich);
                            })
                            ;*/

    $filtersgenre = $unfiltered->pluck('genre', ',', true);
    $filterstatigkeit = $unfiltered->pluck('tatigkeit', ',', true);
    $filtersbereich = $unfiltered->pluck('bereich', ',', true);





  return [
    'bereich' => $bereich,
    'tatigkeit' => $tatigkeit,
    'genre' => $genre,

    'filterBy' => $filterBy,
    'unfiltered' => $unfiltered,
    'projects' => $projects,
    'filtersbereich' => $filtersbereich,
    'filtersgenre' => $filtersgenre,
    'filterstatigkeit' => $filterstatigkeit
  ];

};

The problem is in these lines, you always use the filter query, when it should be genre, tatigkeit or bereich, depending on what you want to filter by. The filterBy variable is redundant in your controller.

And then you need to use that in the combination with the commented code in your controller.

So for example for the activities:

<?php foreach ($filterstatigkeit as $filtertatigkeit): ?>
    <li>
        <a class="tags-each" href="<?= $page->url()?>?tatigkeit=<?= $filtertatigkeit ?>"><?= $filtertatigkeit ?></a>
    </li>
<?php endforeach ?>

Oh, and this

must be

$bereich  = get('bereich');
$tatigkeit = get('tatigkeit');
$genre   = get('genre');

get() gets the url query by name.

Note that if you want to filter by multiple filters at the same time (i.e. genre=“politics” AND bereich=abc), you would have to either adapt your links or better use a form.

Thank you!
Unfortunatly it’s still not working with this changes. Here is the code again. Am I missing something?

<?php
/*
  We always use an if-statement to check if a page exists to
  prevent errors in case the page was deleted or renamed before
  we call a method like `children()` in this case
*/
?>

<?php snippet('header') ?>


<div class="filter-menu" id="filter-menu">
      <nav class="nav-1">
        <ul class="tags">
          <li class="filter-category">
            <a>Genre</a>
          </li>
          <?php foreach ($filtersgenre as $filtergenre): ?>
            <li>
              <a class="tags-each" href="<?= $page->url()?>?genre=<?= $filtergenre ?>"><?= $filtergenre ?></a>
            </li>
          <?php endforeach ?>
        </ul>
      </nav>

      <nav class="nav-2">
        <ul class="tags">
          <li class="filter-category">
            <a>Tätigkeit</a>
          </li>
          <?php foreach ($filterstatigkeit as $filtertatigkeit): ?>
              <li>
                  <a class="tags-each" href="<?= $page->url()?>?tatigkeit=<?= $filtertatigkeit ?>"><?= $filtertatigkeit ?></a>
              </li>
          <?php endforeach ?>
        </ul>
      </nav>

      <nav class="nav-3">
        <ul class="tags">
          <li class="filter-category">
            <a>Bereich</a>
            <a class="all" href="<?= $page->url()?>?bereich=">Alle anzeigen</a>
          </li>

          <?php foreach ($filtersbereich as $filterbereich): ?>
            <li>
              <a class="tags-each" href="<?= $page->url()?>?bereich=<?= $filterbereich ?>"><?= $filterbereich ?></a>
            </li>
          <?php endforeach ?>
        </ul>
      </nav>

</div>




<div class="home-list">
      <div class="detailsGroup">

        <?php $key=1; ?>
        <?php $array1=1; ?>
        <?php $array2=1; ?>


        <?php foreach ($projects
                        as $project): ?>


          <div class="linie"></div>

          <details class="list-item" id="project-<?php print($key)?>">

            <summary class="project-info">

                <div class="details-1">
                  <div class="project-info-title"><?= $project->projecttitle()->html() ?></div>
                </div>

                <div class="details-2">
                  <div class="project-info-category"><?= $project->category()->html() ?></div>
                  <div class="project-info-client"><?= $project->client()->html() ?></div>
                  <div class="project-info-year"><?= $project->year()->html() ?></div>
                </div>

                <div class="details-3">
                  <div class="project-info-thumb">
                    <?php if($image = $project->image()): ?>
                    <img src="<?= $image->url() ?>" alt="">
                    <?php endif ?>
                  </div>
                </div>

            </summary>

            <div class="more">
                <div class="more-details-1">

                  <table border="1">

                  <tr>
                  <td >Genre </td>
                  <td>
                    <?php foreach ($project->genre()->split('|') as $genreeinzeln): ?>
                    <?= $genreeinzeln ?> 
                    <?php endforeach ?>
                  </td>
                  </tr>

                  <tr>
                  <td>Tätigkeit </td>
                  <td>
                    <?php foreach ($project->tatigkeit()->split('|') as $tatigkeiteinzeln): ?>
                    <?= $tatigkeiteinzeln ?> 
                    <?php endforeach ?>
                  </td>
                  </tr>

                  <tr>
                  <td>Bereich </td>
                  <td>
                    <?php foreach ($project->bereich()->split('|') as $bereicheinzeln): ?>
                    <?= $bereicheinzeln ?> 
                    <?php endforeach ?>
                  </td>
                  </tr>

                  </table>




                  <p><?= $project->text()->html()->kirbyText() ?></p>
                  <div class="more-credit-info"><?= $project->credits()->html()->kirbyText() ?></div>

                </div>


                <div class="more-details-2">
                      <div class="container">
                        <?php if($image = $project->image()): ?>
                        <img id="mainImage-<?= $project->num() ?>" src="<?= $image->url() ?>" alt="">
                        <?php endif ?>


                        <iframe class="iframe-video" name="iframe-<?= $project->num() ?>" id="iframe-<?= $project->num() ?>" width="1000" height="563" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen ></iframe>


                      </div>

                </div>

                <div class="more-details-3">
                  <div class="row">

                    <div class="column" onmouseover="changeImage<?= $project->num() ?>(event)">
                        <?php foreach($project->images() as $image): ?>

                          <div class="column-thumb">
                            <img src="<?= $image->url() ?>" data-src="<?= $image->url() ?>">

                            <?php echo '<script type="text/javascript">',
                                        'function changeImage'.$project->num().'(event) {',
                                          'event = event || window.event;',
                                          'var targetElement = event.target || event.srcElement;',
                                          'if (targetElement.tagName == "IMG") {',
                                            'document.getElementById("mainImage-'.$project->num().'").src = targetElement.getAttribute("data-src");',
                                          '}',
                                          '}',
                                        '</script>';
                                        ?>
                          </div>
                        <?php endforeach ?>



                        <?php if ($video = $project->vimeolinks()): ?>
                          <?php foreach($project->vimeolinks()->toStructure() as $vimeovid): ?>

                            <?php echo $vimeovid->oembed([
                               'lazyvideo' => true,
                               'autoload' => true,
                               'thumb' => '',
                             ]); ?>

                            <?php $videoID = $vimeovid->vimeovid();?>

                              <div class="column-thumb">
                                <a onmouseover="click();openiframe();" onmousedown="closeiframe();click();" href="https://player.vimeo.com/video/<?= $videoID ?>?autoplay=1&loop=1&title=0&byline=0&portrait=0" target="iframe-<?= $project->num() ?>" >
                                  <img id="videothumb" src="https://vumbnail.com/<?= $videoID ?>.jpg" alt=""></img>
                                </a>
                                <?php echo '<script type="text/javascript">',
                                            'function changeImage'.$project->num().'(event) {',
                                              'event = event || window.event;',
                                              'var targetElement = event.target || event.srcElement;',
                                              'if (targetElement.tagName == "IMG") {',
                                                'document.getElementById("mainImage-'.$project->num().'").src = targetElement.getAttribute("data-src");',
                                              '}',
                                              '}',
                                            '</script>';
                                            ?>
                              </div>
                          <?php endforeach ?>



                        <?php endif ?>
                    </div>

                  </div>
                </div>


            </div>
          </details>


          <?= js(['assets/js/popup.js', '@auto']) ?>


        <?php $key=$key+1; ?>
        <?php $array1=$array1+1; ?>
        <?php $array2=$array2+1; ?>
        <?php endforeach ?>


      </div>
</div>

<?php

return function () {

  $bereich  = get('bereich');
  $tatigkeit = get('tatigkeit');
  $genre   = get('genre');


    $unfiltered = page('projects')
                 ->children()
                 ->listed()
                 ->sortBy('year', 'desc');
/*    $projects = $unfiltered
                ->when($filterBy, function($filterBy) {
                  return $this->filterBy('genre', $filterBy, ',');
                })
                ;*/

      $projects = $unfiltered
                  ->when($genre, function($genre) {
                    return $this->filterBy('genre', $genre);
                  })
                  ->when($tatigkeit, function($tatigkeit) {
                    return $this->filterBy('tatigkeit', $tatigkeit);
                  })
                  ->when($bereich, function($bereich) {
                    return $this->filterBy('bereich', $bereich);
                  })
                  ;

    $filtersgenre = $unfiltered->pluck('genre', ',', true);
    $filterstatigkeit = $unfiltered->pluck('tatigkeit', ',', true);
    $filtersbereich = $unfiltered->pluck('bereich', ',', true);





  return [
    'bereich' => $bereich,
    'tatigkeit' => $tatigkeit,
    'genre' => $genre,

    'unfiltered' => $unfiltered,
    'projects' => $projects,
    'filtersbereich' => $filtersbereich,
    'filtersgenre' => $filtersgenre,
    'filterstatigkeit' => $filterstatigkeit
  ];

};

What exactly is not working?

Oh, and why are you splitting by pipe here?

$project->tatigkeit()->split('|')

The filters don’t function. I don’t get any results. The url is changing, but no projects are shown.

Also some of the given tags (filtersgenre, filterstatigkeit, filtersbereich) are now missing in the filter-menu

The separator is missing as third argument, should be

     ->when($genre, function ($genre) {
            return $this->filterBy('genre', $genre, ',');
        });

in all instances.

Amazing!! It works!! Thanks a lot for your help :slightly_smiling_face:

1 Like