Skip to content

Instantly share code, notes, and snippets.

@jeromecoupe
Last active November 2, 2020 18:10
Show Gist options
  • Save jeromecoupe/c958c1c6600d37cd7a4fe5cc630734a7 to your computer and use it in GitHub Desktop.
Save jeromecoupe/c958c1c6600d37cd7a4fe5cc630734a7 to your computer and use it in GitHub Desktop.
Probably not a good idea: normalize array of objects in Craft
{# variables #}
{% set allNews = [] %}
{% set today = "now"|date("Y-m-d") %}
{# create custom allNews array of objects #}
{% set news = craft.entries()
.section(["news"])
.with([
"newsImage"
])
.orderBy("postDate DESC")
.limit(8)
.all() %}
{% for item in news %}
{% set thumbSmall = item.newsImage[0].getUrl({ width: 600, height: 450 }) ?? null %}
{% set thumbMedium = item.newsImage[0].getUrl({ width: 800, height: 600 }) ?? null %}
{% set allNews = allNews|merge([{
thumbSmall: thumbSmall,
thumbMedium: thumbMedium,
title: item.commonTitle,
url: item.url,
displayDate: item.postDate|date("Y-m-d"),
sortDate: item.postDate|date("U"),
typeFormatted: "News",
cssClass: "c-news--news"
}]) %}
{% endfor %}
{% set events = craft.entries()
.section(["events"])
.with([
"eventsImage"
])
.orderBy("eventStartDate DESC")
.eventEndDate(['and', ">= #{today}"])
.limit(8)
.all() %}
{% for item in events %}
{% set thumbSmall = item.eventImage[0].getUrl({ width: 600, height: 450 }) ?? null %}
{% set thumbMedium = item.eventImage[0].getUrl({ width: 800, height: 600 }) ?? null %}
{% set allNews = allNews|merge([{
thumbSmall: thumbSmall,
thumbMedium: thumbMedium,
title: item.commonTitle,
url: item.url,
displayDate: item.eventStartDate|date("Y-m-d"),
sortDate: item.eventStartDate|date("U"),
typeFormatted: "Event",
cssClass: "c-news--event"
}]) %}
{% endfor %}
{% set videos = craft.entries()
.section(["videos"])
.with([
"videoImage"
])
.orderBy("postDate DESC")
.limit(8)
.all() %}
{% for item in videos %}
{% set thumbSmall = item.eventImage[0].getUrl({ width: 600, height: 450 }) ?? null %}
{% set thumbMedium = item.eventImage[0].getUrl({ width: 800, height: 600 }) ?? null %}
{% set allNews = allNews|merge([{
thumbSmall: thumbSmall,
thumbMedium: thumbMedium,
title: item.commonTitle,
url: item.url,
displayDate: item.postDate|date("Y-m-d"),
sortDate: item.postDate|date("U"),
typeFormatted: "Vidéo",
cssClass: "c-news--video"
}]) %}
{% endfor %}
{# sort and slice #}
{% set allNews = allNews|sort((a, b) => a.sortDate < b.sortDate) %}
{% set allNews = allNews|slice(0,8) %}
{# display (@TODO: replace by a component using custom objects) #}
{% for item in allNews %}
<p>{{ item.displayDate }} - {{ item.typeFormatted }} - {{ item.title }}</p>
{% endfor %}
@jeromecoupe
Copy link
Author

I am just querying and displaying data here, so using Twig makes sense. However the template code gets messy ... so a module might be in order. But I am no PHP dev and maintaining a module over time triggers a few alarm bells.

@brettburwell
Copy link

brettburwell commented May 15, 2020

You might be able to dry this up a bit if you use the Empty Coalesce plugin.

That would allow you to do something like this:

{# variables #}
{% set newsEntries = [] %}
{% set normalizedNewsEntries = [] %}
{% set today = "now"|date("Y-m-d") %}

{# Grab news entries #}
{% set news = craft.entries()
  .section(["news"])
  .with([
    "newsImage"
  ])
  .orderBy("postDate DESC")
  .limit(8)
  .all() %}

{# Grab event entries #}
{% set events = craft.entries()
  .section(["events"])
  .with([
    "eventsImage"
  ])
  .orderBy("eventStartDate DESC")
  .eventEndDate(['and', ">= #{today}"])
  .limit(8)
  .all() %}

{# Grab video entries #}
{% set videos = craft.entries()
  .section(["videos"])
  .with([
    "videoImage"
  ])
  .orderBy("postDate DESC")
  .limit(8)
  .all() %}

{# Merge everything together #}
{% set newsEntries = allNews | merge(news, events, videos) %}

{# Loop through entries and set applicable content #}
{% for entry in newsEntries %}
  {% set thumb =  entry.newsImage[0] ???  entry.eventImage[0] ???  entry.videoImage[0] ??? null %}
  {% set thumbSmall = thumb.getUrl({ width: 600, height: 450 }) ??? null %}
  {% set thumbMedium = thumb.getUrl({ width: 800, height: 600 }) ??? null %}
  {% set date = entry.eventStartDate ??? entry.postDate  %}
  {% set entryType = entry.type.name %}
  {% set normalizedNewsEntries = normalizedNewsEntries|merge([{
     thumbSmall: thumbSmall,
     thumbMedium: thumbMedium,
     title: item.commonTitle,
     url: item.url,
     displayDate: date|date("Y-m-d"),
     sortDate: date|date("U"),
     typeFormatted: entryType | title,
     cssClass: "c-news--" ~ entryType
  }]) %}
{% endfor %}

{# sort and slice #}
{% set allNews = normalizedNewsEntries|sort((a, b) => a.sortDate < b.sortDate) %}
{% set allNews = normalizedNewsEntries|slice(0,8) %}

{# OUTPUT STUFF #}

This is quick and dirty and 100% untested... but I just wrapped a project where we had to take a fairly similar approach and it served us well.

@jeromecoupe
Copy link
Author

jeromecoupe commented May 15, 2020

@brettburwell yes that's another / cleaner approach, thank you for posting it. I now have a version where I just do one big for loop like you do with a switch / case on the entry type. Cleaner indeed.

@jeromecoupe
Copy link
Author

Got an event simpler way of dealing with that with the help of Brandon and by taking advantage of the possibility to use raw SQL in the order clause:

{% set eventSection = craft.app.sections.getSectionByHandle('events') %}
{% set today = 'now'|date_modify("-1 month")|date('Y-m-d') %}

{% set allNews = craft.entries()
  .section(['news', 'events', 'videos'])
  .eventEndDate(['or', ':empty:', ">= #{today}"])
  .orderBy(
    expression('(
      CASE
        WHEN sectionId = :eventSectionId THEN field_eventStartDate
        ELSE postDate
      END
    ) DESC', {
      eventSectionId: eventSection.id
    })
  )
  .with([
    'newsImage',
    'eventsImage',
    'videoImage',
  ])
  .all()
%}

@brettburwell
Copy link

Nice. That definitely tightens things up even more. Thanks for sharing @jeromecoupe!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment