From 5ca8f83873e311c21ab4ecc705d0690d22d5456c Mon Sep 17 00:00:00 2001 From: Ricardo Date: Sat, 28 Mar 2026 18:46:06 +0100 Subject: [PATCH] feat: add /updated.xml feed for recently edited posts New RSS feed at /updated.xml that surfaces posts where the updated date is newer than the published date. Complements /feed.xml (new posts) with a dedicated feed for edits. - recentlyUpdated collection: filters posts with updated > published, sorted by update date, limited to 20 - Unique guid per edit (url#updated-date) so feed readers treat updates as new entries - Auto-discovery link in and footer link --- _includes/layouts/base.njk | 2 ++ eleventy.config.js | 16 ++++++++++++++ updated-feed.njk | 45 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 updated-feed.njk diff --git a/_includes/layouts/base.njk b/_includes/layouts/base.njk index 6ba6999..63fa37a 100644 --- a/_includes/layouts/base.njk +++ b/_includes/layouts/base.njk @@ -102,6 +102,7 @@ + {% if site.markdownAgents.enabled and page.url and page.url.startsWith('/articles/') and page.url != '/articles/' %} @@ -351,6 +352,7 @@ diff --git a/eleventy.config.js b/eleventy.config.js index c270948..477d642 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1057,6 +1057,22 @@ export default function (eleventyConfig) { .slice(0, 20); }); + // Recently edited posts (updated !== published) — for /updated.xml + eleventyConfig.addCollection("recentlyUpdated", function (collectionApi) { + return collectionApi + .getFilteredByGlob("content/**/*.md") + .filter(isPublished) + .filter((item) => { + if (!item.data.updated) return false; + // Only include if updated date differs from published date + const published = new Date(item.date).getTime(); + const updated = new Date(item.data.updated).getTime(); + return updated > published; + }) + .sort((a, b) => new Date(b.data.updated) - new Date(a.data.updated)) + .slice(0, 20); + }); + // Categories collection - deduplicated by slug to avoid duplicate permalinks eleventyConfig.addCollection("categories", function (collectionApi) { const categoryMap = new Map(); // slug -> original name (first seen) diff --git a/updated-feed.njk b/updated-feed.njk new file mode 100644 index 0000000..b3a244b --- /dev/null +++ b/updated-feed.njk @@ -0,0 +1,45 @@ +--- +permalink: /updated.xml +eleventyExcludeFromCollections: true +eleventyImport: + collections: + - recentlyUpdated +--- + + + + {{ site.name }} — Recently Updated + {{ site.url }}/ + Posts recently edited on {{ site.name }} + {{ site.locale | default('en') }} + + + {%- if collections.recentlyUpdated.length %} + {{ collections.recentlyUpdated[0].data.updated | dateToRfc822 }} + {%- endif %} + {%- for post in collections.recentlyUpdated %} + {%- set absolutePostUrl = site.url + post.url %} + {%- set postImage = post.data.photo %} + {%- if postImage %} + {%- if postImage[0] and (postImage[0] | length) > 10 %} + {%- set postImage = postImage[0] %} + {%- endif %} + {%- endif %} + {%- if not postImage or postImage == "" %} + {%- set postImage = post.data.image or (post.content | extractFirstImage) %} + {%- endif %} + + {{ post.data.title | default(post.content | striptags | truncate(80)) | escape }} [updated] + {{ absolutePostUrl }} + {{ absolutePostUrl }}#updated-{{ post.data.updated | dateToRfc822 }} + {{ post.data.updated | dateToRfc822 }} + {{ post.content | htmlToAbsoluteUrls(absolutePostUrl) | escape }} + {%- if postImage and postImage != "" and (postImage | length) > 10 %} + {%- set imageUrl = postImage | url | absoluteUrl(site.url) %} + + + {%- endif %} + + {%- endfor %} + +