Category Group Based Tabs (Grouping Entries by Categories)

Problem

How to group entries, dynamically, using a category group. Useful for outputting category-based tabs.

Solution

Since this recipe was published, created a plugin to make this easier. Enjoy!

{% set entriesByCat = {} %}
{% set entries = craft.entries.section('media') %}
{% set cats = craft.categories.group('media') %}

{% for cat in cats %}
  {% set entries = entries.relatedTo(cat) %}
  {% if entries|length %}
    {% set entriesByCat = entriesByCat|merge({
      (cat.slug): entries
    }) %}
  {% endif %}
{% endfor %}

{% if cats|length %}
  <div class="Tabs">
    <ul class="Tabs-nav">
      {% for cat in cats %}
          <li><a href="#{{ cat.slug }}">{{ cat.title }}</a></li>
      {% endfor %}
    </ul>

    {% for catSlug, catEntries in entriesByCat %}
      <div id="{{ catSlug }}" class="Tabs-panel">
        {% for entry in catEntries %}
          <div>
            <time datetime="{{ entry.postDate.iso8601 }}">{{ entry.postDate.localeDate }}</time>
            <h3>{{ entry.title }}</h3>
            <a href="/{{ entry.uri }}">Full Article</a>
          </div>
        {% endfor %}
      </div>
    {% endfor %}
    
  </div>
{% endif %}

Discussion

It’s worth noting that using the group() filter won’t work for category fields, or anything else that doesn’t have a __toString() method (see this Stack Exchange question for details).

So this does not work:

{% set entries = craft.entries.section('media').find() %}
{% set entriesByCat = entries|group('mediaCategory.slug') %}