<p>This is probably pretty much the same code you already have, but I can't think of a more elegant solution:</p>

<pre><code>{% set relatedEntriesIds = craft.entries.section('news').relatedTo(entry).limit(8).ids() %}

{% if relatedEntriesIds|length &lt; 8 %}
    {% set moreRelatedEntriesIds = craft.entries.section('news').limit(8 - relatedEntries|length).ids() %}
    {% set relatedEntriesIds = relatedEntriesIds|merge([moreRelatedEntriesIds]) %}
{% endif %}

{% set relatedEntries = craft.entries.id(relatedEntriesIds).fixedOrder(true) %}
</code></pre>

CC BY-SA 3.0
2015-06-09T14:32:07.643Z
Yeah, I think this is about as clean as it gets, and a good solution. It's also a nice example of something that is probably better to handle with PHP in a [custom business logic plugin](https://github.com/lindseydiloreto/craft-businesslogic). Twig gets convoluted fairly quickly, even for something relatively simple as this.
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2015-06-09T14:42:03.090Z
Do you think it's possible to reduce the amount of DB queries with PHP / make performance better, @mmikkel? You'd still have these criteria models, or is something "complex" like this possible with custom DbCommands and a single query?
carlcs
CC BY-SA 3.0
2015-06-09T15:08:34.727Z
Probably _possible_ to do with one query, but also probably not worth the effort :) Possible performance gains aside, doing it in a plugin would make for a much cleaner template and more readable, isolated logic – both big wins in my book – even if the PHP solution would more or less "mirror" the Twig above. _Preference_ is also relevant here, of course. Personally I find complex Twig pretty hard to read (especially when/if it bleeds into the markup).
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2015-06-09T15:49:52.627Z
Looks like we're all ending up in the same place… I'll keep running with this approach. Thanks.
philzelnar
CC BY-SA 3.0
2015-06-09T14:20:34.363Z
2015-06-09T14:20:34.363Z
carlcs
<p>it's now 2024 and I'm wondering what the best way to do this is.</p>
<p>Example Setup: News Article (with an entries field for 'Categories')</p>
<p>Desired result: Show 3 related (by 'category') entries, if not get any other news entry to fill up to 3.</p>
<p>Edit: I think I might have cracked it:</p>
<pre><code>{% set relatedEntriesIds = craft.entries()
  .section('news')
  .relatedTo({
    targetElement: entry.newsCategory,
    field: 'newsCategory'
  })
  .id('not ' ~ entry.id)
  .limit(3)
  .ids()
%}

{% if relatedEntriesIds|length &lt; 3 %}
    {% set moreRelatedEntriesIds = craft.entries.section('news').id('not ' ~ entry.id).limit(3).ids() %}
    {% set relatedEntriesIds = relatedEntriesIds|merge(moreRelatedEntriesIds)|unique %}
{% endif %}

