Filter pages section by current user

Hi,

I need to filter a pages section to only show pages that have the current user selected in a users field on that page.

I have found this post on the forum:

Is the method shown here (a custom page method) still the best approach?

Thanks!

Does your users field store one or multiple users?

Note that a pages section is not filterable, you need the pagesdisplay plugin

Or a page model, depends on whether the method is needed for one or more page types.

The field stores a single user, and I only need to apply the filter to a single page type. I plan on showing it as part of site.yml, so users can see pages that have been linked to them

The adding the method to a page model instead will be fine. The filter can be shortened a bit using an arrow function

public function getUserPages(string $fieldName)
{
	return $this->children()->filter(fn ($child) => $child->{$fieldName}()?->toUser()?->is(kirby()->user()));
}

This method requires a fieldname as input, but you remove the parameter and hard-code a field name instead.

Thank you @texnixe I will be working on this next week and this is a great starting point

I have got the pagesdisplay plugin installed, and tested it with some of the example queries. All working great.

I am going with a page method, as I will probably need to use this elsewhere. I have this in my blueprint as my section:

primarySchools:
  headline: Primary schools
  type: pagesdisplay
  query: site.currentUser
  status: all
  create: false
  templates: school 
  image: false

And this in site/plugins/page-methods/index.php:

<?php

Kirby::plugin('mhd/page-methods', [
    'pageMethods' => [
        'currentUser' => function () {
          return $this->children()->filter(function($child) {
            return $child->mentor()->toUser() === kirby()->user();
         });
        }
    ]
]);

But am getting the following error:

The section “primarySchools” could not be loaded: Query result must be of type “Kirby\Cms\Pages”, “Kirby\Cms\Field” given

The pages I am filtering are all top level, and I need to do an additional filter on them as well (site.index.filterBy('schoolType', '==', 'primary'), which I have tried and works well), but it would be good to get the user filtering working.

This is in a user-specific blueprint using the method here: Different site blueprint depending on user - if that makes any difference, but I don’t think it would

=======================
UPDATE

I have tried this as my query (the first part works great):

query: site.index.filterBy('schoolType', '==', 'primary').currentUser

And this as the method:

Kirby::plugin('mhd/page-methods', [
    'pageMethods' => [
      'currentUser' => function () {
          return $this->mentor() == kirby()->user();
      }
    ]
]);

But then get this error:

**The section "primarySchools" could not be loaded:** Query result must be of type "Kirby\Cms\Pages", "null" given

You are defining a page method, but calling site.currentuser in your blueprint. A site object is not the same as a page object.

Thanks for the pointer, that makes sense. I think I would like it to be a page method, so it is more reusable.

I have updated my query to be:

query: page.index.filterBy('schoolType', '==', 'primary').currentUser

If I remove the .currentUser I get the pages listed correctly.

My currentUser method is:

Kirby::plugin('mhd/page-methods', [
    'pageMethods' => [
        'currentUser' => function () {
            return $this->mentor()->toUser() === kirby()->user();
        }
    ]
]);

Which throws the error:

The section “primarySchools” could not be loaded: Query result must be of type “Kirby\Cms\Pages”, “null” given

I am at the edge of my understanding with this at the moment, so any help would be great.

This will return a boolean, not a collection.

Here you are trying to run your page method on a pages collection. But for a pages collection, you would need a pages method, not a page method. Please read up about object types and return values (the new docs intro, chapter about return types might be helpful: About the docs | Kirby CMS).

Thank you for your patience, I appreciate it. I have taken a look at your suggested sections of the docs, and understand a bit more about return values (and that I need a pages one in this instance).

I am trying out a new approach to achieve this, using a user model. This was suggested on Discord, and probably makes more sense as I only need to do this for this type of user. I now have the following query:

query: kirby.user.schools

And a new schools.php collection:

return function ($site) {
    return $site->index()->filterBy('template','school');
};

And have set up this user model at plugins/user-models/index.php:

<?php

class MentorUser extends User
{
  public function schools() {
      return kirby.collection('schools').filterBy('schoolType', '==', 'primary').filter(function ($school) {
        return $school->mentor()->toUser() === kirby()->user();
    });
  }
}

Kirby::plugin('users/plugin', [
    'userModels' => [
        'mentor' => 'MentorUser'
    ],
]);

And am getting the error:

The section “primarySchools” could not be loaded: Query result must be of type “Kirby\Cms\Pages”, “Kirby\Cms\Field” given

Having looked at the docs I understand this means that the returned object is not correct. However kirby.collection('schools') should return a pages object, I think?

The problem with this user model approach is that if a user with another role than mentor is logged in, you get this error result, because then the method is not defined. If you want a user method, then use a normal user method, not a user model method.

Note that I’m not following along the discussions on Discord. Official support = forum :grinning:

Absolutely, I was just seeing if I could get some help without bothering you too much!

I have started back with the page method approach as I understand this the best. Method now looks like:

<?php 

Kirby::plugin('mhd/page-methods', [
    'pageMethods' => [
        'currentUser' => function () {
            if($this->mentor()->isNotEmpty()){
              return $this->mentor()->toUser() == kirby()->user();
            }
            else {
              return false;
            }
        }
    ]
]);

As some schools don’t have mentors. The query now looks like:

query: kirby.collection('schools').filterBy('schoolType', '==', 'primary').filterBy('currentUser')

So I can use my page method. Unfortunately it is showing an empty section (‘No pages yet’) but at least I am not getting an error :sweat_smile:. So I think something must be up with my comparison in the middle of the method. Does that sound right?

It doesn’t even work if I hard-code the value for kirby()->user(), like this:

return $this->mentor()->toUser() === 'KP87ZUaa';

Almost, but there is a comparison value missing:

query: kirby.collection('schools').filterBy('schoolType', '==', 'primary').filterBy('currentUser', true)

And you can improve your method a little:

Kirby::plugin('mhd/page-methods', [
    'pageMethods' => [
        'currentUser' => function () {
              // comparing these two values will return either true or false
              return $this->mentor()->toUser() === kirby()->user();
        }
    ]
]);

No need for if else… it doesn’t matter if the field is empty. If it is empty, toUser() will return null and null is not the same as the current user.

Amazing! That is working.

Thanks for your help and patience - miraculously, I actually also understand the solution now.