2

I have an entry with two matrix fields and I want to use relations between them using Tags to create a fake nested Matrix functionality for one block type. The "main" matrix field is for creating a typical banded page (several horisontal stripes of content). One of the blocks in this main matrix has to contain a contentSlider, and since in this specific case adding an Assets field is not sufficient we have to nest or merge two matrix fields.

While looping through the main matrix field using the Switch method I have a block type named "contentSlider". In this block type I have a Tags field named "showTags". In my second matrix field named "slidesMatrix" I have a field named "tags". I want to find blocks in the second matrix (slidesMatrix) related to the current block in the main matrix.


Here is my attempt, it is not giving me any errors but it is not outputting the "slide.heading" field either so something must be wrong:

{% case "contentSlider" %}
    {% set tagsToFind = block.showTags %}
    {% set relatedSlides = entry.slidesMatrix.tags.relatedTo(tagsToFind).order('score').find() %}
    {% for slide in relatedSlides %}
        Matched Tag in: {{ slide.heading }}<br>
    {% endfor %}

This alternative code works, but it is only matching the first Tag from the current block to all the Tags in the second matrix block (slidesMatrix.tags) and switching to one of the native Craft methods like "relatedTo" would be a more powerful solution.

{% case "contentSlider" %}
    {% set tagsToFind = block.showTags %}
    {% set tagToFind = tagsToFind.first.title %}
    {% for slide in entry.slidesMatrix if tagToFind in slide.tags %}
        Matched Tag in: {{ slide.heading }}<br>
    {% endfor %}            

To sum this up into one question;
How can I loop through a matrix field filtered by Tags contained in a tags fields inside the matrix blocks I want to loop through, using a native Craft feature like 'relatedTo'?

  • 1
    Why isn't an Assets field sufficient? You can have custom fields on assets. – Bryan Redeagle Feb 9 '15 at 2:37
  • We need some more fields in addition to the asset field in the slides. I know we can make all the fields we need on the asset itself, but if I'm not wrong those fields are not unique per entry they are placed in which mean they have to be the same every time they are used (global). For some slides there might not be an image at all. This is more a "content slider" than an image slideshow. It must support an header, image, richtext body and a entry-link with a related textfield (to be output as a button with custom text). – Alf Vestre Feb 9 '15 at 7:36
  • If you remove tags.relatedTo(tagsToFind).order('score').find() altogether and only do {% set relatedSlides = entry.slidesMatrix %}, does it return all slides? – carlcs Feb 9 '15 at 12:18
  • @carlcs, yes your code return all slides. – Alf Vestre Feb 9 '15 at 17:30
4

I just tried to replicate your setup (in simplified form), because I thought this is in fact an interesting and creative approach to do Matrix nesting that might come handy.

Here's my code that works great for me. I hope it helps, even though I actually don't see the difference to what you have?!

{# Go through our Main Matrix blocks #}
{% for block in entry.mainMatrix.type('mainRelationsBlock') %}

    {# Get the tags selected in the Main Matrix block #}
    {% set tagsToFind = block.mainTags %}

    {# Try filtering Matrix blocks of our Sub Matrix using `relatedTo` #}
    {% set relatedBlocks = entry.subMatrix.relatedTo({
        targetElement: tagsToFind
    }) %}

    {# Show them #}
    {% for relatedBlock in relatedBlocks %}
        <li>{{ relatedBlock.text }}</li>
    {% endfor %}

{% endfor %}
  • This line did the magic: {% set relatedBlocks = entry.subMatrix.relatedTo({ targetElement: tagsToFind }) %} – Alf Vestre Feb 9 '15 at 18:16
  • I can't see how this code {% set relatedBlocks = entry.subMatrix.relatedTo({ targetElement: tagsToFind }) %} targets the subMatrix.tagsfield it seems to target the entire subMatrix. If you can explain this, it might be easier to understand how this work? – Alf Vestre Feb 9 '15 at 18:43
  • @AlfVestre sorry, I can't explain this to you and there's no word on it in the docs. I actually thought that there's only a very limited set of filters available to filter Matrix blocks: type('myBlockType'), first(), nth('3') and since Craft 2.3 the new field filter myLightSwitchField('1') or myDateTimeField('> 2014-01-01'). I did not expect relatedTo() to work at all, but it seems like it gets all the Matrix blocks that are related. Nice find! – carlcs Feb 9 '15 at 18:57
1

I have another approach that I prefer. This does not involve multiple matrixes, but instead clever templating. Start with your main matrix. Add the blocks from your slide matrix to the main matrix. When editing the matrix, add slide blocks underneath each Content Slider block. When you're done with slides just add the other blocks as usual.

The template is where the magic happens!

{% case "contentSlider" %}
    {% set openSlider = true %}
    <div class="contentSlider">

{% case "imageSlide" %}
    {% if openSlider %}
        {{ block.heading }}
    {% endif %}

{% case "richTextBlock" %}
    {% if openSlider %}
        {% set openSlider = false %}
        </div>
    {% endif %}
    {{ block.richTextField }}

So what's happening here is when you start a new slider, the openSlider variable tells other blocks when there's a slider being built. When a non-slide shows up, it closes the slider before adding its own content. For slides, they only show their content when there's an open slider. This keeps them from showing up elsewhere in case they are misplaced.

  • I guess this will work as well, thanks for sharing your approach! For my current project I'll stick with @carlcs solution, but your approach can be a better fit for another site. Does it work well with Live Preview? – Alf Vestre Feb 10 '15 at 8:09
  • I haven't tested it (I don't use Live Preview much), but I don't see why it wouldn't work. – Bryan Redeagle Feb 10 '15 at 13:49
0

Here is my initial code with @carlcs solution included:

{% case "contentSlider" %}
    {% set tagsToFind = block.showTags %}

    {# Match the tags between the current matrix block and another matrix field  #}
    {% set relatedSlides = entry.slidesMatrix.relatedTo({
        targetElement: tagsToFind
    }) %}

    {% for slide in relatedSlides %}
        Matched Tag in: {{ slide.heading }}<br>
    {% endfor %}

This works great, but I still have my fingers crossed for native support for nested matrix support in Craft! It would be a killer feature and is on the top of my wish-list.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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