{% set relatedEntries = craft.entries.id(relatedEntriesIds).limit(3).all() %}
</code></pre>
<p>Previous very verbose code solution:</p>
<pre><code>{# First get any articles with the same category #}
{% set articleRelatedArticlesQuery = craft.entries()
  .section('news')
  .limit(3)
  .id('not ' ~ entry.id)
  .relatedTo({
    targetElement: entry.newsCategory.all(),
    field: 'newsCategory',
  }) %}

{# Grab their IDs #}
{% set articleRelatedArticlesIDs = articleRelatedArticlesQuery.ids() ??? null %}

{# Are there less than 3? If so, we need fallback articles #}
{% if articleRelatedArticlesQuery.count() &lt; 3 %}

  {% set fallbackArticlesQuery = craft.entries()
    .section('news')
    .id('not ' ~ entry.id)
    .limit(3)
  %}

  {# If there are _any_ related matching entries, make sure they are removed from the fallback query #}
  {% if articleRelatedArticlesIDs %}

    {# Format the string to exlude the IDs #}
    {% set relatedArticleExclusionString = articleRelatedArticlesIDs|join(', not ') ??? null %}

    {# Update the query #}
    {% do fallbackArticlesQuery.id(&quot;and, not #{entry.id}, not #{relatedArticleExclusionString}&quot;) %}

    {# Grab the Fallback IDs #}
    {% set fallbackArticlesIDs = fallbackArticlesQuery.ids() ??? null %}

    {# Now merge the two sets of IDs #}
    {% set articleRelatedArticlesIDs = articleRelatedArticlesIDs|merge(fallbackArticlesIDs) ??? null %}

  {% else %}

    {% set articleRelatedArticlesIDs = fallbackArticlesQuery.ids() ??? null %}

  {% endif %}

{% endif %}

{# Now grab the related articles #}
{% set articleRelatedArticles = craft.entries.section('news').limit(3).id(articleRelatedArticlesIDs).all() ??? null %}
</code></pre>
<p>Can anyone help me with some better code here?</p>

CC BY-SA 4.0
2024-05-23T11:52:31.827Z
2024-05-23T12:02:08.830Z
2024-05-23T12:02:08.830Z
Rob Hodges
<p>At the bottom of an entry I want to display links for eight other posts. To make this useful, what I'd like to do is:</p>

<ul>
<li><p>start with entries that are related to the post currently being viewed by category (generally there are 4-5 of these)</p></li>
<li><p>then fill in the remain slots with the other posts (not related by category), newest first</p></li>
</ul>

<p>Is there a simple-ish way to do this? I started down the path of separate queries, counting, and merging results but something about that feels more complicated that it should be. I'm wondering if this can be achieved via ordering or grouping?</p>

<p>Thanks in advance.</p>

<categories><ordering>
Entries Related by Category with Filler Entries After
# Entries Related by Category with Filler Entries After

(Asked by: username_0 on 2015-06-09)

At the bottom of an entry I want to display links for eight other posts. To make this useful, what I'd like to do is:

* start with entries that are related to the post currently being viewed by category (generally there are 4-5 of these)
* then fill in the remain slots with the other posts (not related by category), newest first

Is there a simple-ish way to do this? I started down the path of separate queries, counting, and merging results but something about that feels more complicated that it should be. I'm wondering if this can be achieved via ordering or grouping?

Thanks in advance.

**Tags:** categories, ordering


---

## 2 answers

### Answer by username_1 on 2015-06-09. Score: 2 | Accepted answer

This is probably pretty much the same code you already have, but I can't think of a more elegant solution:
{% set relatedEntriesIds = craft.entries.section('news').relatedTo(entry).limit(8).ids() %}

{% if relatedEntriesIds|length < 8 %}
    {% set moreRelatedEntriesIds = craft.entries.section('news').limit(8 - relatedEntries|length).ids() %}
    {% set relatedEntriesIds = relatedEntriesIds|merge([moreRelatedEntriesIds]) %}
{% endif %}

{% set relatedEntries = craft.entries.id(relatedEntriesIds).fixedOrder(true) %}

> **Comments:**
> **username_2**: Yeah, I think this is about as clean as it gets, and a good solution. It's also a nice example of something that is probably better to handle with PHP in a [custom business logic plugin](https://github.com/lindseydiloreto/craft-businesslogic). Twig gets convoluted fairly quickly, even for something relatively simple as this.  
> **username_1**: Do you think it's possible to reduce the amount of DB queries with PHP / make performance better, @mmikkel? You'd still have these criteria models, or is something "complex" like this possible with custom DbCommands and a single query?  
> **username_2**: Probably _possible_ to do with one query, but also probably not worth the effort :) Possible performance gains aside, doing it in a plugin would make for a much cleaner template and more readable, isolated logic – both big wins in my book – even if the PHP solution would more or less "mirror" the Twig above. _Preference_ is also relevant here, of course. Personally I find complex Twig pretty hard to read (especially when/if it bleeds into the markup).  
> **username_0**: Looks like we're all ending up in the same place… I'll keep running with this approach. Thanks.  

---

### Answer by username_3 on 2024-05-23. Score: 1

it's now 2024 and I'm wondering what the best way to do this is.
Example Setup: News Article (with an entries field for 'Categories')
Desired result: Show 3 related (by 'category') entries, if not get any other news entry to fill up to 3.
Edit: I think I might have cracked it:
{% set relatedEntriesIds = craft.entries()
  .section('news')
  .relatedTo({
    targetElement: entry.newsCategory,
    field: 'newsCategory'
  })
  .id('not ' ~ entry.id)
  .limit(3)
  .ids()
%}

{% if relatedEntriesIds|length < 3 %}
    {% set moreRelatedEntriesIds = craft.entries.section('news').id('not ' ~ entry.id).limit(3).ids() %}
    {% set relatedEntriesIds = relatedEntriesIds|merge(moreRelatedEntriesIds)|unique %}
{% endif %}

{% set relatedEntries = craft.entries.id(relatedEntriesIds).limit(3).all() %}

Previous very verbose code solution:
{# First get any articles with the same category #}
{% set articleRelatedArticlesQuery = craft.entries()
  .section('news')
  .limit(3)
  .id('not ' ~ entry.id)
  .relatedTo({
    targetElement: entry.newsCategory.all(),
    field: 'newsCategory',
  }) %}

{# Grab their IDs #}
{% set articleRelatedArticlesIDs = articleRelatedArticlesQuery.ids() ??? null %}

{# Are there less than 3? If so, we need fallback articles #}
{% if articleRelatedArticlesQuery.count() < 3 %}

  {% set fallbackArticlesQuery = craft.entries()
    .section('news')
    .id('not ' ~ entry.id)
    .limit(3)
  %}

  {# If there are _any_ related matching entries, make sure they are removed from the fallback query #}
  {% if articleRelatedArticlesIDs %}

    {# Format the string to exlude the IDs #}
    {% set relatedArticleExclusionString = articleRelatedArticlesIDs|join(', not ') ??? null %}

    {# Update the query #}
    {% do fallbackArticlesQuery.id("and, not #{entry.id}, not #{relatedArticleExclusionString}") %}

    {# Grab the Fallback IDs #}
    {% set fallbackArticlesIDs = fallbackArticlesQuery.ids() ??? null %}

    {# Now merge the two sets of IDs #}
    {% set articleRelatedArticlesIDs = articleRelatedArticlesIDs|merge(fallbackArticlesIDs) ??? null %}

  {% else %}

    {% set articleRelatedArticlesIDs = fallbackArticlesQuery.ids() ??? null %}

  {% endif %}

{% endif %}

{# Now grab the related articles #}
{% set articleRelatedArticles = craft.entries.section('news').limit(3).id(articleRelatedArticlesIDs).all() ??? null %}

Can anyone help me with some better code here?


---

