CMS Development

M0zz0
Participant | Diamond Partner
Participant | Diamond Partner

Get blog posts that contains all tags selected

Hi,

 

I'm trying to build a custom module that allow me to retrieve the last 2 blog posts that contains all tags that I select, so for example if I select "tag A" and "tag B" only posts that contains both those tags needs to be returned. Until now I was using the function blog_recent_tag_posts() but this function returns me blog posts that contains at least one of those tags, so even a post that contains only "tag A" is returned. I tried writing some code down to make this but looks like something is not working correctly, here's my code:

{% set posts = blog_recent_posts('default-blog', 200) %}
{% set tags_size = module.tags|length %}
{% for post in posts %}
{% set post_check = 0 %}
   {% for tag in post.tag_list %}   
      {% if module.tags is containing tag.slug %}
        {% set post_check = post_check + 1 %}
      {% endif %}
   {% endfor %}
   {{post_check}}
  {% if post_check|length == tags_size %}
    <div class="post-item span6">
  <a class="post-image-wrapper" href="{{post.absolute_url}}">
    <div class="post-image" style="background-image:url('{{ post.featured_image }}'); background-size: cover; background-repeat: no-repeat; background-position: center center;"></div>
  </a>
    <div class="post-description">
      {% for tag in post.tag_list %}
        {% if tag.slug == module.tags[0] %}
        <div class="box-tag"><a href="http://blog.silikomart.com/houseware/tag{{ tag.slug }}">{{ tag.name }}</a></div>
        {% endif %}
      {% endfor %}
      <div class="related-title"><a href="{{post.absolute_url}}"><h3>{{ post.name}}</h3></a></div> 
      <div class="post-excerpt"><p>{{ post.post_body|safe|striptags|truncate(150, False, '...')}}</p></div>
      <a class="read-more" href="{{post.absolute_url}}">LEGGI DI PIU'</a>
    </div>
</div>
  {% endif %}
{% endfor %}

Here's what I'm doing:
I'm retrieving the last 200 posts, I create a variable called tags_size that stores the number of tags I selected on my custom module (so with "tag A" and "tag B" this variable is = 2), for every post I set a variable called post_check that I first set at 0, for each tag in the post, if it's one of those tags that I selected on my module, the variable post_check is increased by one, so if every tag is found, this variable will be equal to the tags_size variable I declared at the beginning and that post can be returned, sadly this is not working as the variable post_check at the end is always equal to 0, if insted of using :

{% set post_check = post_check + 1 %}

I use:

{{ post_check + 1 }}

the result is that a set of true and number will be printed on the page.
What am I doing wrong? Is there an easier way to achieve this?

Thanks in advance

0 Upvotes
2 Replies 2
lscanlan
HubSpot Alumni
HubSpot Alumni

Get blog posts that contains all tags selected

Hi @M0zz0,

 

Did you ever find a solution here? I just came across your post and noticed you didn't get a response and I'd like to help if I can. One thing I'd point out first of all is that variables in HubL are loop-scoped. Maybe our documentation describes it a bit more eloquently: https://designers.hubspot.com/docs/hubl/hubl-variables-and-macros-syntax#variables-within-loops.

 

