A flexible posts loop! (D.R.Y coding)

I’ve built a lot of stuff using L&L while creating my own WP theme but one of the most useful and time-saving things was a flexible post loop that I use to display posts all over my websites. The template uses parameters (local variables) to flex to many common use cases.

You can see this in use on these websites:
https://cutloosecrew.com/
https://danaeripley.com/

Below are the basic instructions and code for recreating this handy posts loop.

Posts Template Logic

Create a template called ‘Section - Posts’ with this HTML:

<!--Section - Posts-->

<!--Set layout class-->
<If check="{Get local=layout}" is value="1">
    <Set local="layout_class">layout-1 grid-cols grid-md-col-2 grid-lg-col-3</Set>
    <Else check="{Get local=layout}" is value="2" />
    <Set local="layout_class">layout-2 grid-cols-inner grid-md-col-2</Set>
    <Else />
    <p>Variable 'layout' not configured.</p>
</If>

<!--Posts loop-->
<div class="section posts {Get local=layout_class}">
    <Loop type="{Get local=post}" taxonomy="{Get local=taxonomy}" terms="{Get local=terms}" count="{Get local=count}" orderby="{Get local=orderby}" order="{Get local=order}" exclude="{Get local=exclude}">
        <!--Item-->
        <div class="posts-item">
            <!--Image-->
            <div class="image posts-image">
                <a href="{Field url}" target="_self" rel="noopener">
                    <img src="{Field image_url size=medium}" width="1600" height="900" alt="{Field image_alt}">
                </a>
            </div>
            <!--Content-->
            <div class="posts-content">
                <!--Title-->
                <div class="posts-title">
                    <h3 class="title posts-title">
                        <a href="{Field url}" target="_self" rel="noopener">
                            <Field title /></a>
                    </h3>
                </div>
                <!--Meta-->
                <div class="meta post-meta">
                    <span class="post-meta-author"><i aria-hidden="true" class="fa fa-user"></i>
                        <Field author_display_name /></span>
                    <span class="post-meta-date"><i aria-hidden="true" class="fa fa-calendar"></i>
                        <Field publish_date date_format="j M y" /></span>
                    <span class="post-meta-category">
                        <i aria-hidden="true" class="fas fa-tags"></i>
                        <Taxonomy category>
                            <a href="{Field url}" target="_self" rel="noopener">
                                <Term title /></a>
                        </Taxonomy>
                    </span>
                </div>
                <!--Excerpt-->
                <div class="posts-excerpt">
                    <p>
                        <Field excerpt auto="true" words="30" more="..." />
                    </p>
                </div>
                <!--Actions-->
                <div class="posts-actions">
                    <!--Button-->
                    <a href="{Field url}" target="_self" rel="noopener">
                        <button>
                            <span class="button-title">Read more</span>
                        </button>
                    </a>
                </div>
            </div>
        </div>
    </Loop>
</div>

Posts Template SCSS

To enable the layouts add this SCSS under the Styles tab (Credit to @julia):

// Grid - Breakpoints
$breakpoints: (
  xs: "0",
  sm: "576px",
  md: "768px",
  lg: "1025px",
  xl: "1200px",
);

// Grid - Default
.site .grid-cols::before {
  display: none;
}
.grid-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  -webkit-column-gap: 1rem;
  -moz-column-gap: 1rem;
  column-gap: 1rem;
  row-gap: 1rem;
}
@each $key, $value in $breakpoints {
  @media screen and (min-width: #{$value}) {
    .grid-cols.grid-#{$key}-col-1 {
      grid-template-columns: minmax(0, 1fr);
    }
    .grid-cols.grid-#{$key}-col-2 {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .grid-cols.grid-#{$key}-col-3 {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
    .grid-cols.grid-#{$key}-col-4 {
      grid-template-columns: 1fr 1fr 1fr 1fr;
    }
    .grid-cols.grid-#{$key}-col-5 {
      grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
    }
    .grid-cols.grid-#{$key}-col-6 {
      grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
    }
  }
}

// Grid - Direct Descendents
.grid-cols-inner>* {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  -webkit-column-gap: 1rem;
  -moz-column-gap: 1rem;
  column-gap: 1rem;
  row-gap: 1rem;
}
@each $key, $value in $breakpoints {
  @media screen and (min-width: #{$value}) {
    .grid-cols-inner.grid-#{$key}-col-1>* {
      grid-template-columns: minmax(0, 1fr);
    }
    .grid-cols-inner.grid-#{$key}-col-2>* {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .grid-cols-inner.grid-#{$key}-col-3>* {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
    .grid-cols-inner.grid-#{$key}-col-4>* {
      grid-template-columns: 1fr 1fr 1fr 1fr;
    }
    .grid-cols-inner.grid-#{$key}-col-5>* {
      grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
    }
    .grid-cols-inner.grid-#{$key}-col-6>* {
      grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
    }
  }
}

Displaying Posts

To display posts call the Section - Posts template with your required parameters:

<!--Blog Posts-->
<Template name="section-posts" post="post" taxonomy="category" terms="news,music,events" count="6" orderby="date" order="desc" exclude="0" layout="1" />

NB. Please update terms="..." to your required post categories.

Some notes:

  • I am unable to provide the full CSS for styling as I use a lot of CSS variables.
  • You must enable Font Awesome 4 support for the meta icons to display.
  • You can exclude the current post with exclude="{Field id}" which is useful when creating a ‘More posts…’ feature for a single post.
  • There are currently two layouts layout="1" and layout="2".
  • The layout options can be tweaked under <!--Set layout class-->.

One thing that is missing from this solution is a variable to enable pagination which would be useful when using this for category and tag pages with many posts.

I am just a hobbyist developer so this code probably needs a review and I’d love to hear of any improvements from others. :slight_smile:

4 Likes

You could probably handle the pagination logic by creating your loop with a query variable!

<!--Section - Posts-->

<!--Set layout class-->
<If check="{Get local=layout}" is value="1">
    <Set local="layout_class">layout-1 grid-cols grid-md-col-2 grid-lg-col-3</Set>
    <Else check="{Get local=layout}" is value="2" />
    <Set local="layout_class">layout-2 grid-cols-inner grid-md-col-2</Set>
    <Else />
    <p>Variable 'layout' not configured.</p>
</If>
<If check="{Get local=paginate}">
  <Set query=post_loop type="{Get local=post}" taxonomy="{Get local=taxonomy}" terms="{Get local=terms}" count="{Get local=count}" orderby="{Get local=orderby}" order="{Get local=order}" exclude="{Get local=exclude}" exclude="{Get local=exclude}" paged="{Get local=paginate}" />
<Else />
  <Set query=post_loop type="{Get local=post}" taxonomy="{Get local=taxonomy}" terms="{Get local=terms}" count="{Get local=count}" orderby="{Get local=orderby}" order="{Get local=order}" exclude="{Get local=exclude}" exclude="{Get local=exclude}" />
</If>

<!--Posts loop-->
<div class="section posts {Get local=layout_class}">
    <Loop query=post_loop>
        <!--Item-->
        <div class="posts-item">
           ...
        </div>
    </Loop>
    <If check="{Get local=paginate}">
      <PaginateButtons />
    </If>
</div>

You’d probably need to modify the layout class logic to apply grid-cols-inner when pagination is active as well

1 Like