{{craftSnippets}}
Home Articles Plugins Starter theme Components on Github Gists About
  • Home
  • Articles
  • Creating article excerpts with Twig component in Craft CMS
Posted on Jul 26, 2019 by Piotr Pogorzelski

Creating article excerpts with Twig component in Craft CMS

Article excerpts are an integral part of websites like blogs or portals. Learn how to create article excerpts using reusable and robust Twig component.
Table of contents:
  • Article excerpt component
  • Passing parameters to excerpt component
  • Component structure
  • Positioning of attributes

If you are dealing with blog or news portal, article excerpts may be used in multiple places - for example: on blog category page, in "see also" section of article, on homepage as "featured article", in sidebar as "latest articles", on author page as "articles written by author".

Now we are running into a problem. Excerpts in various places should display different properties of the article. Let's think of few examples - featured article on the homepage should display title, thumbnail and category. Excerpt on category page should not show category (we know what category we browse), just title and thumbnail. And sidebar with latest articles should contain only title to save place.

Each of these times, article excerpt should be handled by the same Twig component. Reusability and modularity of templates are important. In this article, I will describe how to create a reusable article excerpt Twig component.

Article excerpt component #

Here's an example of the article excerpt component. Depending on options passed to it, it will display different properties of the article - like title, thumbnail or text intro. These are not set in stone and you can add yours or modify existing HTML markup used for outputting article properties. What's important is overall structure of the component.

{% import '_system/macros' as m %}

{% if article is defined %}

{% set settingsDefault = {
    attributes: ['title'],
    truncateTitle: 60,
    truncateIntro: 20,
    transform: {
        width: 300,
        height: 200,
        format: 'jpg'
    }
} %}

{% set settings = settings|default(settingsDefault) %}
{% set settings = settingsDefault|merge(settings) %}

<div class="article-excerpt {{settings.class ?? null}}">

{% for attribute in settings.attributes %}

{% switch attribute %}

