Reverse query for related pages

Hello,

I am quite new with Kirby. I am trying to use “Page relations” but i am stuck with some functionality.

Let say I have a page called actors with all the actors as subpages and I have a page Films with all the films as subpages. To make relations I create a field “pages” on the films page. That way I can select which actors participate on the film and I can select more than one. On the film page template I can so all the name of the actors and link to their pages, no problem.

The field is defined like:

  actors:
    label: Actors
    type: pages
    translate: false
    query: site.find("actors").children

I can show them on the film template like:

    <?php foreach( $page->actors()->toPages() as $ar ): ?>
    <a href="<?=  $ar->url() ?>"><?= $ar->title()->html() ?></a>
    <?php endforeach ?>

Now I want to show them on the Actor Page. I tried to used pages->filterBy

    <?php foreach( $pages->find('films')->children()->filterBy('Actors',$page->id() )  as $film ): ?>
    	<a href="<?= $film ->url() ?>"><?= $film ->title()->html() ?></a>
    <?php endforeach ?>

But it doesn’t find the correct relation when there is more than one actor. It is logic as the “actor field” is not equal to the page id it contains more than one.

How could I filter it? Should I use another kind of field?

Thanks a lot!!

I guess you would need to use the ->filter() method with a callback. The content file of a film could look something like this:

Actors:

- robert-de-niro
- marlon-brando
- jennifer-lawrence

So using filterBy() will never be true as it’s a yaml list.

Untested, but something like this should work:

<?php
$films = $pages->find('films')->children()->filter(function($film) use ($page) {
  return $film->actors()->toPages()->has($page);
});
foreach($films as $film):
?>
  <?= $film->title()->html() ?>
<?php endforeach ?>
1 Like

Thank you for the quick respond!! . I actually continued trying and I got it working with filterBy by using the ‘*=’, method. Something like:

<?php foreach( $pages->find('films')->children()->filterBy('Actors',**'*=',**$page->id() )  as $co ): ?>
	<a href="<?= $co->url() ?>"><?= $co->title()->html() ?></a>
<?php endforeach ?>

It seems to work fine. I will give also a try at your solution. It is a good way of understanding how everything with Kirby work. Thanks a lot!

The *= (contains) method might not be the best approach because it can lead to false results. Using filter($callback) is the right approach, but the above snippet is missing the $page variable and should be:

$films = $pages->find('films')->children()->filter(function($film) use ($page) {
  return $film->actors()->toPages()->has($page);
});
1 Like

You’re right! I just edited my answer to prevent confusion in the future.

1 Like

Ok, I will do that then . Indeed it can produce some mistakes with pages with similar names.

The only thing I changed fron your code was use ($page) instead if (use $page)

Great to see the community works!! I am enjoying developing with kirby. thanks

2 Likes