So typically what I'll do then is to run code that I need within a loop, but within the last iteration of a loop. So take a look below. I've re-written your HTML into a macro (you can read our docs, but it's basically a function: https://designers.hubspot.com/docs/hubl/hubl-variables-and-macros-syntax#macros) so that the overall logic is easier to see. But take a look at what I'm doing:

 

{# define a macro named post_item #}
{% macro post_item(post) %}
  <div class="post-item span6">
    <a class="post-image-wrapper" href="{{ post.absolute_url }}">
      <div class="post-image" style="background-image:url('{{ post.featured_image }}'); background-size: cover; background-repeat: no-repeat; background-position: center center;"></div>
    </a>
    <div class="post-description">
      {% for tag in post.tag_list %}
        {% if tag.slug == module.tags[0] %}
          <div class="box-tag"><a href="http://blog.silikomart.com/houseware/tag{{ tag.slug }}">{{ tag.name }}</a></div>
        {% endif %}
      {% endfor %}
      <div class="related-title"><a href="{{ post.absolute_url }}"><h3>{{ post.name}}</h3></a></div> 
      <div class="post-excerpt"><p>{{ post.post_body|safe|striptags|truncate(150, False, '...')}}</p></div>
      <a class="read-more" href="{{ post.absolute_url }}">LEGGI DI PIU'</a>
    </div>
  </div>
{% endmacro %}

{% set posts = blog_recent_posts('default-blog', 200) %}
{% set tags_size = module.tags|length %}

{% for post in posts %}
  
  {# for each post, we're creating a variable named post_check and (re-)setting its value to 0 #}
  {% set post_check = 0 %}

  {# loop through the post's tag list #}
  {% for tag in post.tag_list %}
    
    {# if we find one of the tags we're looking for, increment post_check by 1 #}
    {% if module.tags is containing tag.slug %}
      {% set post_check = post_check + 1 %}
    {% endif %}

    {# on the last loop iteration of the tag_list, and after we've run the tag logic for that loop iteration #}
    {% if loop.last %}
      {# now we'll run our macro if post_check is the right length #}
      {% if post_check|length == tags_size %}
        {{ post_item(post) }}
      {% endif %} {# end if post_check|length == tags_size #}
    {% endif %} {# end if loop.last #}

  {% endfor %} {# end for tag in post.tag_list #}

{% endfor %} {# end for post in posts #}

So keep in mind that this is mostly just me thinking through this. I haven't actually tested my logic out, although this method of using variable values in the last iteration of a loop has worked for me before. I have a few questions for you though. Are you sure that you'll find the number of posts that you need within the 200 most recently published posts? And contrarily, if we find more than 2 posts with the selected tags, aren't we just printing them regardless of how many find? In that case, couldn't we be finding more than 2 posts that meet the tag criteria? I don't know if your code needs to be that robust here, but just something to keep in mind. For what it's worth, I think your post_check logic is pretty clever. And maybe I'd need to actually test out the logic, but those are just some questions I have, assuming I'm understanding the code correctly.

 

My original thought for building something like this would be to create 2 different dictionaries. One for posts that have Topic A (we'll call it Dict 1). And then a second dictionary for posts that have Topic B (we'll call it Dict 2). We'd also need to create a blank Dict 3. Then loop through all of the posts in Dict 1. In that loop, loop through the posts in Dict 2. If we find the post there, add it to Dict 3 (because we know it's in both Dict 1 and Dict 2). Then loop through all of the posts in Dict 2. Within that loop, loop through the posts in Dict 1. And if we find a match, add the post to Dict 3. Now we'd just need to du-duplicate based on something like the post ID, which you can do using the |unique filter: https://designers.hubspot.com/docs/hubl/hubl-supported-filters#unique. And then you'll have a dictionary of posts (without dupes) that have both tags A and B. And then you can sort it however you'd like, including by publish date.

 

If none of that helps, let me know. I'm also happy to tag in some other contributers who maybe have built something similar to this in the past.

 

 - Leland

Leland Scanlan

HubSpot Developer Support
M0zz0
Participant | Diamond Partner
Participant | Diamond Partner

Get blog posts that contains all tags selected

Hi Inscallan,

Thanks for your detailed response, I tried this but saldy this is still not working and nothing is being returned from the module, just to let you see why I needed just only two posts here's the section of the blog homepage where we need this functionality, here you can see 2 posts that contains a tag (or multiple tags) then a highligthed post, and then other 2 posts from a different tag or the same tag (in the module there's also an offset parameter so if we set the same tag as the module before, we can start retrieving posts starting for example from the 3rd last post).

As for now we decided to use just a single tag as this took too much time for such a non blocking feature, but would be cool anyway to see if we can make this work so in the future if this happens again we can face this problem easily.

P.S.: thanks for the macros information, never saw those but I will surely start to use them in my next projects!

Immagine.png

0 Upvotes