Run for loop to show posts, but make 3rd card always show post with specific tag

655 Views Asked by At

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?

1

There are 1 best solutions below

0
On

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>