Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Portfolio collection with next/ previous links but unique permalinks #426

Closed
luminarious opened this issue Feb 22, 2019 · 10 comments
Closed
Labels
duplicate waiting-to-close Issue that is probably resolved, waiting on OP confirmation.

Comments

@luminarious
Copy link

luminarious commented Feb 22, 2019

Hey, trying to put together a very basic portfolio site. Documentation is great regarding posts and single pages, but this kind of functionality is harder to suss out.. :/
Portfolio would be a pretty clear example case when documenting this.

Source:

  • ./project-X/*.(jpg|png|gif|mp4|svg|pdf|zip)
  • ./project-X/index.pug
    • tags: portfolio

Goal:

  • //example.com/project-X/*.(jpg|png|gif|mp4|svg|pdf|zip)
  • //example.com/project-X/index.html
    • ˂link rel="canonical" href="//example.com/project-X" /˃
    • <-Prev and Next-> links
@rendall
Copy link

rendall commented Mar 4, 2019

I second this. I really need a way to get access to 'previous' and 'next' in a collection (of posts).

e.g. (something like)

// This adds a 'prev' and 'next' key to each collection item 
// that holds information about the previous and next item
  eleventyConfig.addCollection("posts", collection => {  
    const filtered = collection.getFilteredByGlob("./posts/*").sort((a, b) => a.date - b.date);
    const getPost = (i) => i < 0 || i > filtered.length - 1? undefined : filtered[i].data
    const posts = filtered.map((post, i) => ({ ...post, data: { ...post.data, prev: getPost(i - 1), next: getPost(i + 1) } }))
    return posts
   }); 

Interestingly enough, the code above shows the relevant data inside the collection items, but it does not seem to be accessible from inside templates.

i.e. a collection item might show this structure, with prev and next:

{ 
  data: { 
     title: 'Title Current',
     date: 2019-03-03T00: 00: 00.000Z,
     tags: [ 'web', 'meta' ],
     page: { date: 2019-03-03T00: 00: 00.000Z,
        url: '/posts/current-title/',
        },
     prev: { 
        title: 'Title Previous',
        date: 2019-01-30T00: 00: 00.000Z,
        page: {  
            date: 2019-01-30T00: 00: 00.000Z,
            url: '/posts/previous-title/'
            }
        },
     next: { 
        title: 'Title Next',
        date: 2019-01-30T00: 00: 00.000Z,
        page: {  
            date: 2019-01-30T00: 00: 00.000Z,
            url: '/posts/next-title/'
            }
        },
    }
}

but attempting to access it inside the template, the values are undefined:

<p>{{ title }}</p> (shows up!)
<p>{{ prev.title }}</p> (undefined!)

@zachleat
Copy link
Member

I suspect y’all want to follow along at #211 which seems to be a duplicate of this

@zachleat zachleat added duplicate waiting-to-close Issue that is probably resolved, waiting on OP confirmation. labels Mar 11, 2019
@rendall
Copy link

rendall commented Mar 14, 2019

@zachleat I don't think this is exactly the same. The other seems to deal with pagination which (appears to be) deals with page numbering. e.g. /some-url/page/1 to /some-url/page/2

This thread is a different animal. Let's say the collection is ordered by some other sort. Not page number, but, say, date. It would be nice for the template to have access to the 'next' or 'previous' along some other scheme.

@thejohnfreeman
Copy link

@rendall I think the idea from @zachleat in #211 is this:

  • You create a collection of posts.
  • You order the collection by date. By default, it is ordered by date ascending; how to change to descending is already documented.
  • You paginate the collection, where each page has exactly 1 post.
  • Each page has access to the next and previous pages, all of which have exactly 1 post, so this effectively enables linking to the next and previous post by date.

Here's my problem. I tried sticking my posts in a _posts directory, creating the collection from that directory in my .eleventy.js, and then paginating 1-by-1 like I just described above. It works, but I can't get Eleventy stop creating two copies of my posts: one from the pagination, and one directly from the templates in the _posts directory. If I move _posts out of my input directory, or if I use .eleventyignore to ignore the templates in _posts, no pages are created.

@chinchang
Copy link

@thejohnfreeman You can set permalink: false in your individual posts. I just hope that doesn't affect the pagination output.

@thejohnfreeman
Copy link

@chinchang I have tried that out (more here). Then the problem became that if I wanted to link to a post, I would need to manually craft the URL for that post's page in the pagination; I could no longer use the convention page.url from Eleventy.

@borisschapira
Copy link

borisschapira commented Jun 14, 2019

Hey people, how about using the Custom Collection feature to extend the posts themselves during the build?

function addPrevNext(collectionArray) {
  const l = collectionArray.length;
  for (let p = 0; p < l; p++) {
    if (p > 1)
      collectionArray[p].data.previous = {
        title: collectionArray[p - 1].data.title,
        url: collectionArray[p - 1].url
      };
    if (p < l - 1)
      collectionArray[p].data.next = {
        title: collectionArray[p + 1].data.title,
        url: collectionArray[p + 1].url
      };
  }
  return collectionArray;
}

eleventyConfig.addCollection("my_posts", 
    collection => addPrevNext(collection.getFilteredByTag("posts"))
);

I'm using this with my posts to generate collections of posts for a specific language and a specific category, and have previous/next post inside the collection:

arrLocales = ["en", "fr"];
arrCategories = ["web", "citoyen", "papa"];

for (let i = 0; i < arrLocales.length; i++) {
  let l = arrLocales[i];
  eleventyConfig.addCollection(`posts_${l}`, collection =>
    collection.getFilteredByTag("posts").filter(function(item) {
      return item.data.locale == l;
    })
  );

  for (let j = 0; j < arrCategories.length; j++) {
    let c = arrCategories[j];
    eleventyConfig.addCollection(`posts_${l}_${c}`, collection =>
      addPrevNext(
        collection.getFilteredByTag("posts").filter(function(item) {
          return item.data.category == c && item.data.locale == l;
        })
      )
    );
  }
}

@rendall
Copy link

rendall commented Jun 14, 2019

Hey, awesome. I will try that, this weekend.

@alukito
Copy link

alukito commented Oct 7, 2019

Hi @borisschapira, the custom collection works well for this case, thank you. One note on your code example though. I think the index guard if (p > 1) will exclude first and second item, while we generally would like to exclude only the first item, so maybe it should be if (p > 0).

@zachleat
Copy link
Member

On re-read I believe this is a duplicate of #529 which has a nice workaround. Let’s coalesce over there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate waiting-to-close Issue that is probably resolved, waiting on OP confirmation.
Projects
None yet
Development

No branches or pull requests

7 participants