3

I have 2 sections, events and activities, that share many fields. But activities doesn't have an eventLevel field as there isn't a level. eventLevel is a radio fieldtype. So I want to insert the eventLevel when it exists and if it doesn't just insert the text "Activity". I've tried various tests on if eventLevel is defined, is null, and length. If there is an eventLevel it displays, but if it's an activity I end up with an empty cell.

{% set events = craft.entries.find({section:'events,activities', eventDate : ">= " ~ now.w3cDate() , order:'eventDate'}) %}
{% if events %}
    {% for entry in events %}
    <tr>
        <td class="col-date">{{ entry.eventDate.format('D j M') }}</td>
        <td><a href="{{ entry.url }}" title="More info about {{ entry.eventName }}">{{ entry.eventName }}</a></td>
        <td>{{ entry.nearestTown }}</td>
        <td>{% if entry.eventLevel is defined %}{{ entry.eventLevel }}{% else %}Activity{% endif %}</td>
    </tr>
    {% endfor %}
{% endif %}

I've also tried the twig default filter with the same result:

{{ entry.eventLevel|default('Activity') }}

3 Answers 3

2

Is there a chance you once had this field added to both sections? Because this all looks like there's data still left set and you're only expecting "eventLevel" fields to be empty / null for your "activities" section entries, but in fact they are not.

See this SE for why this can happen:
Entries retain field data that has been removed from entry type layout

To solve the problem you could now clear the data, by (a) recreating the radio field with the same settings but with a different handle / name, go through your entries to copy the values, then delete the old field and give the new one the handle and name of the old one. Or you could (b) directly edit the values in the database, the problem with this approach is, you can't sort the records by section.

This would also mean alot of work and I think it's actually not worth it at all, because there's a better way to distinguish whether to show the field's value or not: just check for the entry's section!

Here's how I would do it:

{% set isEvent = entry.section.handle == 'events' %}
{% set isActivity = entry.section.handle == 'activities' %}

{{ isEvent ? entry.eventLevel : 'Activity' }}

You just evaluate entry.section.handle == 'events' and store the result as a variable at the top of your template code. The variable is now available troughout the template and it is now very easy to use this info. You currently only need it once in your code, but this probably changes as you progress with the project.

2
  • Whilst similar to James's answer this one has a bit more flexibility, so I changed my selected answer.
    – Paul Frost
    Feb 19, 2016 at 21:42
  • It does also reflect the additional help that carlcs gave me getting to the root of the problem via a Slack DM conversation.
    – Paul Frost
    Feb 19, 2016 at 22:06
4

To test if a field exists, you'll have to use brackets notation, i.e.

{% if entry['eventLevel'] is defined %}
   ...
{% endif %}

When the field exists, but there isn't a selected option, the Radio FieldType returns an empty string, so you also need to test for entry.eventLevel != ''.

Putting it together, I believe a ternary conditional would perhaps be the most succinct solution in your particular case:

<td>{{ entry['eventLevel'] is defined and entry.eventLevel != '' ? entry.eventLevel : 'Activity' }}</td>

What the above does is to first check if the entry has a property 'eventLevel' – the brackets notation is needed here, to avoid Twig throwing an exception if the entry variable doesn't have the property – before checking if the attribute's value is not an empty string. If both of those statements evaluate to true, then the attribute's value is printed; if not, the string Activity outputs.

This is a bit beside the point, but if you're wondering about the syntax here, the so called ternary operator (e.g. {{ variable ? 'yes' : 'no' }}) is just a kind of a short-hand way to write conditionals. Ternary operators are supported in many programming languages (including JavaScript and PHP).

If you wanted to, you could write out the full conditional and it would work exactly the same:

<td>
    {% if entry['eventLevel'] is defined and entry.eventLevel != '' %}
       {{ entry.eventLevel }}
    {% else %}
       Activity
    {% endif %}
</td>

I'd argue that a ternary operator is more readable, shorter and also makes it easier to deal with potential whitespace issues etc. when inlined in markup like this, though.

13
  • That didn't work, still blank if no eventLevel.
    – Paul Frost
    Feb 19, 2016 at 12:13
  • @PaulFrost Right – I assumed the Radio FieldType returned a falsey value for fields without a selected value, but it actually returns an empty string. I edited my answer; should work now – the correct test is entry[eventLevel] is defined and entry.eventLevel != '' Feb 19, 2016 at 12:27
  • The if entry.eventLevel is defined test won't work in this case, because it is truthy even if the field isn't attached to this entry type's field layout but to any other entry type. A simple if entry.eventLevel test should work though.
    – carlcs
    Feb 19, 2016 at 13:03
  • Your revised example works. But I'm confused by the structure of the query, I haven't seen the the ? and colon used in examples before, where is that documented?. I had tried {% if entry.eventLevel %}{{ entry.eventLevel }}{% else %}Activity{% endif %} in the first place and when that didn't work I tried to be more specific. So both James and Mats solutions work but neither seem very intuitive.
    – Paul Frost
    Feb 19, 2016 at 13:53
  • I'm really struggling with the conversion from using ExpressionEngine to Craft, some simple things seem to require very complex, unintuitive code and with so many ways to do the same thing finding examples is hard.
    – Paul Frost
    Feb 19, 2016 at 13:58
3

How about a conditional to check the entry.type rather than the field? Perhaps more appropriate in this case rather than checking if the field is defined. Something like this:

{% if entry.type.handle == 'events' %}
    {{ entry.eventLevel }}
{% else %}
    Activity
{% endif %}

Alternatively, check the section rather than the entry type with entry.section.handle instead of entry.type.handle.

6
  • I'm not sure what you mean, by check the entry.type. Plus if it's an event it must have a level set, can't be empty.
    – Paul Frost
    Feb 19, 2016 at 12:16
  • @PaulFrost I’ve just edited the answer to include an example.
    – James
    Feb 19, 2016 at 12:38
  • @James I think he's confused because he's getting the entries from multiple sections. Your answer probably works anyways, because there's a good chance he's got this set up with different entry type handles.
    – carlcs
    Feb 19, 2016 at 13:10
  • @carlcs good point. Paul, you could also check against the entry.section rather than the entry type if that makes more sense.
    – James
    Feb 19, 2016 at 13:23
  • Yes, I changed it to section and that works. But I would never have found that solution from the docs. Why do I need to check the section first?
    – Paul Frost
    Feb 19, 2016 at 13:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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