Filtering from different tags

Hello,

I’ve created a table to display a list of books: each book has several tags from different fields (publishers, authors, designers, etc.).


I want to use these filters to display books by selecting a tag. I’ve created a line to display the tags by type. I’ve tried several filter tutorials (by route, filter by multiple fields), but none of them work. Do you have any advice?

My code :

<thead>
    <tr id="filters">
        <?php
        
        $filters = ['','place', 'publisher', 'year', '', '', 'categorie', '', 'authors', 'designer', 'tools', '', '', '', ''];
        $tags = [];
        // Pluck tags for each filter and merge them into the $tags array
        foreach ($filters as $filter) {
            $tags[$filter] = array_unique($page->children()->listed()->pluck($filter, ',', true));
            sort($tags[$filter]); // Sort each filter's tags alphabetically
        }
        // Iterate over each filter and output tags in their own <td>
        foreach ($filters as $filter): ?>
        <td>
            <ul>
            <?php foreach ($tags[$filter] as $tag): ?>
                <li id='<?= 'filter-'.$filter?>'><a href="<?= url('collection', ['params' => ['filter' => $tag]]) ?>">
                <?= html($tag) ?></a></li>
            <?php endforeach ?>
            </ul>
        </td>
        <?php endforeach ?>
    </tr>
</thead>
<tbody class="list">
    <?php  
        $filters = get('filter');
        $place = get('place');
        $publisher = get('publisher');
        
        $books = page()
            ->children()
            ->listed();
        
        $booksPlace = $books->pluck('place', ',', true);
        $booksPublisher = $books->pluck('publisher', ',', true);

        $books=$books
            ->when($filter, function($filter){
                return $this->filterBy('place', $filter);
            })
            ->when($filter, function($filter){
                return $this->filter('place', $filter);
            });

        foreach($books->sortBy('year', 'desc') as $book): ?>
    <tr>
        <td class="title"><?= $book->title()->isNotEmpty() ? $book->title() : "—" ?></td>
        <?php foreach ($fields as $field_name): ?>
            <td class="<?= $field_name ?>"><?= $book->$field_name()->isNotEmpty() ? $book->$field_name() : "—" ?></td>
        <?php endforeach; ?>
        <td class="medias">
            <div class="gallery">
                <?php foreach($book->images() as $file): ?>
                    <figure>
                        <img src="<?= $file->url() ?>" srcset="<?= $file->srcset() ?>">
                    </figure>
                <?php endforeach; ?>
            </div>
        </td>
    </tr>
    <?php endforeach; ?>
</tbody>

If I understand correctly, no matter what you want to filter by, the param is always filter. So how are you supposed to know what to filter by? If you want to filter by place, the param name must be place etc.

My filters come from different field (place, publisher, etc.) And I want to use a filter from place or publisher or other to display page. I’ve tried to callback my array $filters on line 5 to filter by this, but it seems filterBy() don’t take array for fieldname.

$filters = ['','place', 'publisher', 'year', '', '', 'categorie', '', 'authors', 'designer', 'tools', '', '', '', ''];

$filterBy = get('filter');

$books = page()
                ->children()
                ->listed()
                ->when($filterBy, function($filterBy){
                    return $this->filterBy($filters, $filterBy);
                }); 

You need to filter by each type separately, you cannot pass an array.

Am I in the good direction by doing this ? Because it’s not working

No, this must be

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

etc for all other categories you want to filter by, see the when example: $pages->when() | Kirby CMS

And of course, you need to set the parameters accordingly, so place:someplaceetc.

On a side note, get('place') returns an item from a url query string (https://mydomain.test/?place=someplace), whereas if you use params (https://mydomain.test/place:someplace), you need to get them with param('place')

I’ve got a proble it’s seems some of tags not working, specially when a category took multiple tags. Example, if authors contain more than one author and I click one one author it display a blank page…

I found solution by using filter() rather than filterBy()

books = $books
                ->filter(function ($book) use ($place, $publisher, $bookYear, $category, $bookAuthors, $bookDesigner, $bookTools) {
                    // Filter by place
                    if ($place && $book->place()->value() != $place) {
                        return false;
                    }
                    
                    // Filter by publisher
                    if ($publisher && $book->publisher()->value() != $publisher) {
                        return false;
                    }
                    ...
                    return true;
                });