11ty / eleventy

A simpler site generator. Transforms a directory of templates (of varying types) into HTML.
https://www.11ty.dev/
MIT License
16.84k stars 487 forks source link

How to use different content dates for pages generated from data through pagination? #1249

Open sullyD64 opened 4 years ago

sullyD64 commented 4 years ago

Hi everyone. I don't know if a workaround exists for this or if I'm asking for an enhancement, so sorry if I mislabeled this issue.

When using pagination to Create Pages From Data (setting size: 1 and using an alias), I've found that each individual page inherits the date from the template that generated the pages.

It would be nice, instead, to be able to specify a different date for each page, reading from its source element.

Using the example from the above page, I've added dates to the elements:

[
  {
    "name":"Fluffy",
    "age":2,
+    "date": "2020-01-01",
  },
   ...
  {
    "name":"Pennywise",
    "age":9,
+    "date": "2020-01-02",
  }
]

I tried using computed data but without success:

exports.data = {
  // date: 'Created', // default value for the page date,  say 2020-06-12.
  pagination: {
    data: 'possums',
    size: 1,
    alias: 'possum',
    addAllPagesToCollections: true
  },
  permalink(data) { return `possums/${ possum.name | slug }
  },
+  eleventyComputed: {
+    date(data) {
+      return data.possum.date
+    }
  }
}

But when rendering each page, page.date holds a Date object from the source template's date key.

Is there something else i could do?

denisbrodbeck commented 4 years ago

This should work. Without any computed properties.

One issue I had, was that I didn't pass a Date as value. Passing just a string always failed.

// src/_data/pages.js

module.exports = [
  {
    name: "Fluffy",
    age: 2,
    date: new Date("2020-01-01"),
  },
  {
    name: "Pennywise",
    age: 9,
    date: new Date("2020-01-02"),
  },
];
// src/page.11ty.js

exports.data = () => ({
  title: `Default Title`,
  date: new Date("2019-01-01"), // this one will be ignored
  layout: `base.njk`,
  pagination: {
    data: `pages`,
    size: 1,
    alias: `page`,
    addAllPagesToCollections: true,
  },
  permalink: ({ page }) => `/${page.name.toLowerCase()}/index.html`,
});

exports.render = ({ page }) => `
<div>
  <div>Name: ${page.name}</div>
  <div>Age: ${page.age}</div>
  <div>Date: ${page.date}</div>
</div>`;
// .eleventy.js

module.exports = function (config) {
  // your config here

  // Base Config
  return {
    dir: {
      input: `src`,
      output: `dist`,
      includes: `_includes`,
      layouts: `_layouts`,
      data: `_data`,
    },
    templateFormats: [`njk`, `md`, `11ty.js`],
    htmlTemplateEngine: `njk`,
    markdownTemplateEngine: `njk`,
  };
};
{# src/_layouts/base.njk #}

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ page.title if page.title else title }}</title>
  </head>
  <body>
    <div>
      {{ content | safe }}
    </div>
  </body>
</html>
sullyD64 commented 4 years ago

Hi @denisbrodbeck, thank you. I tried new Date() instead of strings and it works for me too!

One observation I still have is that this practically bypasses Eleventy's default handling of content dates, which brings us to my real question: I wonder if there is a way to tell Eleventy to treat each "generated" page as a page object, so that page.date plus other useful data will be available.

I've ran into this problem when trying to share the same template across both individual templates and pagination-generated pages. Being able to use the same indexes would be super nice.