Mix two HubSpot blogs in one listing ordered by publish date (HubL)

Hi! I’m building an aggregated listing page in HubSpot CMS where I pull posts from two different blogs using:

  • case_posts = blog_recent_posts(case_studies_blog_id, 200)
  • insight_posts = blog_recent_posts(insights_blog_id, 200)

Right now they render in two separate loops, so they are grouped by blog. I need them mixed together and sorted by publish date (newest first).

I’m running into HubL errors when trying to sort/merge, and I suspect it’s because I’m using the wrong date property on the post object in this context.

Questions:

  1. What is the correct property to use for the publish date on objects returned by blog_recent_posts()?
    Is it post.publish_date, post.publishDate, post.published_at, post.created, or something else?
  2. What type/format is that field (integer timestamp vs string date)?
  3. Is there a recommended HubL approach to merge and sort posts from two blogs by date?
    If not, what’s the recommended client-side approach (e.g., adding a data-* attribute) without causing HubSpot template errors?

Extra info:

  • Using a custom grid + JS filtering/pagination based on data-type and data-tags.
  • I can add additional data-* attributes per post if needed.

Any guidance or examples would be appreciated.

{# debug: show available fields #}
<pre>{{ case_posts[0]|tojson }}</pre>

Thank you for posting @LautaroGriguelo!

I want to share a few HubSpot developer resources that directly address the questions you’re running into:

https://developers.hubspot.com/docs/cms/reference/hubl/variables

https://developers.hubspot.com/docs/cms/reference/hubl/functions

There’s also an alternative approach here:

Finally, I’m going to tag a few community experts who may have more insights. Hey there @Anton @Josh and @TomM2 — hope you’re having a great week! Any additional ideas here?

Thanks!
Victor

Hey @LautaroGriguelo,

to combine two blogs into one listing, I’d build the module like this

{% set case_posts = blog_recent_posts(case_studies_blog_id, 200) %}
{% insight_posts = blog_recent_posts(insights_blog_id, 200) %}

{% set all_posts = blog_recent_posts(case_studies_blog_id, 200) ~ blog_recent_posts(insights_blog_id, 200)|sort(false, false, "publish_date") %}

...

{% for single_post in module.all_posts %}
<span class="title">{{ single_post.title }}</span>
<span class="publish-date">{{ single_post.publish_date|format_datetime('MM/YYYY') }}</span> {# info: the datetime format is completely up to you #}
<span class="post-body">{{ single_post.post_body|striptags|truncatehtml(150) }}</span>
{% endfor %}

the documentation might be a bit misleading here, as it refers to the default blog loop

{% for content in content %}
<span class="title">{{ content.title }}</span>
<span class="publish-date">{{ content.publish_date|format_datetime('MM/YYYY') }}</span> {# info: the datetime format is completely up to you #}
<span class="post-body">{{ content.post_body|striptags|truncatehtml(150) }}</span>
{% endfor %}

but:

To get the post date of every post, it’s always build like “what ever name is set after the ‘for’ in the for-loop replaces ‘content’”.

If you look at my first code example, you’ll see I’ve called it single_post. Therefore I’m using

{{ single_post.post_date }}

If I’d written the for loop like

{% for my_individual_post_information_for_a_posts in module.all_posts %}
...
{% endfor %}

it would be

{{ my_individual_post_information_for_a_post.post_date }}

Something like

{% for i in module.all_posts %}
...
{% endfor %}

would result in

{{ i.post_date }}

My recommendation is to keep it short but understandable.

As for combining two blogs into one - In my first code example it’s defined like

{% set all_posts = blog_recent_posts(case_studies_blog_id, 200) ~ blog_recent_posts(insights_blog_id, 200)|sort(false, false, "publish_date") %}

{% for single_post in module.all_posts %}
...
{% endfor %}

in this example (and the way to go) you’re creating basically an object which contains both (or more) blog_recent_posts() functions

Hope this helps

best,

Anton