<p>This is a truly tricky one. Let's restate the problem:</p>

<blockquote>
  <p>For each category in a tree list of categories: We want to display content from an element if the element is related to the category but not related to any of the category's children.</p>
</blockquote>

<p>Off the top of my head, I can't think of a really performant way to do this... So, hopefully there aren't too many categories in your setup, and caching is key.</p>

<p>First we need to generate a recursive structure of categories:</p>

<pre><code>{% set categories = craft.categories.group(...) %}

{% nav category in categories %}

    {% include '_elementsForThisCategory' with {category: category} only %}

    {% ifchildren %}
        {% children %}
    {% endifchildren %}

{% endnav %}
</code></pre>

<p><em>(You could easily use a macro in place of that <code>include</code>. These days I prefer includes over macros for anything other than the very simplest use cases.)</em></p>

<p>Next (in the included template/macro), we need to create a list of elements that are related to the present category but not related to any of its children:</p>

<pre><code>{# Query entries that are related to this category's children. #}

{% set relatedToChildCats = craft.entries.relatedTo({
    targetElement: category.getChildren()
    field: 'yourMatrixField.yourCategoriesField'
}) %}

{# Query entries that are related to this category,
   and exclude the entries that are related to this category's children. #}

{% set theBuckStopsHere = craft.entries.relatedTo({
    targetElement: category
    field: 'yourMatrixField.yourCategoriesField'
}).id('not', relatedToChildCats.ids) %}

{# Display the content however you want. #}

{% for entry in theBuckStopsHere %}
    ...
{% endfor %}
</code></pre>

<p>&rarr; You probably noticed that my example uses <em>Entry</em> elements, and your stated use case deals with <em>MatrixBlock</em> elements. I wanted to give the example using purely out-of-the-box-friendly code, and unfortunately Craft 2 doesn't provide a template method for querying Matrix blocks... But luckily, our good friend <a href="http://gotolow.com/" rel="nofollow noreferrer">Low</a> wrote a nice plugin (<a href="https://github.com/low/lowblocks" rel="nofollow noreferrer">Low Blocks</a>), which adds a handy <code>craft.lowBlocks</code> template variable.</p>

CC BY-SA 3.0
2017-05-29T06:42:40.220Z
It doesn't look like a performant way indeed but it does look like the only way to go. So I'll accept this as an answer. In the mean time, I've talked to the client and we agreed to limit the amount of categories to a level 1 list which makes it all a lot easier. But I'll probably need to use this in other parts of the project too. So thanks!
Tom De Smet
CC BY-SA 3.0
2017-05-29T05:25:53.210Z
2017-05-29T05:25:53.210Z
Michael Rog
<p>I have a category group (CG).
I have a channel of entries with a matrix field (MF).
Every block in that matrix field has a category field linked to the CG.</p>

<p>I want to list all the MF blocks in an ordered list grouped by their category.
So for example:</p>

<ul>
<li>Category A

<ul>
<li>MF block 1</li>
<li>MF block 2</li>
<li>Category AB

<ul>
<li>MF block 3</li>
</ul></li>
</ul></li>
</ul>

<p>I'm looping over all categories within CG (with a recursive macro) and for each category I show a MF block that has that category related.
The problem is that when a block is related to Category AB, it is also related to its parent Category A, so the block is shown in Category A as well as in Category AB.</p>

<p><strong>I want it to be only shown in the lowest level category, being AB in this case.</strong></p>

<p>It gets even trickier because I cannot limit the amount of categories selected to just 1, because than Craft automatically selects only the top parent. So now (even if I don't need it) I have to take care of the possibility that the matrix block has multiple categories selected (and their children).</p>

<p>I was thinking about grouping the matrix blocks by their category with the <a href="https://github.com/timkelty/craft-groupby" rel="nofollow noreferrer">groupBy filter plugin</a> but I haven't found the time yet to try this out. And I'm afraid I might loose the hierarchy of the CG.</p>

<p>I could use a section for the categories (where you can limit it to a single item and it'll select the correct child) but than the client has a hard time to see what the parent category is in the CP. So that's a downer.</p>

<p><strong>Why I need this:</strong> </p>

<p>The client needs to be able to upload a ton of files related to an entry or add links related to an entry. That's why I created a matrix with 3 block types: external link, internal link and file.
The file block has a table field where they can upload an asset and select a locale. Because all files can have multiple translations. But the locales these files can be translated in do not match the locales that the site is available in. So that's why I can't just use a translatable asset field. That also why I can't use a front-end asset browser (because of the links and the translated files and because I have no control over the created folder structure).</p>

<p>I could live without them being able to add links if that would make it simpler. Alternative solutions are more than welcome!</p>

<assets><categories>
Only show items related to the lowest category level
# Only show items related to the lowest category level

(Asked by: username_0 on 2017-05-17)

I have a category group (CG).
I have a channel of entries with a matrix field (MF).
Every block in that matrix field has a category field linked to the CG.

I want to list all the MF blocks in an ordered list grouped by their category.
So for example:

* Category A
  + MF block 1
  + MF block 2
  + Category AB
    - MF block 3

I'm looping over all categories within CG (with a recursive macro) and for each category I show a MF block that has that category related.
The problem is that when a block is related to Category AB, it is also related to its parent Category A, so the block is shown in Category A as well as in Category AB.

**I want it to be only shown in the lowest level category, being AB in this case.**

It gets even trickier because I cannot limit the amount of categories selected to just 1, because than Craft automatically selects only the top parent. So now (even if I don't need it) I have to take care of the possibility that the matrix block has multiple categories selected (and their children).

I was thinking about grouping the matrix blocks by their category with the [groupBy filter plugin](https://github.com/timkelty/craft-groupby) but I haven't found the time yet to try this out. And I'm afraid I might loose the hierarchy of the CG.

I could use a section for the categories (where you can limit it to a single item and it'll select the correct child) but than the client has a hard time to see what the parent category is in the CP. So that's a downer.

**Why I need this:**

The client needs to be able to upload a ton of files related to an entry or add links related to an entry. That's why I created a matrix with 3 block types: external link, internal link and file.
The file block has a table field where they can upload an asset and select a locale. Because all files can have multiple translations. But the locales these files can be translated in do not match the locales that the site is available in. So that's why I can't just use a translatable asset field. That also why I can't use a front-end asset browser (because of the links and the translated files and because I have no control over the created folder structure).

I could live without them being able to add links if that would make it simpler. Alternative solutions are more than welcome!

**Tags:** assets, categories

---

## 1 answers

### Answer by username_1 on 2017-05-29. Score: 0 | Accepted answer

This is a truly tricky one. Let's restate the problem:

For each category in a tree list of categories: We want to display content from an element if the element is related to the category but not related to any of the category's children.

Off the top of my head, I can't think of a really performant way to do this... So, hopefully there aren't too many categories in your setup, and caching is key.
First we need to generate a recursive structure of categories:
{% set categories = craft.categories.group(...) %}

{% nav category in categories %}

    {% include '_elementsForThisCategory' with {category: category} only %}

    {% ifchildren %}
        {% children %}
    {% endifchildren %}

{% endnav %}

(You could easily use a macro in place of that include. These days I prefer includes over macros for anything other than the very simplest use cases.)
Next (in the included template/macro), we need to create a list of elements that are related to the present category but not related to any of its children:
{# Query entries that are related to this category's children. #}

{% set relatedToChildCats = craft.entries.relatedTo({
    targetElement: category.getChildren()
    field: 'yourMatrixField.yourCategoriesField'
}) %}

{# Query entries that are related to this category,
   and exclude the entries that are related to this category's children. #}

{% set theBuckStopsHere = craft.entries.relatedTo({
    targetElement: category
    field: 'yourMatrixField.yourCategoriesField'
}).id('not', relatedToChildCats.ids) %}

{# Display the content however you want. #}

{% for entry in theBuckStopsHere %}
    ...
{% endfor %}

→ You probably noticed that my example uses Entry elements, and your stated use case deals with MatrixBlock elements. I wanted to give the example using purely out-of-the-box-friendly code, and unfortunately Craft 2 doesn't provide a template method for querying Matrix blocks... But luckily, our good friend Low wrote a nice plugin (Low Blocks), which adds a handy craft.lowBlocks template variable.

> **Comments:**
> **username_0**: It doesn't look like a performant way indeed but it does look like the only way to go. So I'll accept this as an answer. In the mean time, I've talked to the client and we agreed to limit the amount of categories to a level 1 list which makes it all a lot easier. But I'll probably need to use this in other parts of the project too. So thanks!  

---

