I have a section called Library, and a category group called libraryYears. The categories in that group are just years (2021, 2020, 2019...)

Each entry in the Library is related to a year in the libraryYears via a related Entries field called theYear.

I want to list all Library entries in order of the related year, so 2021 entries first, followed by 2020 entries, and so on. I don't need year headings, I just need them to be in order of year. But I also want to paginate them so there are only 10 per page.

I tried toying around with the group filter, but can't get it going with pagination.


For this kind of thing, I don't see much advantage of using a category relationship for the years (unless each category actually has further meta data or content held against it) - I'd probably just use a normal number field and get the editors to type in the year (or select from a pre-made dropdown if the range is reasonable)... But that doesn't help you much for your current situation.

How about using the Preparse plugin to populate a hidden field with the year from the chosen category on save? Then you can use a regular orderBy() parameter, which in turn will work with Craft's native pagination.

Alternatively you could use the group filter and then manually build some pagination functionality using segment logic, routes, and offset (or perhaps slice)... but that sounds like a really complex pain... I wouldn't even attempt that to be honest.

  • You know I think you're right that I should just convert these categories to a select field. I've imported them using FeedMe from an XML feed, so it shouldn't be too hard to pull in the values. Thanks. – Mike Mella Apr 20 at 12:56

You could sort using the multisort filter (docs) then paginate using Yii's ArrayDataProvider - see this post for reference.

{# Fetch your entries and order by theYear descending #}
{% set allEntriesByYear = craft.entries()
    .orderBy('postDate DESC')
    .all() | multisort(e => e.theYear[0], direction=SORT_DESC) %}

{# Create your custom pagination #}
{% set dataProvider = create({
    'class': 'yii\\data\\ArrayDataProvider',
    'allModels': allEntriesByYear,
    'pagination': {'pageSize': 4}}) %} {# Change this to the number you need per page #}

{% set results = dataProvider.getModels() %}

{% set currentPage = dataProvider.getPagination().getPage() + 1 %}
{% set totalPages = dataProvider.getPagination().getPageCount() %}

{% if currentPage > 1 %}
    {% set prevPage = currentPage - 1 %}
{% endif %}
{% if currentPage < totalPages %}
    {% set nextPage = currentPage + 1 %}
{% endif %}

{% if results | length %}
    {% for entry in results %}
        {{ entry.title }} - {{ entry.theYear[0] }}<br>
    {% endfor %}
{% endif %}
    {% if prevPage is defined %}
        <a href="{{ url(craft.app.request.absoluteUrl, {'q': craft.app.request.get('q'), 'page': prevPage}) }}">< Previous page</a>
    {% endif %}

    {% if nextPage is defined %}
        <a href="{{ url(craft.app.request.absoluteUrl, {'q': craft.app.request.get('q'), 'page': nextPage}) }}"> - Next page ></a>
    {% endif %}
  • Getting into Yii stuff is a little more than I wanted to do but this is a great suggestion. – Mike Mella Apr 20 at 12:57
  • Ah, fair enough :) – Oli Apr 20 at 13:32
  • This is really neat, being able to invoke the pagination functionality on an arbitrary array without a huge mass of complicated offsets/slicing. Will probably need this one day. – James Smith Apr 20 at 15:48

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.