Tag filtering URL still displaying all albums

So I have created tag filtering (in it’s simplest form) and I am getting the correct URLS (I believe) but when I visit one of those URLs I still just get the full list of things. I am obviously expecting just a list that contains only that one tag, not all of them.

Controller

<?php

return function ($page) {
    $gallery = $page->images()->sortBy("sort");
    $tags = $page->tags();

    if($tag = param('tag')) {
        $tags = $page->filterBy('tags', $tag, ',');
    }

    return [
        'gallery' => $gallery,
        'tag' => $tag,
        'tags' => $tags
    ];
};

Template

<?php if ($tags->isNotEmpty()): ?>
    <?php foreach($tags->split() as $tag): ?>
        <a href="<?= url('photography', ['params' => ['tag' => urlencode($tag)]]) ?>">
            <p><?= $tag ?></p>
        </a>
    <?php endforeach ?>
<?php endif ?>

Returning

http://localhost:8888/plainkit/photography/tag:fiat

So from this I am getting the correct URL (I think) - but why is the display of this URL still show all albums and not just the ones containing the tag fiat?

You cannot filter a single page, you probably want to filter the children:

<?php

return function ($page) {
    $albums = $page->children()->listed();
    $gallery = $page->images()->sortBy("sort");
    $tags = $page->tags();

    if($tag = param('tag')) {
        $albums = $albums->filterBy('tags', $tag, ',');
    }

    return [
        'gallery' => $gallery,
        'tag' => $tag,
        'tags' => $tags,
        'albums' => $albums
    ];
};

Then in your template

<?php foreach ($albums as $album): ?>
<!-- your code here -->
<?php endforeach ?>
1 Like

Ah, OK. I guess I will need to move the controller up a level to the albums list rather than the individual album. Thanks for pointing me in the right direction.

Yep!

Quick question - how would I link from the individual album then?

With the code you already posted above, but a bit modified:

<?php  $tags = $page->tags()->split(','); ?>
<?php if (count($tags)): ?>
    <?php foreach($tags as $tag): ?>
        <a href="<?= url('photography', ['params' => ['tag' => urlencode($tag)]]) ?>">
            <p><?= $tag ?></p>
        </a>
    <?php endforeach ?>
<?php endif ?>

And if you urlencode(), you have to urldecode() again in the controller.

if($tag = urldecode(param('tag'))) {

Last one, can you point me in the right direction to always show all tags. Currently going to tag:books for example, will only show the tags that those articles have and not all of them.

All Tags = Books, Life, Colors

tag:books = Books, Life
tag:colors = Life, Colors

This will fetch all unique tags of all children into an array:

$tags = $page->children()->listed()->pluck('tags', ',', true);

Yeah, I already have that which is why I asked.

I can’t point to parent because blog is the parent of all blog articles.

This is now the updated code

<?php

return function ($page) {
    $notes = $page->children()->listed();
    $tagurl = $page->url();

    if($tag = urldecode(param('tag'))) {
        $notes = $notes->filterBy('tags', $tag, ',');
    }

    $tags = $notes->pluck('tags', ',', true);

    sort($tags);

    return [
        'notes' => $notes,
        'tags' => $tags,
        'tagurl' => $tagurl
    ];
};

Then this is the template

    <ul class="c-tags">
        <li class="c-tags__item"><a href="<?= $page->url() ?>" class="c-tags__link">All</a></li>
        <?php foreach ($tags as $tag): ?>
            <li class="c-tags__item">
                <a href="<?= url($tagurl, ['params' => ['tag' => urlencode($tag)]]) ?>" class="c-tags__link">
                    <?= $tag ?>
                </a>
            </li>
        <?php endforeach ?>
    </ul>

Hm, maybe I’m missing something, but if you place your $tags definition after the filter code, you will only get the filtered tags when the URL contains a parameter, not all tags. If you want to always have all tags, the order should be like this:

    $notes = $page->children()->listed();
    $tags = $notes->pluck('tags', ',', true);

    $tagurl = $page->url();

    if($tag = urldecode(param('tag'))) {
        $notes = $notes->filterBy('tags', $tag, ',');
    }

1 Like

Ah I see. OK. Many thanks.