Theme colour switcher

Print raw values from Smart Date fields in Twig templates - Drupal 8+

This is a followup to my post "Print formatted date with correct timezone from datetime or daterange field in node and Views templates - Drupal 8".

That post deals with core Drupal Date and Daterange fields. Recently I've been working on a site with events which use a Smart Date field. The Smart Date module offers many features that core Drupal date fields don't, such as recurrence.

Raw Smart Date field values

I used the Devel module to figure out what these were. Note that the first value will change depending on where you are printing the value. This assumes you're printing it in a node template, hence node; if you're printing it in a Views views-view--fields.html.twig template, it would be row._entity.

If your Smart Date field accepts only a single value, i.e. doesn't allow recurrence, you can just use the values as below (you will of course need to replace "FIELD_NAME" with the name of your field). If it has recurrence, read on to find out how to loop over the field values to print them all.

// Start date & time
{{ node.field_FIELD_NAME.value }}
// End date & time
{{ node.field_FIELD_NAME.end_value }}
// Duration (length) of the date, in minutes; e.g. if the event is an hour long, the output would be "60"
{{ node.field_FIELD_NAME.duration }}
// Recurrence rule (this returns a number; I'm not entirely sure what that means)
{{ node.field_FIELD_NAME.rrule }}
// Recurrence rule index (also not sure of this one)
{{ node.field_FIELD_NAME.rrule_index }}
// Date timezone
{{ node.field_FIELD_NAME.timezone }}

Note that these may need some processing; for example, the start and end date values are Unix timestamps. To convert them to human-readable values, you can use the Twig |date filter and pass it values from PHP Date, e.g.:

// Displays the start date as "November 01, 2023 01:00 PM EDT"
{{ node.field_FIELD_NAME.value|date('F d, Y h:i A T') }}

You can also use the format_date filter, which allows you to pass a Drupal date format.

Get values from Smart Date field with recurrence

Smart Date fields which allow recurrence are multiple-value fields, with each date instance being one value.

Essentially, the values are an array. So to get them in Twig, we need to get the keys for the array items. Doing {{ node.field_FIELD_NAME.value }} will get you only the first value, which in some cases might be what you want. Or you can do {{ node.field_FIELD_NAME[3].value }}, where [3] is the key of the specific value you're looking for.

But if you want all the values, you will need to loop over them. Here's a simple example of how to do that if you just want to display every value from the date field. This is for a views-view--fields.html.twig template; for a node template, replace row._entity with node; for a paragraph template, paragraph; and so on:

    {% for key in row._entity.field_FIELD_NAME|keys %}
        {{ row._entity.field_FIELD_NAME[key].value }}
    {% endfor %}

We use the Twig keys filter which returns the keys of an array in order to iterate over them.

Again, this will print the raw Unix timestamp value, which the |date or |format_date filters can be applied to.

Example of using raw Smart Date field values to create Twig logic

For my current site, as mentioned, events are recurring, and can have many dates. I needed to return the next date on which an event would occur, for a particular View display.

[Note that Smart Date fields with recurrence can create a headache with Views, because they will create a row for each date; i.e. the same piece of content will be displayed once for every value in its date field. If this isn't what you want, you can get around it by adding the date field to the View, turning on aggregation, and selecting an aggregation method that will make the date display only once (I used "minimum" for this view, but can't pretend I understand them all).]

Back to my use case. I ended up looping over the date field values, returning only those which are greater than now (i.e., in the future), pushing those values to a new array, and displaying the first item from that new array, i.e. the next date:

// Create new empty array to push future values to
{% set future_dates = [] %}

// Loop over all date field values; if they are greater than now, push them to the future_dates array. Note that Twig does not have a "push" filter; it's called "merge":
{% for key in row._entity.field_event_dates|keys %}
    {% if row._entity.field_event_dates[key].value > now|date('U') %}
        {% set future_dates = future_dates|merge([row._entity.field_event_dates[key].value]) %}
    {% endif %}
{% endfor %}

// Create variables from the first item of the future_dates array for display. I had to display the date and time separately, hence two variables:
{% set next_date = future_dates[0]|date('F d, Y') %}
{% set next_time = future_dates[0]|date('h:i A T') %}

Notes:

  • Items from arrays won't print in Twig without some kind of filter. I was driving myself crazy trying to get this to work for way too much time, forgetting I couldn't just print the future_dates array in Twig. You have to use the |join filter at a minimum. Here, the |date filter is converting the array item value into a format that can be displayed in the template.
  • now|date('U') creates a Unix timestamp from the current date and time for comparison with the Unix timestamp value of the date field.
  • I am using the value value to get the start date of each occurrence; you would of course use one of the different values if you need that.

Tags:

Comments

Thank you for posting this, it saves me tons of time trying to access the values. :)

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.