Closed mehtapratik closed 3 years ago
According to https://www.11ty.dev/docs/dates/ the items Created
and Last Modified
will change dynamically, so you could try something like this:
---
Published: Created
Updated: Last Modified
---
Thanks for the response @brycewray. But, this doesn't work.
index.md
---
tags:
- notPost
- navItem
layout: site.njk
title: Home
Published: Created
Updated: Last Modified
---
site.njk
...
<p>This article was published on {{ Published }}.</p>
<p>Last updated on: {{ Updated }}</p>
...
It outputs following:
This article was published on: Created.
Last updated on: Last Modified
@mehtapratik True, that's a different matter. Sorry; I misunderstood what you were trying to do. In my site's case, I use a more manual approach (which is probably what you want to avoid). For example, in a post's front matter I might have:
date: 2020-01-18T21:20:00-06:00
lastmod: 2020-01-20T08:15:00-06:00
And then, in the appropriate template (omitting some styling items irrelevant to this discussion):
<p>
Published: {{ page.date | htmlDateString }}<br />
{% if lastmod %}
Last modified: {{ lastmod | htmlDateString }}
{% else %}
{% endif %}
</p>
As for htmlDateString
, of course, it's defined in my .eleventy.js
file following an earlier const { DateTime } = require("luxon")
:
eleventyConfig.addFilter('htmlDateString', dateObj => {
return DateTime.fromJSDate(dateObj).toFormat('MMMM d, yyyy')
})
Thanks @brycewray.
Hello @zachleat: Is this supported in current version or any plans to include it in future releases?
I'd very much like to see this too.
Maybe more future proof than simply adding another pre-processed update
field would be to allow the user to hook in "processing functions" for fields through the .eleventy.js
config, such that they can choose to make arbitrary transformations on a field value. There could be pre-defined "processing functions" for common use cases, like date parsing.
A basic syntax could look like
// custom function
eleventyConfig.addKeyTransform("key-name", function(key) {});
// pre-defined function
eleventyConfig.addKeyTransform("key-name", "date");
I want the data @brycewray put in his front matter:
date: 2020-01-18T21:20:00-06:00 lastmod: 2020-01-20T08:15:00-06:00
on all of my pages' data automatically. I've been fooling around with global computed data to try to find a way to extract the file modification time by running fs
on the inputPath
.
This is what I tried in _data/eleventyComputed.js
:
const fs = require('fs')
module.exports = {
created: (data) => data.length?fs.statSync(data.inputPath).birthtime:undefined,
modified: (data) => data.length?fs.statSync(data.inputPath).mtime:undefined,
}
I have to check data.length
because some pages feed in data = {}
and statSync
errors out if you feed it undefined
as an arg.
Next, in my nunjuck template:
<footer>
date: {{eleventyComputed.modified}}
</footer>
And the html output is:
<footer>date: function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return obj[val].apply(obj, args);
}
</footer>
Which dumps all that weird javascript right out onto the footer. A spectacular failure. Absolute catastrophe.
I give up. I'm pretty sure this is possible with computed data, but I haven't figured it out.
@keith24 I think that's correct. Your eleventyComputed.js file's modified
property is an anonymous function, so Eleventy is outputting the function definition.
I recreated your code in a new project and got the following:
---
title: Homepage
permalink: /
---
<footer>
<p>created: {{ eleventyComputed.created }}</p>
<p>created(): {{ eleventyComputed.created() }}</p>
<p>created(page): {{ eleventyComputed.created(page) }}</p>
<hr/>
<p>modified: {{ eleventyComputed.modified }}</p>
<p>modified(): {{ eleventyComputed.modified() }}</p>
<p>modified(page): {{ eleventyComputed.modified(page) }}</p>
</footer>
And my output is:
<footer>
<p>created: function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return obj[val].apply(obj, args);
}</p>
<p>created(): </p>
<p>created(page): Tue Jan 26 2021 23:50:44 GMT-0800 (Pacific Standard Time)</p>
<hr/>
<p>modified: function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return obj[val].apply(obj, args);
}</p>
<p>modified(): </p>
<p>modified(page): Wed Jan 27 2021 00:01:52 GMT-0800 (Pacific Standard Time)</p>
</footer>
But I also had to revise the eleventyComputed.js file slightly, since the data
argument is expecting an object and I don't think you can use data.length
to check for an empty object. So instead I used optional chaining (?.
) to check if the data
argument has an inputPath
property before trying to use it w/ fs.statSync
:
const fs = require('fs')
module.exports = {
created: (data) => data?.inputPath ? fs.statSync(data.inputPath).birthtime : undefined,
modified: (data) => data?.inputPath ? fs.statSync(data.inputPath).mtime : undefined,
};
TL:DR: I think your code [mostly] works, but you'll need to pass in the current page
object to your custom method in order to get the page's current context.
If you don't want to pass in the page
context every time (can't blame you), another option might be shortcodes, which have access to the current page
context via this.page
(assuming you aren't using arrow functions):
// in your .eleventy.js config file:
eleventyConfig.addShortcode("created", function () {
return this.page?.inputPath ? fs.statSync(this.page.inputPath).birthtime : undefined;
});
eleventyConfig.addShortcode("modified", function () {
return this.page?.inputPath ? fs.statSync(this.page.inputPath).mtime : undefined;
});
Now, in my one random Nunjucks test file, I can add this:
<p>created (shortcode): {% created %}</p>
<p>modified (shortcode): {% modified %}</p>
<p>created (shortcode): Tue Jan 26 2021 23:50:44 GMT-0800 (Pacific Standard Time)</p>
<p>modified (shortcode): Wed Jan 27 2021 00:21:09 GMT-0800 (Pacific Standard Time)</p>
It doesn't look like this.page
works w/ filters yet; ref: https://github.com/11ty/eleventy/issues/1047. But, I think we can hack it, although it feels kind of messy:
<p>created (filter): {{ page.inputPath | fileDate }}</p>
<p>created (filter): {{ page.inputPath | fileDate("birthtime") }}</p>
<p>modified (filter): {{ page.inputPath | fileDate("mtime") }}</p>
// somewhere in your .eleventy.js config file:
eleventyConfig.addFilter("fileDate", (inputPath, key="birthtime") => {
return inputPath ? fs.statSync(inputPath)[key] : undefined;
});
<p>created (filter): Tue Jan 26 2021 23:50:44 GMT-0800 (Pacific Standard Time)</p>
<p>created (filter): Tue Jan 26 2021 23:50:44 GMT-0800 (Pacific Standard Time)</p>
<p>modified (filter): Wed Jan 27 2021 00:32:07 GMT-0800 (Pacific Standard Time)</p>
Last one... an async Nunjucks shortcode, since you mentioned a Nunjucks template:
eleventyConfig.addNunjucksAsyncShortcode("fileDateShortcode", async function (label="", key="birthtime") {
const inputPath = this.page?.inputPath;
if (!inputPath) {
return "";
}
const stats = await fs.promises.stat(inputPath);
const date = new Date(stats[key]);
return `${label} ${date?.toLocaleDateString()}`.trim();
});
<p>{% fileDateShortcode "CrEaTeD:" %}</p>
<p>{% fileDateShortcode "MoDiFiEd:", "mtime" %}</p>
<p>CrEaTeD: 2021-01-26</p>
<p>MoDiFiEd: 2021-01-27</p>
Any update on this?
I tried @brycewray's idea, but it doesn't seem to work. In the rendered version I get "Wed Apr 14 2021 22:00:00 GMT+0200 (Central European Summer Time)" :(
I got it to work. Note that only the last example brycewray gave actually converts to a readable string. I think it's done by the .toLocaleDateString()
method in the return function. There are lots of similar methods to convert a Date object to readable text. You can find a good list at the MDN Javascript Date Object docs.
I am not really a fan of additions like this because of the unreliability of file creation and modified times. See also https://www.11ty.dev/docs/dates/#collections-out-of-order-when-you-run-eleventy-on-your-server
I do think a better way forward is https://github.com/11ty/eleventy/issues/142
But I’ll put this in the enhancement queue and let folks vote on it
This repository is now using lodash style issue management for enhancements. This means enhancement issues will now be closed instead of leaving them open.
View the enhancement backlog here. Don’t forget to upvote the top comment with 👍!
I'm not following how #142 helps with the original issue. The question was how can I display both the created and last modified dates without manually editing them. Currently it seems it is an either/or situation for date
front matter.
I'm not following how #142 helps with the original issue. The question was how can I display both the created and last modified dates without manually editing them. Currently it seems it is an either/or situation for
date
front matter.
Yes, this is something I'm working through right now as well. For the purpose of a blog site I'm working I want to be able to use git Created
and git Last Modified
to show Date Created and Date Updated, respectively; however, date is the only front matter tag recognized. Knowing little-to-no JS my current option is to just hard type one of these values. I'd like to be able to use the git date values, though, since I'm working on this with git source control.
For the purpose of using the existing setup to having a working sitemap page that updates automatically, I just use date: git Last Modified
and use a filter code snippet I found to convert it to ISO from JSDate. The Date Created will have to be hard coded.
Just for the record, this is possible to implement today using computed data: https://www.11ty.dev/docs/data-computed/
It’s worth also linking to https://github.com/11ty/eleventy/issues/867 which doesn’t allow multiple dates but does allow further customization of primary date behavior.
Let's say I want to put two dates on my blog. Date it was originally created and date it was last modified. How can I do this using 11ty?
I thought following could work. But, now I understand it won't because value of
createdDate
will not be transformed.Am I missing something? Is there a better way of handling this scenario?