1

Craft noob here. I have an include file which I'm calling a "component" so I can reuse it across the site.

The component is set up like this.

<h2>{{ heading }}</h2>
{{ bodyContent }}
{% if ctaUrl is defined %}
  <a class="primary link" href="{{ ctaUrl }}">Click</a>
{% endif %}

Then on the template, I include it and pass some variables. In this case, the variables are from a Matrix field.

{% set matrixBlocks = entry.fullContentMatrix.all() %}

{% for block in matrixBlocks %}
    {% if block.type == 'imageRight' %}

        {% include '_components/imageRight' with {
            heading: block.heading,
            bodyContent: block.bodyContent,
            ctaUrl: block.ctaUrl
        } %}

...etc

This all works great. Until I have fields that are optional and have no value, in this case, the ctaUrl.

What is the best way to write this so that variables are only passed to the include if they are defined?

  • Simple approach would be to have two includes and use your conditional to decide which to execute,\ – Roi Agneta Feb 23 '19 at 0:05
  • That would work but in the case when I have a Matrix field with a lot of optional fields this doesn't feel very scalable. – Lee Feb 23 '19 at 11:34
  • What do you want to know exactly? How to check for those variables if they are defined in your included template or how to not pass the value in your parent template? – Robin Schambach Feb 23 '19 at 18:27
  • Keep in mind that you do not have to pass variables to an include - you can just declare them in the main template, setting them to null if they do not exist, and then reference those variables in the "component" – Roi Agneta Feb 24 '19 at 17:23
2

So in this case with ctaUrl, the issue is that you are checking if ctaUrl is defined.

As long as a field exists, is defined will return true as in reality, the variable block.ctaUrl exists, it's just empty. To check for content in your case, you should test for NULL. So if ctaUrl is not NULL show your link.

In terms of organisation of your code, it's up to you. Like Roi said, you don't need the with. Your matrixBlocks will be available within the component.

Whether you set stuff up in the main template is up to you. Personally, I would do my logic in the component rather than the main templates.

You will need to be consistant with your naming but the component is where you need this logic so if it's is in there, you don't need to dig around to understand what is going on. If you remove a component, the logic goes with it as suppose to have a bloated main template and also, you don't do a lot of stuff before you need to. No need in checking if you have a ctaUrl if your _components/imageRight isn't requested...

One reason for doing the logic in the main template would be that you would have less duplication (maybe) but from experience, I'm not sure it's worth it. So In your case:

{% set matrixBlocks = entry.fullContentMatrix.all() %}

{% for block in matrixBlocks %}
    {% if block.type == 'imageRight' %}
        {% include '_components/imageRight' %}
    {% elseif block.type == 'imageLeft' %}
        {% include '_components/imageLeft' %}
    {% elseif block.type == 'someOtherBlock' %}
        ....
    {% endif %}
{% endfor %}

Then do your work in your components:

<h2>{{ block.heading }}</h2>
{{ block.bodyContent }}
{% if ctaUrl is not NULL %}
  <a class="primary link" href="{{ block.ctaUrl }}">Click</a>
{% endif %}

Doing this, you will have a lean and clear main template and the component level logic will live in the component where it belongs. My opinion only though... Plenty of ways to do this :)

So to your question:

What is the best way to write this so that variables are only passed to the include if they are defined?

In your case, don't worry about that, check if they are defined when you need to use them, at component level.

|improve this answer|||||
  • Thank you Olivier. You're right, I was using is defined wrong. I ended up using {% if ctaUrl is defined and ctaUrl %} to check both. Also thanks for the advice on how to construct the templates. – Lee Feb 25 '19 at 1:38

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.