Complex collections depending on Frontmatter headers and it's value?

Include partial view with a complex collection:

{% include 'partials/article-main.html.twig' with {'page': #here goes condition} %}

How can i choose all pages, that has a field named main_article in the headers/Frontmatter set to true?

Or even without that “with” part directly in a TWIG file:

{% set options = { items: {'@root': #someCondition here} } %}
{% set main_collection = page.collection(options) %}

nobody needed that functionality?

Well, it’s Easter. The Grav experts are probably on vacation, enjoying well deserved time outside in the nature with their families, friends and/or significant others. It’s only the struggling newbies like me who still have to sit in front of their computers, learning how to use Grav.

If I understand you correctly (and I’m not certain I do), you probably want something like this:

  {% for p in pages.children.visible if p != page %}
    {% if p.header.main_article %}
      {# Do stuff. #}
    {% endif %}
  {% endfor %}
1 Like

Thank you for your answer, i think it’s trivial task, that everyone would want to do, it’s just like u’re doing a SELECT page WHERE main_article = true query from database , i just want to get all pages with that field set to true only, then use it in collection:

{% set options = { #here we filter all pages with header.field set to true } %}

# then we're using this as collection
{% set main_collection = page.collection(options) %}

Won’t your example make a huge performance hit, because it will iterate over all pages, if i want just one with that field set to true.

I wouldn’t know. I’m really quite new to Grav. I suppose, once Easter is over and the forum becomes more vivid, somebody with more experience might double check this.

That being said: I got that approach from reading the Twig templates of the “Antimatter” theme where looping over pages.children.visible is used in the navigation partial. Also, my expectation would be that a) performance issues would come up only with really, really huge sites. (It’s just looping through an PHP array and checking a value.) and that b) caching takes care of that anyways.

I don’t quite understand, why you need to construct a collection in Twig. My (possibly wrong) understanding is that collections are just a way to define a set of pages in a page’s markdown file. In my (again: possibly wrong) understanding, they’re not something you’d define in a Twig file.

However, in that vein, the documentation mentions taxonomy collections: https://learn.getgrav.org/content/collections#taxonomy-collections

So if it’s okay for you to define your main_article pages by adding a tag instead of a field in the frontmatter, you might just use something like (untested):

content:
   items:
      '@taxonomy.tag': main_article

I’ll explain the logic behind it. In admin section i’ve added field of type “toggle” (using blueprints) with options - yes or no. When admin toggles this to yes, then this page is going to be shown on the front page as preview: image and title. You think, that using taxonomies would fill my needs?

I think using taxonomies would be inconvenient for site administrator, because he would have to choose that tag vs just toggling yes/no button.

I think that’s a matter of taste. Using a tag like ‘featured’ is perfectly reasonable if you think of “being featured on the front page” as “this is an additional property of that article”.

I had a very similar case: pages to be featured with images in a side bar. I tried the taxonomy approach first. But then I thought: having a toggle, like you, is better for this particular site and this particular end user. I ended up using the approach I first posted (from the Antimatter theme), i. e. iterating over pages.children.visible. I think that’s perfectly reasonable and straight forward.

Reading the documentation some more, it seems like creating collections from Twig or even PHP is a thing. From the looks of it, it seems useful when using complex taxonomies, sorting orders etc. However, reading both the documentation and <site name>/system/src/Grav/Common/Page/Collection.php, I see nothing to filter collections based on a flag in the frontmatter.

(Again: I’m new to Grav, so I might be wrong with everything.)

Documentation is clearly missing information about filtering collections. I guess, grav team is not implemented this kind of things yet.

So you’ve ended using taxonomies or like this:

{% set options = { items: '@root.descendants', 'order': {'by': 'date', 'dir': 'desc'}, 'pagination': false } %}
{% set main_collection = page.collection(options) %}

{% for p in main_collection|slice(0, 1) if p.header.main_article %}
	{{ dump(p) }}
	<article class="main-news">
	    <a href="/" class="d-block mb-3">
	        <img src="{{ p.header.image }}" alt="..." class="img-responsive w-100 rounded">
	    </a>

	    <a href="/">
	        <h4>{{ p.title }}</h4>
	    </a>
	</article>
{% endfor %}

A few things bothering me using this approach:

  1. Iterates over all pages;
  2. If i set 'limit': 1 in ordering, then it wouldn’t work, because it’s limited to one page and if it’s page doesn’t have that field in a header, then nothing would be shown;

By the way:

What does mean if p != page, it means if it’s not a page object? Then what else it could be, except the page ? :smiley:, maybe i’m misunderstanding something.


In my understanding - collections is like an Eloquent in Laravel (DB Query builder), is it wrong?

Ah, I understand now that there’s only ever to be one page with that flag. Yeah, it seems like it’s not possible to break from a for loop in Twig.

page is the current page. It’s to avoid having a page featuring itself; the way I understood you at first, I thought that would be useful.

Only one will be shown (in frontend - to the user), but there could hundreds of them with main_article set to true.

How do you order items using this method? Without collections is impossible to order pages, as i know.

The sort order is the same as it appears in the “Pages” section of the admin panel; which means: users can order it manually. This is what I needed for my sidebar.

I learned something about collections through our discussion; in your case, I’d use a collection now, too.

Grav dev’s should take care of that issue with filtering collections, hope to see it live very soon.

I’ve faced another issues - it’s not possible to limit number of articles, while using Twig’s for… Dev’s are you there?

If you want to limit your range of articles, this should be of help to you I think :slight_smile: In combination with this you could turn the current article id (if there is one) into a number that scopes your from … to … range :slight_smile: Hope it helps!
https://twig.symfony.com/doc/2.x/functions/range.html