How to create dynamic filters

Hey guys,

in the docs I learned how to use filters, but I didn’t understand how to use them in my specific case. I have an online shop with products by different artists. Then I have subpages of all artists with information about them. This artist page should now show all products (subpages) from this artist. In the blueprints of product and artist pages, I set up a field for an artist id. In this case simply the full name of the artist (like johndoe).

My artist template needs a filter which is created by himself on every artist subpage. I can do the following:

$collection = page('projects')
  ->filterBy('artistid', 'johndoe');

But in this case on every artist page there would be the work of John Doe. Is it possible that Kirby puts in the correct artist id matching to the specific artist? So it lists all subpages with the same artist id? Or is there another way to do this in Kirby?

I hope you can understand what I mean :smiley:

You can pass an artist as argument to your filter. Usually, you will probably filter by an URL parameter, then you’d get your parameter and pass that in instead of the hardcoded johndoe.

You can find an example in this cookbook recipe:

I tried this, but it did not work:

<div class="products">
    <?php if ($page = page('home')): ?>
    <?php foreach ($page->children()
                      	->filterBy('artistid', param('artistid')) as $product); ?>

      <div class="product-box">
        <a href="<?= $product->url() ?>">
          <div class="product-thumb"><?= $product->image() ?></div>
          <?= $product->name() ?><br>
          <?= $product->price() ?>€

    <?php endforeach ?>
    <?php endif ?>

Do you actually call your page with a parameter in the URL? If not, the filter doesn’t make sense. I’m not sure about your context here…

Sorry, I hove no idea how PHP works :sweat_smile: I love Kirby because I can build websites without knowing much about PHP, but when I need some deeper functions I have to ask.

First I don’t know what I should do with the first code window. echo param('tag'); Is this an example to show how it works, or do I have to put this line somewhere in my code, if yes, where?

Then can I use my code like as above?

And at which point do I have to put the third code example from the doc. Can I replace all the tags and $tag codes with artistid and $artistid? Sometimes I don’t know which tag/variable is from kirby and which one can I name how I want :woozy_face:

I am not sure if filtering by URL is that what I need right now.

This works as expected, but I need something dynamic.
<?php foreach ($page->children()->filterBy('artistid', '==', 'johndoe' as $product): ?>

I want something like this, but this isn’t working. Can you explain why?
<?php foreach ($page->children()->filterBy('artistid', '==', $page->artistid()) as $product): ?>

$page->artistid() text field contains exactly johndoe

Well, yes, but you want to filter the children, not the current page.

What I don’t really get is where the information to filter by (the author) is supposed to come from.

Could you please

  1. post your directory structure
  2. indicate, in which template you want to filter
  3. tell us, where the argument to filter by is supposed to come from

1. File structure

– Product 1
– Product 2
– Product 3
– ...

– Artist 1
– Artist 2
– Artist 3
– ...

2. Which template

I want the filter in the template of an artist page. It should show all products by the specific artist. The artist page shows some facts about the artist like bio and last exhibitions and underneath the products. So the user doesn’t have to apply the filter via a link or something. It should load with the page.

3. Argument

In each product page blueprint is a text field which I called artistid. The same artistid text field is in the artist blueprint. So, all products by John Doe have an artistid johndoe and the artist page about John Doe has also the same artist id. I thought, this could be the way how the filter knows on which page it is and which products it has to filter.
This is why I wrote: filterBy('artistid', '==', $page->artistid())

I hope you get me know, because I can’t explain better :sweat_smile:

Ah! Now we are getting somewhere :slightly_smiling_face:.

$artistProducts = page('shop')->children()->filterBy('artistid', $page->artistid()->value());

Adding the artistid manually in two places in a text field is not what I’d do, though.

You can use a pages field instead in the product page blueprint where you query the artists instead. It will then store the artist page id in the content file and you can use that to filter by.

Okay thank you, the pages field (i called it related) is definitely a better option than a text field.

Product content file contains now:


- artists/john-doe

Never the less I don’t know how to write the filter line.

<?php if ($page = page('home')): ?>
<?php foreach ($page->children()->filterBy( ? ) as $product): ?>

This should work:

$products = page('home')->children()->listed()->filterBy('related', '==', $page->id(), '-');
foreach ($products as $product): ?>
<?php endforeach ?>

If not:

$products = page('home')->children()->listed()->filter(function($child) use($page) {
  return $child->related()->toPage() === $page;
foreach ($products as $product): ?>
<?php endforeach ?>

listed() is optional…

The second one works. Thank you!