{# title #}
{% case 'title' %}
 <a href="{{article.url}}" class="article-excerpt__title">
    {{m.truncateChars(article.title, settings.truncateTitle)}}
</a>

{# date #}
{% case 'date' %}
{% if article['postDate'] is defined%}
<time class="article-excerpt__date" datetime="{{date|date('yy-m-d')}}">
    {{article.postDate|time('full')}}
</time>
{% endif %}

{# intro #}
{% case 'intro' %}
{% if article['intro'] is defined and article['intro'] is not empty %}
<div class="article-excerpt__intro">
    {{m.truncateChars(article['intro'], settings.truncateIntro)}}
</div>
{% endif %}

{# categories #}
{% case 'category' %}
{% if article['category'] is defined and article.category.exists() %}
    <a href="{{category.one().url}}" class="post-single__category">{{category.one().title}}</a>
{% endif %}

{# read more link #}
{% case 'more' %}
<a href="{{post.url}}" class="article-excerpt__more">
    {{'read_more'|t}}
</a>

{# thumbnail #}
{% case 'thumbnail' %}
{% if article['thumbnail'] is defined and article.thumbnail.exists() %}
<a href="{{article.url}}">
    <img src="{{article.thumbnail.getUrl(settings.transform)}}" class="article-excerpt__thumbnail">
</a>
{% endif %}

{% endswitch %}
{% endfor %}

</div>
{% endif %}

Here is how the article excerpt component should be used - it needs to be included with options passed to it:

{% for singleEntry in entries.all() %}
{% include 'article-excerpt' with {
    article: singleEntry,
    settings: {
        attributes: ['title', 'intro', 'more'],
        class: 'featured',
    }
} only %}
{% endfor %}

Passing parameters to excerpt component #

Article excerpt requires element object passed as an article to the component in order to display anything - usually, it would be single entry or category. It also needs options - to decide which article properties should be displayed and in what order.

If no options are provided, default ones defined inside the component are used. If you provide your options, they will be merged with default options - and your values will overwrite specific values in defaults. Therefore there is no need to always define all options - just these which you want to change from their default values.

Note the only keyword used in include tag - thanks to it we can isolate the component from outside variable context and prevent any unforeseen complications.

Here is the options list:

  • attributes - an array of article attributes to display. Order is taken into account. All possible attributes are listed within switch tag inside article excerpt component, with their names as case values.
  • truncateTitle - number of characters to which title of the element (article) should be truncated (if we want to display it). The component uses truncating macro described in this article, but you can switch to any other method. It's important to truncate text values - excessively long text might break our layout and we never know what content authors might type in.
  • truncateIntro - number of characters by which intro of the element should be truncated (if we want to display it).
  • transform - image transform settings for thumbnail - will be used if we want to display a thumbnail.
  • class - by using this option you can set an additional class on article excerpt to tweak it looks.

Component structure #

How does it work exactly? Let's take a closer look at Twig code.

First, we check if element is defined. If it is not, there is nothing to display. Then, there are default options and code that merges them with options provided when including component. Lastly, there is {% switch %} and {% for %} tag - thanks to it we can loop through elements and display them in the correct order.

Note that each element has if tag checking if such field/attribute of the article exists. Thanks to that, our component will be robust and won't throw errors in case someone uses it with an element that does not have a specific field/attribute. In the case of text values, we also check if text not empty. In case of element objects (like category or image) we use .exists() method to check if such an element exists.

One more thing worth noting is the usage of BEM CSS class notation. It's perfect for modular webpages.

Positioning of attributes #

The attributes order is decided by their order in elements array. What about the situation when we want to have two columns? For example, one column for thumbnail and second for other attributes like title, intro, and category.

Popular WordPress themes usually use position: absolute for that. This solution however, has disadvantages - you need to make sure that all attributes have proper positioning and don't overlap.

I recommend the usage of display: grid. Here is example setup:

.article-excerpt{
    display: grid;
    grid-template-columns:  [left] auto [right] auto;
    grid-template-rows:  auto;
    grid-column-gap:  1rem;
}

.article-excerpt__thumbnail{
    grid-column:  left;
    grid-row:  1/100;
}

.article-excerpt__title, .article-excerpt__intro, .article-excerpt__date{
    grid-column:  right;
}

There are two columns - left and right. Thanks to grid-template-rows: auto we don't need to explicitly set up a number of rows - this CSS is supposed to be universal and work properly regardless of how many attributes of the article we plan to display.

Thumbnail is on left column - and it stretches from row 1 to 100. 100 is just some large number that we are sure is bigger than the maximum amount of article properties that can be displayed. Thanks to that, properties on the right column will be properly displayed, stacking on top of each other - and their position will not depend on how big thumbnail is. I guess it can be called a bit of hack.


TAGS:
#twig #components
If you want to get latest updates on Craft CMS tutorials and components, follow me on Twitter or subscribe to RSS feed.
Articles on blog:
  • Frontend testing for Craft CMS websites with Codeception and Cypress
  • Building reactive Craft Commerce product page with Sprig plugin
  • Dynamically generated PDF attachments for Freeform submissions
  • Using template hooks in Craft CMS
  • Alpine JS modal component for Craft CMS
  • Using template UI elements to extend Craft CMS control panel
  • Matrix within a Matrix - possible solutions for Craft CMS
  • Universal email template for Craft CMS
  • Creating attributes table from entry fields in Craft CMS
  • Namespacing forms in Craft CMS
  • Creating map-based navigation for Craft CMS
  • Placeholder image macro for Craft CMS
  • Building AJAX contact form with Craft CMS
  • Using incognito field plugin for Craft CMS
  • Email footer creator made with Craft CMS
  • Infinite scrolling and lazy loading with Craft CMS
  • Using Javascript in Twig templates with Craft CMS
  • Twig templating tips and tricks for Craft CMS
  • Basic SEO functionality for Craft CMS
  • Working with dates in Craft CMS templates
  • Working with SVG images in Craft CMS templates
  • Responsive and lazy-loaded youtube videos with Craft CMS
  • Debugging and inspecting Twig templates in Craft CMS
  • Creating article excerpts with Twig component in Craft CMS
  • Adding favicons to Craft CMS website
  • Truncating text with Twig macros in Craft CMS
  • Universal language switcher for Craft CMS
  • Read time macro for Craft CMS
  • Using attr() function to render HTML attributes in Craft CMS
  • Building dynamic, AJAX based pagination for Craft CMS
  • How to add Disqus comments to Craft CMS website
  • Ellipsis pagination component for Craft CMS
  • Converting email addresses into links using Twig macro
  • Breadcrumb created from URL for Craft CMS
  • Best developer-oriented Craft CMS plugins
  • Search autocomplete component for Craft CMS
  • RSS feed - template component for Craft CMS
  • Testing emails sent by Craft CMS using Mailtrap
  • Quick edit link - Twig component for Craft CMS
  • Filtering entries in control panel using Searchit plugin
  • Fetching routes into Twig templates in Craft CMS


Frontend testing for Craft CMS websites with Codeception and Cypress

Building reactive Craft Commerce product page with Sprig plugin

Dynamically generated PDF attachments for Freeform submissions

Using template hooks in Craft CMS

Alpine JS modal component for Craft CMS

Using template UI elements to extend Craft CMS control panel

Matrix within a Matrix - possible solutions for Craft CMS

Universal email template for Craft CMS

Copyright ©2023 Piotr Pogorzelski