0

This question is regarding HubSpot/HuBl, but I am also tagging twig as the syntaxes are similar.

I have a blog layout containing 7 cards and has the following structure:

enter image description here

For reference, the class modifiers for the above are:

  1. blogCard
  2. blogCard
  3. blogCard--long
  4. blogCard
  5. blogCard
  6. blogCard--wide
  7. blogCard

Now, in HubL, I'm trying to loop though posts and where the loop.index is equal to three, I want it to show a blog post which has the tag of video. This video post will appear in blogCard--long.

So all other 6 cards can show posts with any tag, but the 3rd (blogCard--long) must be a post with the tag of video.

To achieve this, I have tried the following:

<!-- get all posts from blog -->
{% set all_posts = blog_recent_posts(blog_id, 21) %}

<!-- find all posts with the tag "video" -->
{% set video_posts = blog_recent_tag_posts(blog_id, 'video') %}

<!-- remove video posts from all_posts array -->
{% set posts =  all_posts|difference(video_posts) %}

{% for post in posts %}

  <div class="blogCard"></div>

  {% if (loop.index == 3) %}
    {% for video_post in video_posts %}
      <div class="blogCard--long">{{ video_post.name }}</div>
    {% endfor %}
  {% endif %}

  <div class="blogCard"></div>

  {% if loop.index == 6 %}
   <div class="latestBlogs__blog--wide"></div>
  {% endif %}
 
  <div class="blogCard"></div>

{% endfor %}

I am essentially running the initial posts loop on all posts excluding those tagged with video. Then, when encountering the third item, I'm running a nested loop to obtain data from a video post. However, since it is a nested loop, it shows all of the video posts in one loop iterations. For example, if I have two posts that are tagged with video, on one iteration, it will show both those video posts.

Just looking to advice on the logic I'm applying here and what the best way would be to achieve this?

Freddy
  • 683
  • 4
  • 35
  • 114
  • As seen in the [documentation](https://developers.hubspot.com/docs/cms/hubl/functions#blog-recent-tag-posts), you can specify a 3rd argument for `blog_recent_tag_posts`, which controls how many posts are returned – DarkBee Jun 04 '21 at 10:30
  • @DarkBee - How many posts are returned in `video_posts` is not really the issue, unless I'm missing something? I looking for a way to make the 3rd card pull from `video_posts` and then, when the main loop runs again, show the next video post (so no cards are showing the same content) – Freddy Jun 04 '21 at 12:42
  • Thought the issue you were having was that 2 video posts were shown? – DarkBee Jun 04 '21 at 15:13
  • @DarkBee - Yes that is happening. But, if I set a limit on `blog_recent_tag_posts` i.e. to `1`. When the loop runs again, it will show the same video post again – Freddy Jun 04 '21 at 15:18
  • Okay so basically you want to repeat the grid you have, because you can have more than 6 posts? – DarkBee Jun 04 '21 at 16:05
  • @DarkBee - So, one `slide` refers to 7 grid items (like in the image above). The number of `slides` rendered will depend on how many blog posts exist that have the tag `video`. So, if there are `three` blogs with the tag `video`, there will be `three slides`. In each single `slide`, the third card (`blogCard--long`) will always be a post that has the tag `video`. All other grid items are posts that don't have the tag `video`, but `blogCard--long` will always be a post tagged with `video`. Hopefully that makes sense? – Freddy Jun 04 '21 at 17:44

1 Answers1

1

After reading through the comments, you could use batch to repeat the grid. I would do something like the following:

{% for row in blogs|batch(6, '&nbsp;') %}
<div class="wrapper">
    {% for blog in row %}
        {% if loop.index == 3 %}
        <div class="long">
            {{ videos[loop.parent.loop.index0]|default }}
        </div>
        {% endif %}
        <div{% if loop.index == 5 %} class="wide"{% endif %}>
            {{ blog }}
        </div>
    {% endfor %}
</div>
{% endfor %}

demo

The first line, {% for row in blogs|batch(6, '&nbsp;') %} will turn your collection in an array of 6 items each, which you then can loop to create one full grid.

If the index equals 3 you then can "prepend" one video post. Here I use the loop variable from the first loop:

loop.parent.loop.index0

This index you then can use to fetch a video on that index, chained with the default filter if the videos is non-existent


    .wrapper {
        display: grid;
        grid-template-rows: 200px 200px 200px;
        grid-template-columns: 200px 200px 200px;
        grid-gap: 10px;
        margin: 0 0 20px;
    }

    .wrapper div {
        border-radius: 10px;
        background: #333333;
        color: #FFFFFF;
    }

    .wrapper .long {
        grid-row: span 2;
        grid-column: 3;
    }

    .wrapper .wide {
        grid-column: span 2;
    }
<div class="wrapper">
    <div>1</div>
    <div>2</div>
    <div class="long">vid1</div>
    <div>3</div>
    <div>4</div>
    <div class="wide">5</div>
    <div>6</div>
</div>

<div class="wrapper">
    <div>7</div>
    <div>8</div>
    <div class="long">vid2</div>
    <div>9</div>
    <div>10</div>
    <div class="wide">11</div>
    <div>12</div>
</div>

<div class="wrapper">
    <div>13</div>
    <div>14</div>
    <div class="long">vid3</div>
    <div>15</div>
    <div>16</div>
    <div class="wide">17</div>
    <div>18</div>
</div>
DarkBee
  • 16,592
  • 6
  • 46
  • 58