Filter images by tags of parent page

My page structure looks like this:

Home

Archive

  • Post 1
  • Post 2
  • Post 3

There are several images on each post. All post pages have multiple tags assigned to them.

The archive page shows an overview of all posts with links to the respective post page. A tag cloud on the archive page can be used to filter the displayed posts. For this I used the recipe “Filter collections by tags” from the cookbook, works great.

On the home page thumbnails of all images of all post pages from the archive are displayed. Now I would like to make this overview on the home page also filterable with a tag cloud just like the archive page. Therefore the individual images would have to be assigned the tags of the post from which they originate. I assume.

And again that’s the point where I fail miserably, due to lack of PHP knowledge.

How should the controller for the home page look like?
Thanks in advance for your support!

Please post how you are fetching the images (template, controller) on the homepage.

Basically, each of your files has the page it originates from a parent. So you can filter those images by the properties of this parent.

Currently I’m fetching the images like this:

 <?php if ($archive = page('archive')) : ?>

      <?php foreach ($archive->children()->images()->flip() as $image) : ?>

        <li style="--columns: 1">
          <a href="<?= $image->url() ?>" data-lightbox>
            <figure>
              <span class="img" style="--w:2;--h:2">
                <img loading="lazy" alt="<?= $image->page()->title() ?>" title="<?= $image->page()->title() ?>" src="<?= $image->resize(200)->url() ?>" srcset="<?= $image->srcset() ?>" sizes="
                                                  (min-width: 900px) 5vw,
                                                  (min-width: 600px) 3vw,
                                                  10vw">
              </span>
            </figure>
          </a>
        </li>

      <?php endforeach ?>

    <?php endif ?>

If another solution makes more sense or can be combined better with the tag cloud, I am open for suggestions.

Something like this should work:

<?php

return function($page) {
    $archivePages = page('archive')->children()->listed();
    $tags         = $archivePages->pluck('tags', ',', true);
    $images       = $archivePages->images()->flip();

    if ($tag = param('tag')) {
        $images = $images->filter(fn ($image) => in_array($tag,  $image->parent()->tags()->split()));
    }

    return [
        'archivePages' => $archivePages,
        'tags' => $tags,
        'images' => $images,
    ];
};

It… kind of works…?

I don’t get any errors, I can select tags in the tagcloud, the tag is added to the URL - but the content is not filtered after the page load. And the pagination I tried to add doesn’t work. No matter if a tag is selected, all images are always displayed.

I tried to add the pagination to the controller you suggested which led me to this:

<?php

return function($page) {
    $archivePages = page('archive')->children()->listed();
    $tags         = $archivePages->pluck('tags', ',', true);
    $images       = $archivePages->images()->flip();

    if ($tag = param('tag')) {
        $images = $images->filter(fn ($image) => in_array($tag,  $image->parent()->tags()->split()));
    }

    $images   = $images->paginate(10);
    $pagination = $images->pagination();

    return [
        'archivePages' => $archivePages,
        'tags' => $tags,
        'images' => $images,
        'pagination' => $pagination,
    ];
};

This is how I generate the tagcloud:

<?php foreach ($tags as $tag) : ?>
      <li>
        <a title="<?= html($tag) ?>" href="<?= url($page->url(), ['params' => ['tag' => $tag]]) ?>" <?php e($tag === param('tag'), 'class="tag-active"', '')  ?>>
          <?= html($tag) ?>
        </a>
      </li>
    <?php endforeach ?>

And the images on the home page are still fetched like shown above, nothing has been changed here.

The code should filter fine, unless you didn’t replace this line

with

<?php foreach ($images as $image) : ?>

If we define variables in the controller, we must not override them in the template.

Oh well, time to go to bed… thank you so much again, it works perfectly fine now!

One last question (for now…):

To reset the filter, I use a prepended manually generated “all” tag:

<ul>
    <li class="tag-all"><a title="Alle" href="<?= $page->url() ?>" <?php e($tags === param('null'), 'class="tag-active"', '') ?>>Alle</a></li>
    <?php foreach ($tags as $tag) : ?>
      <li>
        <a title="<?= html($tag) ?>" href="<?= url($page->url(), ['params' => ['tag' => $tag]]) ?>" <?php e($tag === param('tag'), 'class="tag-active"', '')  ?>>
          <?= html($tag) ?>
        </a>
      </li>
    <?php endforeach ?>
  </ul>

If no tag is selected, this “all” tag should be assigned the class “tag-active”. This worked on the archive page, but doesn’t work on the home page. What do I need to adjust to make it work again? Or is there a better solution?

That doesn’t make sense, the param is still filter

e(is_null(param('filter')), ...)

Thanks for your answer. You meant the param is tag, not filter - right?

<?php e(is_null(param('tag')), 'class="tag-active"', '') ?>

With this little change it works perfectly fine.

Oh, yes, sorry, was mentally still in another thread…

No problem at all. The fact that I get such good support here at two in the morning is absolutely impressive. So it’s totally okay if I have to do some thinking myself :wink: