Eleventy: Double-layered pagination?

Created on 6 Dec 2018  路  7Comments  路  Source: 11ty/eleventy

I'm creating a blog. Each post are tagged. I've created each tag with the zero maintenance tag pages tip.

But each tag can potentially contain lots of posts. Can Eleventy create paginated tag pages?

EG:

  1. /tags/tag1/
  2. /tags/tag1/page2
  3. /tags/tag1/page3
  4. /tags/tag2/
  5. /tags/tag2/page2
  6. /tags/tag3/

And so on.

education

Most helpful comment

This is a fascinating idea鈥擨鈥檝e been mulling it over since you posted it.

I think you can do this, but you would have to flatten your custom collection to a single layer to do it.

Use custom collections: https://www.11ty.io/docs/collections/#advanced%3A-custom-filtering-and-sorting.

Here鈥檚 how it would work:

// note that this uses the lodash.chunk method, so you鈥檒l have to require that
eleventyConfig.addCollection("doublePagination", function(collection) {
    // Get unique list of tags
    let tagSet = new Set();
    collection.getAllSorted().map(function(item) {
        if( "tags" in item.data ) {
            let tags = item.data.tags;

            // optionally filter things out before you iterate over?
            for (let tag of tags) {
                tagSet.add(tag);
            }

        }
    });

    // Get each item that matches the tag
    let paginationSize = 3;
    let tagMap = [];
    let tagArray = [...tagSet];
    for( let tagName of tagArray) {
        let tagItems = collection.getFilteredByTag(tagName);
        let pagedItems = lodashChunk(tagItems, paginationSize);
        // console.log( tagName, tagItems.length, pagedItems.length );
        for( let pageNumber = 0, max = pagedItems.length; pageNumber < max; pageNumber++) {
            tagMap.push({
                tagName: tagName,
                pageNumber: pageNumber,
                pageData: pagedItems[pageNumber]
            });
        }
    }

    /* return data looks like:
        [{
            tagName: "tag1",
            pageNumber: 0
            pageData: [] // array of items
        },{
            tagName: "tag1",
            pageNumber: 1
            pageData: [] // array of items
        },{
            tagName: "tag1",
            pageNumber: 2
            pageData: [] // array of items
        },{
            tagName: "tag2",
            pageNumber: 0
            pageData: [] // array of items
        }]
     */
    //console.log( tagMap );
    return tagMap;
});

and then in your template it might look like this:

pagination:
  data: collections.doublePagination
  size: 1
  alias: tag
permalink: /tags/{{ tag.tagName }}/{% if tag.pageNumber %}{{ tag.pageNumber + 1 }}/{% endif %}
---

{% for post in tag.pageData %}
  Iterate over the items.
{% endfor %}

Does that make sense?

All 7 comments

I don't think there's a straightforward way. There are a couple issues about this but I don't think a solution was found, without some custom modules/preprocessing.
https://github.com/11ty/eleventy/issues/294
https://github.com/11ty/eleventy/issues/308

_includes files can't use pagination in their own frontmatter.

But there's this idea from the docs (I haven't tried this approach for anything):
https://www.11ty.io/docs/permalinks/#ignore-the-output-directory

Basically, let Eleventy compile a file and output it to the _includes directory.
Then your other file will include the compiled file.

edit: This statement, specifically:

Writes to _includes/index.html even though the output directory is _site. This is useful for writing child templates to the _includes directory for re-use in your other templates.

If you give this a go and if it works, please let us know how it goes.

Another idea might be to add a custom collection that outputs the data you want. Essentially recreate all the tag page collections, but one entry per page, rather than one per tag.

This is a fascinating idea鈥擨鈥檝e been mulling it over since you posted it.

I think you can do this, but you would have to flatten your custom collection to a single layer to do it.

Use custom collections: https://www.11ty.io/docs/collections/#advanced%3A-custom-filtering-and-sorting.

Here鈥檚 how it would work:

// note that this uses the lodash.chunk method, so you鈥檒l have to require that
eleventyConfig.addCollection("doublePagination", function(collection) {
    // Get unique list of tags
    let tagSet = new Set();
    collection.getAllSorted().map(function(item) {
        if( "tags" in item.data ) {
            let tags = item.data.tags;

            // optionally filter things out before you iterate over?
            for (let tag of tags) {
                tagSet.add(tag);
            }

        }
    });

    // Get each item that matches the tag
    let paginationSize = 3;
    let tagMap = [];
    let tagArray = [...tagSet];
    for( let tagName of tagArray) {
        let tagItems = collection.getFilteredByTag(tagName);
        let pagedItems = lodashChunk(tagItems, paginationSize);
        // console.log( tagName, tagItems.length, pagedItems.length );
        for( let pageNumber = 0, max = pagedItems.length; pageNumber < max; pageNumber++) {
            tagMap.push({
                tagName: tagName,
                pageNumber: pageNumber,
                pageData: pagedItems[pageNumber]
            });
        }
    }

    /* return data looks like:
        [{
            tagName: "tag1",
            pageNumber: 0
            pageData: [] // array of items
        },{
            tagName: "tag1",
            pageNumber: 1
            pageData: [] // array of items
        },{
            tagName: "tag1",
            pageNumber: 2
            pageData: [] // array of items
        },{
            tagName: "tag2",
            pageNumber: 0
            pageData: [] // array of items
        }]
     */
    //console.log( tagMap );
    return tagMap;
});

and then in your template it might look like this:

pagination:
  data: collections.doublePagination
  size: 1
  alias: tag
permalink: /tags/{{ tag.tagName }}/{% if tag.pageNumber %}{{ tag.pageNumber + 1 }}/{% endif %}
---

{% for post in tag.pageData %}
  Iterate over the items.
{% endfor %}

Does that make sense?

Seems to work!

image

This is really cool!

Looks great! Lemme test it out as soon as I can :D

This is an automated message to let you know that a helpful response was posted to your issue and for the health of the repository issue tracker the issue will be closed. This is to help alleviate issues hanging open waiting for a response from the original poster.

If the response works to solve your problem鈥攇reat! But if you鈥檙e still having problems, do not let the issue鈥檚 closing deter you if you have additional questions! Post another comment and I will reopen the issue. Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DirtyF picture DirtyF  路  3Comments

kaloja picture kaloja  路  3Comments

zachleat picture zachleat  路  3Comments

smaimon picture smaimon  路  3Comments

proog picture proog  路  3Comments