2

Background:

One of my templates has up to 6 fields that should each go into the same markup. Here's an example with a courseDesign field:

{% if entry.courseDesign|length %}
  <section class="col-xl mb-3">
    <h2 id="courseDesign">Course Design</h2>
    {{ entry.courseDesign }}
  </section>
{% endif %}

This worked fine when I wrote each section out like this. However, once I also added a table of contents/nav, I decided to refactor.

I now have a courseFields array, and I'm adding each field to it if it exists:

{% set courseFields = {} %}
{% if entry.courseDesign %}
  {% set courseFields = courseFields|merge({ "courseDesign": { handle: "courseDesign", title: "Course Design" } }) %}
{% endif %}

My navigation macro works perfectly, because it's only interacting with the objects in the courseFields array.

My problem:

I can't figure out how to iterate through my fields and get the actual content from them using a macro.

If I use {{ entry.handle }} in my macro, even when handle is a valid field handle, I get the runtime error Variable "entry" does not exist.

I also tried:

{% set courseField = "entry." ~handle %}
{{ courseField }}

but that produces a string: "entry.courseDesign".

How do I access entry from my macro? Should I be going about this a different way?

4

I figured it out! I ditched the macro and just included the following in my template:

{% for field in courseFields %}

  <section class="col-xl mb-3">
    <h2 id="{{ field.handle }}">{{ field.title }}</h2>
    {{ entry[field.handle] }}
  </section>

{% endfor %}
1

Just as an additional note: instead of creating your fields array in your template you can use Craft functions

{% set layout = entry.getFieldLayout() %}
{#
    you can either output all tabs or check for a specific tab where all
    your "frontend" form/output fields live
    so you could create a "frontend" tab in your fieldLayoutDesigner
    If you just want to display all fields do
    for field in layout.getFields() directly
#}
{% for tab in layout.tabs %}
    {# you can either output all#}
    {{ tab.name }}
    {% if tab.name == "Frontend" %}
        {% for field in tab.getFields %}
            {% switch field.className() %}
                {# different templates for different field types #}
                {% case "craft\\fields\\PlainText" %}
                    <section class="col-xl mb-3">
                        <h2 id="{{ field.handle }}">{{ entry.getFieldValue(field.handle) }}</h2>
                        {{ entry.getFieldValue(field.handle) }}
                    </section>
                {% case "craft\\fields\\Assets" %}
                    {% set asset = entry.getFieldValue(field.handle).one() %}
                    {% if asset %}
                        <img src="{{ asset.getUrl() }}" alt="{{ asset.title }}" class="" >
                    {% endif %}
            {% endswitch %}

        {% endfor %}
    {% endif %}
{% endfor %}

Edit you can also list all fields for your frontend in a certain group and do

{% for field in layout.getFields %}
    {% if field.groupId == X %}

    {% endif %}
{% endfor %}

In order to group all your fields so you won't need that much work and it's easier to change things via CP

In order to gain access to field values by string you can/should use the Element->getFieldByValue($handle) function. Twigs element->handle could be explained as a "slower" redirect to that function but it fetches the field layout first and checks if the field is actually in the layout and if the field exists. In the end, the function above is executed so you can use it directly as well

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.