1

I need to output a list of channel authors. There are about 40 authors but I want the 8 authors with the most entries. Not sure how to achieve this.

What I have so far:

    {# get all the itbuzz entries #}
    {% set allEntries = craft.entries.section('itbuzz').all() %}
    {# get all the authors #}
    {% set authors = craft.users.group('itBuzzAuthor').limit(8).all() %}

    <ul class="flex flex-row flex-wrap">
      {% for author in authors %}
        <li class="inline-block mb-4 mr-4 text-sm text-center">
          <img src="{{ craft.gravatar.url( author.email ) }}" alt="">
          <a href="#" class="text-blackBrand">{{ author.firstName }}<br>{{ author.lastName }}</a>
        </li>
      {% endfor %}
    </ul>

All this does is output the first 8 authors, it's not finding the 8 with the most entries.

2 Answers 2

2

You could do something like this:

{# Fetch entries + authors and group by author id #}
{% set entriesByAuthors = craft
    .entries()
    .section('itbuzz')
    .limit(null)
    .with('author')
    .all() | group(e => e.author.id) %}

{# Build an array with authorId and entry count for each that we can sort them #}
{% set leaderBoard = [] %}
{% for author, entries in entriesByAuthors  %}
    {% set leaderBoard = leaderBoard | merge([{'author' : author, 'count' : entries | length}]) %}
{% endfor %}

{# Build an array of user ids only sorted by entry count and extract the top 8 #}
{% set authorIds = [] %}
{% for result in leaderBoard | multisort(e => e.count, direction=SORT_DESC) | slice(0,8) %}
    {% set authorIds = authorIds | merge([result.author]) %}
{% endfor %}

{# Fetch users based on our sorted and sliced array of ids #}
{% for author in craft.users().id(authorIds).all() %}
    {{ author.firstName }} - {{ author.lastName }}<br>
{% endfor %}
1
  • Oli, this works perfectly, thank you. I"m not sure what's going on in with .with(author) and the |group filter. Could you explain that a little for me. Thank you.
    – CreateSean
    Commented Mar 4, 2020 at 14:36
1

Maybe a good excuse to use the spaceship operator (<=>)... Combined with the group filter, this seems to work for me:

{% set groupedEntries = craft.entries.section('itbuzz').all()|group('author') %}

{% for author, entries in groupedEntries|sort((a, b) => a|length <=> b|length)|reverse|slice(0,8) %}
    <h3>{{ author }}</h3>
    {# optionally output their entries too... #}
    <ul>
        {% for entry in entries %}
            <li>{{ entry.title }}</li>
        {% endfor %}
    </ul>
{% endfor %}
3
  • Thought of that but the simple fact of grouping means you loose your user object and Sean seems to need to access author.stuff ¯_(ツ)_/¯
    – Oli
    Commented Mar 4, 2020 at 10:05
  • Ah ha good point yerp. Commented Mar 4, 2020 at 10:06
  • That sort filter - wow, I would never have thought of that.
    – CreateSean
    Commented Mar 4, 2020 at 14:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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