<p>If you can, I would go ahead and convert Categories to Entries, following the <a href="https://craftcms.com/blog/entrification" rel="nofollow noreferrer">Entrification plan</a>. 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.</p>
<hr />
<p>If you can't do that, you can also filter the selected categories to only include leaf nodes (nodes without children):</p>
<pre class="lang-twig prettyprint-override"><code>{% set selectedLeafCategories = entry.categoriesField.leaves() %}
{% set products = craft.entries()
    .section('products')
    .relatedTo(selectedLeafCategories)
    .all()
%}
</code></pre>
<p>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.</p>
<p>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:</p>
<pre class="lang-twig prettyprint-override"><code>{% set selectedCategories = entry.categoriesField.all() %}
{% set leafCategories = selectedCategories|filter(
    category =&gt; selectedCategories|filter(current =&gt; category.isAncestorOf(current)) is empty
)|values %}
</code></pre>
<p>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.</p>

CC BY-SA 4.0
2023-10-16T02:28:02.420Z
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
CC BY-SA 4.0
2023-10-16T15:34:28.447Z
@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
CC BY-SA 4.0
2023-10-17T00:07:30.370Z
Yeah, using `.all()` in the categories query. This is what I'm doing – https://gist.github.com/tyssen/fb4ef35da93ebee1f5c8ac1abe388027 It's a component in a page builder, so the categories are being passed in a bit differently than calling `entry` directly but I am using all of them. When I `dd` `selectedCategories` I get an array with the parent first and the child second. But when I `dd` `leafCategories` I get that order reversed.
Tyssen
CC BY-SA 4.0
2023-10-17T00:11:27.543Z
Here's what those `dd`s look like: https://www.dropbox.com/scl/fi/3pgi62pwo8tazwex70x2f/leafCategories.png?rlkey=lutx0s6uxje3zlke98mulqjhb&dl=0 https://www.dropbox.com/scl/fi/4qf60w5jflye8x72su74l/selectedCategories.png?rlkey=y490c41a0bfvkud46p3sndju7&dl=0
Tyssen
CC BY-SA 4.0
2023-10-17T08:03:05.157Z
@Tyssen Well, that looks correct to me. You said you don't get any results, but `leafCategories` includes at least one item. Furthermore, the first item was removed from `selectedCategories` (index `0` with title `Accomodation` is gone). I'm guessing that's the parent category, while `Self-contained` is a child of that parent. The parent is gone while the child remains. What's not working as expected?
MoritzLost
CC BY-SA 4.0
2023-10-17T08:13:43.000Z
@Tyssen To get a better overview of which categories are in both arrays, you can also use `{% dd leafCategories | column('title') %}`.
MoritzLost
CC BY-SA 4.0
2023-10-17T13:55:17.923Z
With that I get just _Self-contained_ for the `leafCategories`. So it's not the output of categories that's not working, it's the entries related to that category that doesn't work. So in the CMS I have a bunch of entries that are in the self-contained category which automatically have accommodation also chosen because it's the parent. If I only choose the accommodation category from the categories field, I get entries results with `relatedTo(leafCategories)`, but if I then add the self-contained child category, I get no results.
Tyssen
CC BY-SA 4.0
2023-10-17T13:56:21.637Z
I've tested with `relatedTo(category_id_number)` equalling the value of what the `leafCategories` is and do get results when I do it that way.
Tyssen
CC BY-SA 4.0
2023-10-17T14:26:29.463Z
@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
CC BY-SA 4.0
2023-10-17T22:54:43.653Z
yes that did it. Now I can see results related to the correct category. Thanks for sticking with me through it. :)
Tyssen
CC BY-SA 4.0
2023-10-18T14:00:10.117Z
@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
CC BY-SA 4.0
2023-10-13T10:43:51.947Z
2023-10-18T07:51:29.060Z
2023-10-18T07:51:29.060Z
MoritzLost
<p>I have a categories field for outputting products to a map. The categories linked to that field have a parent/child relationship.</p>
<p>With <code>{% set products = craft.entries.section('products').relatedTo(categoriesField).all() %}</code> 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.</p>
<p>I only want to show entries relating to the child category if one has been selected, and if not, then use the parent category.</p>
<p>How do I do that?</p>

<entries><categories><relations>
Only show entries related to child category if it exists
# Only show entries related to child category if it exists

(Asked by: username_0 on 2023-10-13)

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?

**Tags:** entries, categories, relations


---

## 1 answers

### Answer by username_1 on 2023-10-13. Score: 2 | Accepted answer

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.

> **Comments:**
> **username_0**: 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.  
> **username_1**: @username_0 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.  
> **username_0**: Yeah, using `.all()` in the categories query. This is what I'm doing – https://gist.github.com/tyssen/fb4ef35da93ebee1f5c8ac1abe388027 It's a component in a page builder, so the categories are being passed in a bit differently than calling `entry` directly but I am using all of them. When I `dd` `selectedCategories` I get an array with the parent first and the child second. But when I `dd` `leafCategories` I get that order reversed.  
> **username_0**: Here's what those `dd`s look like: https://www.dropbox.com/scl/fi/3pgi62pwo8tazwex70x2f/leafCategories.png?rlkey=lutx0s6uxje3zlke98mulqjhb&dl=0 https://www.dropbox.com/scl/fi/4qf60w5jflye8x72su74l/selectedCategories.png?rlkey=y490c41a0bfvkud46p3sndju7&dl=0  
> **username_1**: @username_0 Well, that looks correct to me. You said you don't get any results, but `leafCategories` includes at least one item. Furthermore, the first item was removed from `selectedCategories` (index `0` with title `Accomodation` is gone). I'm guessing that's the parent category, while `Self-contained` is a child of that parent. The parent is gone while the child remains. What's not working as expected?  
> **username_1**: @username_0 To get a better overview of which categories are in both arrays, you can also use `{% dd leafCategories | column('title') %}`.  
> **username_0**: With that I get just _Self-contained_ for the `leafCategories`. So it's not the output of categories that's not working, it's the entries related to that category that doesn't work. So in the CMS I have a bunch of entries that are in the self-contained category which automatically have accommodation also chosen because it's the parent. If I only choose the accommodation category from the categories field, I get entries results with `relatedTo(leafCategories)`, but if I then add the self-contained child category, I get no results.  
> **username_0**: I've tested with `relatedTo(category_id_number)` equalling the value of what the `leafCategories` is and do get results when I do it that way.  
> **username_1**: @username_0 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.  
> **username_0**: yes that did it. Now I can see results related to the correct category. Thanks for sticking with me through it. :)  
> **username_1**: @username_0 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!  

---

