Find all pages with a custom header field

Hello,

I want to find all the pages with a custom variable in the frontmatter, in php.

Here’s some pages frontmatters:

---
news:
    location:
        - New York
    link: http://kufhlskjflkdjfhls
---
---
news:
    location:
        - New York
        - Chicago
    link: http://klmlmlmlkkkkmkmk
---
---
news:
    location:
        - Amsterdam
    link: http://qsssssszzszszszszszs
---

I want to find the pages where “New York” is a location.

Have you got an idea ?

I can do something like that

$collection = new Collection();
foreach( $all_pages as $p )
{
    $header = $p->header();
    if(
       $header
       && property_exists( $header, 'news' )
       && array_key_exists( 'location', $header->news )
       && in_array( 'New York', $header->news['location'] )
    )
    {
        $collection->append( $p );
    }
}

but I don’t know how to get all the pages first ! This is silly.
And I have the feeling that something easier could be done. With $page->evaluate(…) maybe ?

Thank you for any tip. I will also appreciate any relevant link to the documentation.

P.S: A convenient solution could be to make this “location” field a part of the taxonomy. But it bother me that this taxonomy field will appear in the admin settings form, for every page, including the pages where this field make no sense.

@lilive, A few answers/suggestions:

  • To get all pages in PHP you can do:
    $pages = $this->grav['pages']->all();
    
    See docs \Grav\Common\Page\Pages::all()
  • To filter all pages you could use \Grav\Common\Iterator::filter(callback)
    public function onPagesInitialized()
    {
      $city = 'New York';
      $pages = $this->grav['pages']->all();
    
      $pages->filter(function ($slug, $path) use ($pages, $city) {
        $page = $pages[$path];
        $header = (array) $page->header();
    
        if (!empty($header['news']['location'])) {
          $location = $header['news']['location'];
    
          return (is_array($location) && in_array($city, $location)) ||
            $location === $city;
        }
    
        return false;
      });
    
      // Process found pages
    }
    
  • Use taxonomy as you suggested.
    • To prevent taxonomy field from being displayed on ‘default’ pages you could override the ‘default’ blueprint and remove the taxonomy field .
      Docs: Removing Fields / Properties (unset-*@)
    • Create a dedicated blueprint for your own custom page type/template and add the taxonomy field there together with other fields required for your page header (e.g ‘link’) in a dedicated ‘tab’ that only shows in that page type.
      Docs: Example page blueprint

Hope this gives you enough ideas to continue…

1 Like

Yes indeed ! Thank you very much for this quick and really complete answer. You make me understand grav better.
This code works fine (and the empty() test is a good shortcut).

I’m already making a blueprint for this type of pages, but after some reading here, it seems tricky to me to hide and displace only one taxonomy field. I think I will stay with the first solution.

Thanks again !