11ty / eleventy

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

Permalink Fix to Match Previous Blog #923

Open iChris opened 4 years ago

iChris commented 4 years ago

I've got 1,800 posts ported over from a WordPress install and have figured out that I can adjust permalinks by editing the posts.json file in the /posts/ directory.

What I'd like it to look like:

/year/month/title-of-post-with-dashes/

What I have so far in my posts.json file is this which I know isn't right.

{
  "layout": "layouts/post.njk",
  "permalink": "/{{ page.date.year }}/{{ page.date.month }}/{{ title | slug }}/"
}

I've been trying to sort through the docs on dates and page data but I can't quite grasp what I'm missing.

pdehaan commented 4 years ago

@iChris Ah, I think you're 99% of the way there. I believe page.date is a date object, so I'd create a couple of custom Nunjucks filters to extract the full year and another one to extract the month (and add 1 because 0-index, and maybe check that it's "02" for the month, but I guess it depends on how WordPress formatted the URLs originally if you're aiming for backwards compatibility there.

// Option 1: Separate filters for year/month.
// USAGE:
//   "permalink": "/{{ page.date | permalink_year }}/{{ page.date | permalink_month }}/{{ page.fileSlug }}/"
eleventyConfig.addFilter("permalink_year", dateObj => dateObj.getFullYear());
eleventyConfig.addFilter("permalink_month", dateObj =>
  String(dateObj.getMonth() + 1).padStart(2, "0")
);

// Option 2: Single filter for year/month/slug.
// USAGE:
//   "permalink": "{{ page | post_permalink }}"
eleventyConfig.addFilter("post_permalink", page => {
  const yyyy = page.date.getFullYear();
  const mm = String(page.date.getMonth() + 1).padStart(2, "0");
  return `${yyyy}/${mm}/${page.fileSlug}/`;
});

Full example at https://github.com/pdehaan/11ty-wordpress-permalinks

Only other caveat I can think of, is that dates can sometimes be unpredictable. Not sure if you're relying on Eleventy's default file creation/updated date behavior, or if your posts/*.njk files have an explicit date in the front-matter (or if the dates are part of the initial file slug -- for example, 2020-02-11-hello-world.njk).

I'd have to dig into the default Nunjucks filters to see if they have any built-in ways of doing this, but yeah. Something like that might work for you.

iChris commented 4 years ago

Full example at https://github.com/pdehaan/11ty-wordpress-permalinks

Ooh thanks! I tried your example on a branch here but get an error of Cannot GET / when I run npm start in the folder.

I'm relying on the file slug for the date convention currently - i.e. 2002-05-27.title-is-here.md so that it'll match with what my current WordPress based site has when I switch over to Eleventy/Netlify. i.e.

pdehaan commented 4 years ago

Ah, OK. I think I see it.

Your branch has an odd config, since I think the second module.exports = at the bottom would likely overwrite your original one above.

I killed about 95% of your posts (because I'm impatient), and then tweaked your config to move the one permalink filter you were using up to the top config, like so:

module.exports = function(config) {
  // Filters

  // Option 2: Single filter for year/month/slug.
  // USAGE:
  //   "permalink": "{{ page | post_permalink }}"
  config.addFilter("post_permalink", page => {
    const yyyy = page.date.getFullYear();
    const mm = String(page.date.getMonth() + 1).padStart(2, "0");
    const slug = page.fileSlug.replace(/^\d{4}-\d{2}-\d{2}\./, "");
    return `${yyyy}/${mm}/${slug}/`;
  });

  config.addFilter('dateFilter', dateFilter);
  config.addFilter('markdownFilter', markdownFilter);
  config.addFilter('w3DateFilter', w3DateFilter);

Then, running npm start generates a bunch of dist pages and the Terminal shows a bunch of this super cool output:

[1] Writing dist/2017/11/imagination-tom-wallisch-north-face/index.html
    from ./src/posts/2017-11-23.imagination-tom-wallisch-north-face.md.
[2] Writing dist/2017/11/apple-watch-used-to-identify-irregular-heart-rhythms/index.html
    from ./src/posts/2017-11-30.apple-watch-used-to-identify-irregular-heart-rhythms.md.
[3] Writing dist/2018/05/a-second-life-after-cancer/index.html
    from ./src/posts/a-second-life-after-cancer.md.

Note that I had to tweak the "post_permalink" filter above to try and strip out the date from the post's fileSlug. Since the dates on your blog all seem to start with YYYY-MM-DD., the RegEx clumsily just strips anything that looks like that. I did notice some blog posts didn't have the date prefix in the filename (see [3] above), but as you can see in the console output above, it seems to handle that case as well. I think that all works because they have the date metadata in the page's frontmatter.

If that all works for you, I'd probably just move that filter function into the src/filters/* folder, to be consistent with the other filters in your config.

iChris commented 4 years ago

Your branch has an odd config, since I think the second module.exports = at the bottom would likely overwrite your original one above.

Ah see that's because I have no idea what I'm doing! :)

But your fix worked perfectly. Thank you!

If that all works for you, I'd probably just move that filter function into the src/filters/* folder, to be consistent with the other filters in your config.

I don't totally get this. Would I move the entire code from above out of eleventy.js and into a file in /src/filters/date-permalink.js or something?

  // Permalink possible fix from https://github.com/11ty/eleventy/issues/923
  //   "permalink": "{{ page | post_permalink }}"
config.addFilter("post_permalink", page => {
  const yyyy = page.date.getFullYear();
  const mm = String(page.date.getMonth() + 1).padStart(2, "0");
  const slug = page.fileSlug.replace(/^\d{4}-\d{2}-\d{2}\./, "");
  return `${yyyy}/${mm}/${slug}/`;
});

config.addFilter('dateFilter', dateFilter);
config.addFilter('markdownFilter', markdownFilter);
config.addFilter('w3DateFilter', w3DateFilter);
pdehaan commented 4 years ago

I don't totally get this. Would I move the entire code from above out of eleventy.js and into a file in /src/filters/date-permalink.js or something?

Sorry, I'm not explaining this very well. Let me do a quick re-clone of your repo and submit a pull request and we can see it a bit better in context. Stand by.


Done, https://github.com/iChris/chrisennsdotcom/pull/11. I reviewed my own PR and added some comments which hopefully explain the possible refactoring a bit better.

iChris commented 4 years ago

Done, iChris/chrisennsdotcom#11. I reviewed my own PR and added some comments which hopefully explain the possible refactoring a bit better.

I love the internet. This is amazing. I'm off to bed for now but I'll check it out in the morning when I have clear eyes and coffee in hand. Thanks so much for your help!