1

I have a categories field for outputting products to a map. The categories linked to that field have a parent/child relationship.

With {% set products = craft.entries.section('products').relatedTo(categoriesField).all() %} if a child category is selected, the parent gets selected by default too and on the front end, entries belonging to the parent category get output too.

I only want to show entries relating to the child category if one has been selected, and if not, then use the parent category.

How do I do that?

1 Answer 1

2

If you can, I would go ahead and convert Categories to Entries, following the Entrification plan. For Categories fields, the hierarchy is always maintained, so you can't select child categories without selecting all their ancestors. But for Entries fields, this is optional, so you can just turn off the option to maintain the hierarchy. This will allow your editors to select child categories without selecting their parents.


If you can't do that, you can also filter the selected categories to only include leaf nodes (nodes without children):

{% set selectedLeafCategories = entry.categoriesField.leaves() %}
{% set products = craft.entries()
    .section('products')
    .relatedTo(selectedLeafCategories)
    .all()
%}

However, this will only find actual leaf nodes, so only categories that have no children at all. If the editor only selects a parent category without selecting any children, those still won't be included in the results above, because they aren't leaf nodes.

I don't think it's possible to apply this logic in the query itself. But you can use a Twig filter to remove any parent categories where at least one of their child categories is selected as well:

{% set selectedCategories = entry.categoriesField.all() %}
{% set leafCategories = selectedCategories|filter(
    category => selectedCategories|filter(current => category.isAncestorOf(current)) is empty
)|values %}

Keep in mind that this might make the behaviour a bit difficult to understand for your editors. The entrification is definitely the better solution, if that is possible for your project at this time.

11
  • I can't convert categories to entries so I'm using your last example with the filters. With this in place, if I only select a 1st-level category, I get results, but if I select a 2nd-level category, I get nothing.
    – Tyssen
    Commented Oct 16, 2023 at 2:28
  • @Tyssen Hm, pretty sure the code is correct, tested it again. Are you maybe using leaves() in the query for the second approach? In this approach, you need to fetch all categories, or it won't work correctly. If not, please put {% dd selectedCategories %} in your template to check if the query is returning the correct results and then {% dd leafCategories %} to see which categories remain after the filter operation.
    – MoritzLost
    Commented Oct 16, 2023 at 15:34
  • 1
    @Tyssen Hm, sounds like that's a different issue. Maybe try .relatedTo(leafCategories | values). Sometimes the skipped indexes caused by the filter filter can mess up some internal logic.
    – MoritzLost
    Commented Oct 17, 2023 at 14:26
  • 1
    yes that did it. Now I can see results related to the correct category. Thanks for sticking with me through it. :)
    – Tyssen
    Commented Oct 17, 2023 at 22:54
  • 1
    @Tyssen Great! Yeah the indexing thing when using filter has tripped me up a lot of times … I've updated the example code in my answer accordingly!
    – MoritzLost
    Commented Oct 18, 2023 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.