Does anyone know a proper way to DRY up an entry template so that it can dynamically become an item listing vs. an entry page? For a (non-working) example:

{% if item is defined %}{% else %}{% extends [entry.locale ~ "/layout", "_layout"] %}{% endif %}

Not sure why this isn’t working, but it would allow creating one template per section/type and then conditional output based on how you called it in a template, i.e. {% include "entry" with { "item": "small" }

Instead of having to create a separate template to output a smaller/truncated version of an item in a list.

1 Answer 1


Can't be done. In short, a template is either extending another template (i.e. it contains an {% extends %} tag anywhere in the code), or it doesn't. Twig doesn't permit the {% extends %} tag inside an {% if %} statement, which makes "conditional extending" impossible.

Using a ternary operation to conditionally select which template to extend is allowed, though:

{% extends item is defined ? "_item" : [entry.locale ~ "/layout", "_layout"] %}

Not sure how you apply the concept of {% extends %}, but personally, I very rarely have more than one "layout" template, and that layout template is fairly stark – usually it'll only contain the stuff that all pages across the site should have, i.e. the basic HTML structure (<html><head><body>, global header/footer etc) and global CSS/JavaScript). Sure, some designs require more layouts, but usually that's not where the DRY stuff happens – instead, I tend to use "partial" templates (and macros) a lot, to re-use markup.

Assuming your _layout.html contains the basic HTML framework for your site, and that the entry page and an entry inside a listing is basically the same thing (the former just displays more content), you could do something like this to create a template that works for both listings and single entries:

{# Template /news/index.html #}
{% extends '_layout.html' %}
{% block main %}
    {% if entry is defined %}
        {# Single entry #}
        {% include '_partials/entry' %}
    {% else %}
        {# Listing, pull entries and include the entry partial with a "teaser" flag #}
        {% set entries = craft.entries.section('news') %}
            {% for entry in entries %}
                <li>{% include '_partials/entry' with { teaser: true } %}</li>
            {% endfor %}
    {% endif %}
{% endblock %}

{# Template /_partials/entry.html #}
{% set isTeaser = teaser is defined and teaser %}
<article class="entry{{ isTeaser ? ' entry--teaser' }}">
    <h1>{{ entry.title }}</h1>
    {% if entry.thumbnail|length %}
        <img src="{{ entry.thumbnail.getUrl() }}" />
    {% endif %}
    <p class="excerpt">{{ entry.excerpt }}</p>
    {% if isTeaser %}
        {# Just a teaser – display a "Read more" link #}
        <a href="{{ entry.url }}">Read more</a>
    {% else %}
        {# Not a teaser – render the content in full #}
        {{ entry.body }}
    {% endif %}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.