Advance queries in blueprints

I have a list of roles I would like to show in a select field. The problem is I want to only show roles that have results above a certain number. How would i do this inside a blueprint file?

Hers the code

query: site.find("interviews").children.pluck("role", ",", true)

What is that supposed to mean?

OK so each post can have two tags, but rather than listing all tags I only want to list the tags that appear in posts over a certain number of time. Only show this tag if when used as a filter will show more than 5 results.

You can’t do this in a blueprint query but have to create a custom method.

Ah I thought as much, are there any guides out there I can follow?

There are docs about how to create custom methods, in this case probably a page method: Page methods | Kirby CMS

As for the actual logic, there is of course no guide. But I think if you search a bit, you will find something here on the forum you can build on.

Some context:

I’m building an interview website and on the homepage I want to give admins the ability to choose a filter based on location or role of the interviewee.

The data would then be piped into a section that shows 5 interviews from the chosen filter.

The problem I am now facing is that some locations and roles only have 1 or 2 interviews. I want to exclude the roles and locations from the dropdown in the Panel that would show less than 5 results.

I’ve been able to create Page Methods that make it easy to access the locations and roles but now I want to filter them down to only show roles that will output 5 or more results.

Could you please post your current method(s)?

So these are the three I created for location

<?php
Kirby::plugin('my/page-methods', [
  'pageMethods' => [
    'city' => function () {
      $location = $this->mymap()->toLocation();
      $cityname = $location->city();
      if($location->has('city')) {
        if($location->city()->isNotEmpty()) {
          return $cityname;
        }
        else {}
        }
      else {}
    },
    'country' => function () {
      $location = $this->mymap()->toLocation();
      $countryname = $location->country();
      if($location->has('country')) {
        if($location->country()->isNotEmpty()) {
          return $countryname;
        }
        else {}
        }
      else {}
    },
    'location' => function () {
      $location = $this->mymap()->toLocation();
      $cityname = $location->city();
      $countryname = $location->country();
      if($location->has('city')) {
        if($location->city()->isNotEmpty()) {
          return $cityname . ', ' . $countryname;
        }
        else {}
        }
      else {}
    }
  ]
]);

I then use them like this

query: site.find("interviews").children.pluck("location", ";", true)

FYI I’m using this plugin https://github.com/sylvainjule/kirby-locator

That’s not as straightforward as expected, because in this case, your pages do not even contains the saved string.

So basically you would have to create either a new method, or inside this method, a way to filter the locations by separating that string again into city and country and check which of the pages has both values in the yaml array.

You could fetch your locations from a collection. Doesn’t create much overhead but gives you the full power of php.

Haven’t tested it, but I think this could work

/site/collections/cities.php:

<?php
return function ($site) {
    return $site
      ->find('interviews')
      ->children()
      ->groupBy('location') //create a collection of collections
      ->filterBy('count', '>=', 5) //use only those that have at least 5 pages
      ->map(function($collection) {
        //map each collection to the location of it's first page (it doesn't 
        //actually matter which page, they all have the same location)
        return $collection->first()->location();
      })
};

blueprint query:
query: kirby.collection("cities")

And here’s some info on collections:

2 Likes

Hey, thanks so much for chiming in. So I played around with this but ran into a few issues.

  1. I don’t think the groupBy would work as ‘location’ isn’t actually a field. mymap is a structure field. I created a page method to pull out the location (city & country). What would be the way around this?

     Mymap:
     lat: 42.3602534
     lon: -71.0582912
     city: Boston
     country: United States of America
     ----
    
  2. I tested this with the role as this is a field that is available. The query seems to work but I get this error. It looks like it wants me to define the text and value bit I don’t know what to place there.

Any ideas?

query: 
    fetch: kirby.collection("cities")
    value: ?
    text: ?

Should definitely work, the groupBy function doesn’t distinguish between “real fields” and page methods (or any method for that matter). You just have to make sure every page you want to group has data in the myMap field, otherwise your “location” method returns null, and that can’t be used as a group key.

It’s just kirby being weird: it seems like, for the panel, the query result can’t be a Collection of strings (which is what we get out of our “map” call). On the other hand it definitely accepts an array of strings. So instead of calling “map”, we need to call “toArray”.

Here’s the function:

<?php

return function ($site) {
    return $site
      ->find('interviews')
      ->children()
      ->filterBy('location', '!=', null) //NEW: consider only pages with locations
      ->groupBy('location') //create a collection of collections
      ->filterBy('count', '>=', 5) //use only those that have at least 5 pages
      ->toArray(function($collection) { //NEW: toArray, not map
        //map each collection to the location of it's first page (it doesn't 
        //actually matter which page, they all have the same location)
        return $collection->first()->location();
      });
};

This worked!

Thanks so much!

I did the same for another field but had to adjust the return to this:

return $collection->first()->role()->value();

Thanks for the support.