feat: update implementation of RSS feeds
Adds a new filter `convertRelativeLinks` that converts any relative link to an absolute path Adds an XML transform to minify the final output for smaller filesizes Updates some data in meta Adds a new macro for generating an RSS feed
This commit is contained in:
parent
46ed7a29be
commit
e6cfa88f61
14 changed files with 1508 additions and 271 deletions
|
@ -4,6 +4,8 @@ import advancedFormat from "dayjs/plugin/advancedFormat.js";
|
||||||
|
|
||||||
import pluralizeBase from "pluralize";
|
import pluralizeBase from "pluralize";
|
||||||
|
|
||||||
|
import { JSDOM } from "jsdom";
|
||||||
|
|
||||||
export const keys = Object.keys;
|
export const keys = Object.keys;
|
||||||
export const values = Object.values;
|
export const values = Object.values;
|
||||||
export const entries = Object.entries;
|
export const entries = Object.entries;
|
||||||
|
@ -12,6 +14,7 @@ dayjs.extend(utc);
|
||||||
dayjs.extend(advancedFormat);
|
dayjs.extend(advancedFormat);
|
||||||
|
|
||||||
export const formatDate = (date, format) => dayjs.utc(date).format(format);
|
export const formatDate = (date, format) => dayjs.utc(date).format(format);
|
||||||
|
export const formatAsUTCString = (date) => new Date(date).toUTCString();
|
||||||
|
|
||||||
export const organizeByDate = (collection) => {
|
export const organizeByDate = (collection) => {
|
||||||
const collectionByDate = {};
|
const collectionByDate = {};
|
||||||
|
@ -101,3 +104,29 @@ export const isOld = (dateArg) => {
|
||||||
|
|
||||||
return diffInYears >= 2;
|
return diffInYears >= 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// From coryd.dev
|
||||||
|
// https://www.coryd.dev/posts/2025/generating-absolute-urls-in-my-rss-feeds/
|
||||||
|
export const convertRelativeLinks = (htmlContent, url) => {
|
||||||
|
if (!htmlContent || !url) return htmlContent;
|
||||||
|
|
||||||
|
const dom = new JSDOM(htmlContent);
|
||||||
|
const document = dom.window.document;
|
||||||
|
|
||||||
|
document.querySelectorAll("a[href]").forEach((link) => {
|
||||||
|
let href = link.getAttribute("href");
|
||||||
|
|
||||||
|
if (href.startsWith("#")) {
|
||||||
|
link.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!href.startsWith("http://") && !href.startsWith("https://"))
|
||||||
|
link.setAttribute(
|
||||||
|
"href",
|
||||||
|
`${url.replace(/\/$/, "")}/${href.replace(/^\/+/, "")}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return document.body.innerHTML;
|
||||||
|
};
|
||||||
|
|
12
config/transforms/xml-config.js
Normal file
12
config/transforms/xml-config.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export default function (eleventyConfig) {
|
||||||
|
eleventyConfig.addTransform("xml-minify", (content, path) => {
|
||||||
|
if (path && path.endsWith(".xml")) {
|
||||||
|
return minifyXML(content, {
|
||||||
|
shortenNamespaces: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
});
|
||||||
|
}
|
|
@ -7,11 +7,13 @@ import { collectionByTag, postsByTag } from "./config/collections/index.js";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
allTagCounts,
|
allTagCounts,
|
||||||
|
convertRelativeLinks,
|
||||||
entries,
|
entries,
|
||||||
filter,
|
filter,
|
||||||
filterByTags,
|
filterByTags,
|
||||||
filterFavourites,
|
filterFavourites,
|
||||||
formatDate,
|
formatDate,
|
||||||
|
formatAsUTCString,
|
||||||
isOld,
|
isOld,
|
||||||
keys,
|
keys,
|
||||||
limit,
|
limit,
|
||||||
|
@ -24,6 +26,7 @@ import markdown from "./config/plugins/markdown.js";
|
||||||
import liteYoutube from "./config/shortcodes/youtube.js";
|
import liteYoutube from "./config/shortcodes/youtube.js";
|
||||||
|
|
||||||
import htmlConfigTransform from "./config/transforms/html-config.js";
|
import htmlConfigTransform from "./config/transforms/html-config.js";
|
||||||
|
import xmlConfigTransform from "./config/transforms/xml-config.js";
|
||||||
|
|
||||||
export default function (eleventyConfig) {
|
export default function (eleventyConfig) {
|
||||||
eleventyConfig.addWatchTarget("./src/css");
|
eleventyConfig.addWatchTarget("./src/css");
|
||||||
|
@ -49,11 +52,13 @@ export default function (eleventyConfig) {
|
||||||
|
|
||||||
// --------------------- Custom Filters -----------------------
|
// --------------------- Custom Filters -----------------------
|
||||||
eleventyConfig.addFilter("allTagCounts", allTagCounts);
|
eleventyConfig.addFilter("allTagCounts", allTagCounts);
|
||||||
|
eleventyConfig.addFilter("convertRelativeLinks", convertRelativeLinks);
|
||||||
eleventyConfig.addFilter("entries", entries);
|
eleventyConfig.addFilter("entries", entries);
|
||||||
eleventyConfig.addFilter("filter", filter);
|
eleventyConfig.addFilter("filter", filter);
|
||||||
eleventyConfig.addFilter("filterFavourites", filterFavourites);
|
eleventyConfig.addFilter("filterFavourites", filterFavourites);
|
||||||
eleventyConfig.addFilter("filterByTags", filterByTags);
|
eleventyConfig.addFilter("filterByTags", filterByTags);
|
||||||
eleventyConfig.addFilter("formatDate", formatDate);
|
eleventyConfig.addFilter("formatDate", formatDate);
|
||||||
|
eleventyConfig.addFilter("formatAsUTCString", formatAsUTCString);
|
||||||
eleventyConfig.addFilter("isOld", isOld);
|
eleventyConfig.addFilter("isOld", isOld);
|
||||||
eleventyConfig.addFilter("keys", keys);
|
eleventyConfig.addFilter("keys", keys);
|
||||||
eleventyConfig.addFilter("limit", limit);
|
eleventyConfig.addFilter("limit", limit);
|
||||||
|
@ -65,6 +70,7 @@ export default function (eleventyConfig) {
|
||||||
|
|
||||||
// --------------------- Custom Transforms -----------------------
|
// --------------------- Custom Transforms -----------------------
|
||||||
eleventyConfig.addPlugin(htmlConfigTransform);
|
eleventyConfig.addPlugin(htmlConfigTransform);
|
||||||
|
eleventyConfig.addPlugin(xmlConfigTransform);
|
||||||
|
|
||||||
// Image Transforms
|
// Image Transforms
|
||||||
// Works with any <img> tag in output files.
|
// Works with any <img> tag in output files.
|
||||||
|
|
1502
package-lock.json
generated
1502
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -34,5 +34,9 @@
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.1.0",
|
||||||
"postcss-import-ext-glob": "^2.1.1"
|
"postcss-import-ext-glob": "^2.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jsdom": "^26.0.0",
|
||||||
|
"minify-xml": "^4.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export default {
|
export default {
|
||||||
url: process.env.URL || "http://localhost:8080",
|
url: process.env.URL || "http://localhost:8080",
|
||||||
siteName: "wonderfulfrog",
|
siteName: "wonderfulfrog.com",
|
||||||
siteDescription:
|
siteDescription:
|
||||||
"My name is Devin Haska and this is my little slice of the internet I call home.",
|
"My name is Devin Haska and this is my little slice of the internet I call home.",
|
||||||
locale: "en_EN",
|
locale: "en_EN",
|
||||||
|
|
29
src/includes/macros/feed.njk
Normal file
29
src/includes/macros/feed.njk
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{% macro feed(meta, items, buildTime, feedPath, feedTitle, filterTag) %}
|
||||||
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||||
|
<channel>
|
||||||
|
<title>![CDATA[{% if feedTitle %}{{ feedTitle }} • {% endif %}{{ meta.siteName }}]]</title>
|
||||||
|
<link>{{ meta.url }}</link>
|
||||||
|
<atom:link href="{{ meta.url }}{{ feedPath }}" rel="self" type="application/rss+xml" />
|
||||||
|
<description>![CDATA[{{ meta.siteDescription }}]]</description>
|
||||||
|
<language>en-ca</language>
|
||||||
|
<pubDate>{{ buildTime | formatAsUTCString }}</pubDate>
|
||||||
|
<lastBuildDate>{{ buildTime | formatAsUTCString }}</lastBuildDate>
|
||||||
|
{% for item in items | reverse %}
|
||||||
|
<item>
|
||||||
|
<title>![CDATA[{{ item.data.title }}]]</title>
|
||||||
|
<guid>{{ meta.url }}{{ item.url }}</guid>
|
||||||
|
<pubDate>{{ item.date | formatAsUTCString }}</pubDate>
|
||||||
|
<link>{{ meta.url }}{{ item.url }}</link>
|
||||||
|
{% for tag in item.data.tags | filter(filterTag) %}
|
||||||
|
<category>{{ tag }}</category>
|
||||||
|
{% endfor %}
|
||||||
|
{% if item.content %}
|
||||||
|
<description>![CDATA[{{ item.content | convertRelativeLinks(meta.url) | escape }}]]</description>
|
||||||
|
{% elseif item.data.excerpt %}
|
||||||
|
<description>![CDATA[{{ item.excerpt }}]]</description>
|
||||||
|
{% endif %}
|
||||||
|
</item>
|
||||||
|
{% endfor %}
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
|
{% endmacro %}
|
|
@ -1,27 +1,15 @@
|
||||||
---
|
---
|
||||||
permalink: /feeds/all.xml
|
permalink: /feeds/all.xml
|
||||||
layout: null
|
layout: null
|
||||||
|
filterTag:
|
||||||
|
- post
|
||||||
|
- game
|
||||||
|
- tv
|
||||||
|
- movie
|
||||||
|
- book
|
||||||
eleventyExcludeFromCollections: true
|
eleventyExcludeFromCollections: true
|
||||||
excludeFromSitemap: true
|
excludeFromSitemap: true
|
||||||
---<?xml version="1.0" encoding="utf-8"?>
|
---
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
{% set data = collections.all | filterByTags(["page", "podcast"]) %}
|
||||||
<title>{{ meta.siteName }}</title>
|
{% from "macros/feed.njk" import feed %}
|
||||||
<subtitle>{{ meta.siteDescription }}</subtitle>
|
{{ feed(meta, data, page.date, permalink, title, filterTag) }}
|
||||||
<link href="{{ meta.url }}/feeds/all.xml" rel="self" />
|
|
||||||
<link href="{{ meta.url }}/" rel="alternate" type="text/html" />
|
|
||||||
<id>{{ meta.url }}/</id>
|
|
||||||
<author>
|
|
||||||
<name>{{ meta.author }}</name>
|
|
||||||
</author>
|
|
||||||
{% for item in collections.all | filterByTags(["page"]) %}
|
|
||||||
<entry>
|
|
||||||
<id>{{ meta.url }}{{ item.url }}</id>
|
|
||||||
<title>{{ item.data.title | escape }}</title>
|
|
||||||
<link href="{{ item.url }}{{ post.url }}" />
|
|
||||||
<pubDate>{{ item.date }}</pubDate>
|
|
||||||
{# The first tag is always a type e.g. post, page, etc. #}
|
|
||||||
{%- for tag in item.data.tags %}{% if not loop.first %}<category term="{{ tag }}" />{% endif %}{%- endfor %}
|
|
||||||
<content type="html">{{ item.content | escape }}</content>
|
|
||||||
</entry>
|
|
||||||
{% endfor %}
|
|
||||||
</feed>
|
|
||||||
|
|
|
@ -1,26 +1,11 @@
|
||||||
---
|
---
|
||||||
permalink: /feeds/books.xml
|
permalink: /feeds/books.xml
|
||||||
layout: null
|
layout: null
|
||||||
|
title: Books
|
||||||
|
filterTag:
|
||||||
|
- book
|
||||||
eleventyExcludeFromCollections: true
|
eleventyExcludeFromCollections: true
|
||||||
excludeFromSitemap: true
|
excludeFromSitemap: true
|
||||||
---<?xml version="1.0" encoding="utf-8"?>
|
---
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
{% from "macros/feed.njk" import feed %}
|
||||||
<title>Books • {{ meta.siteName }}</title>
|
{{ feed(meta, collections.book, page.date, permalink, title, filterTag) }}
|
||||||
<subtitle>{{ meta.siteDescription }}</subtitle>
|
|
||||||
<link href="{{ meta.url }}/feeds/books.xml" rel="self" />
|
|
||||||
<link href="{{ meta.url }}/" rel="alternate" type="text/html" />
|
|
||||||
<id>{{ meta.url }}/</id>
|
|
||||||
<author>
|
|
||||||
<name>{{ meta.author }}</name>
|
|
||||||
</author>
|
|
||||||
{% for item in collections.book %}
|
|
||||||
<entry>
|
|
||||||
<id>{{ meta.url }}{{ item.url }}</id>
|
|
||||||
<title>{{ item.data.title | escape }}</title>
|
|
||||||
<link href="{{ item.url }}{{ post.url }}" />
|
|
||||||
<pubDate>{{ item.date }}</pubDate>
|
|
||||||
{%- for tag in item.data.tags | filter("book") %}<category term="{{ tag }}" />{%- endfor %}
|
|
||||||
<content type="html">{{ item.content | escape }}</content>
|
|
||||||
</entry>
|
|
||||||
{% endfor %}
|
|
||||||
</feed>
|
|
||||||
|
|
|
@ -1,26 +1,11 @@
|
||||||
---
|
---
|
||||||
permalink: /feeds/games.xml
|
permalink: /feeds/games.xml
|
||||||
layout: null
|
layout: null
|
||||||
|
title: Games
|
||||||
|
filterTag:
|
||||||
|
- game
|
||||||
eleventyExcludeFromCollections: true
|
eleventyExcludeFromCollections: true
|
||||||
excludeFromSitemap: true
|
excludeFromSitemap: true
|
||||||
---<?xml version="1.0" encoding="utf-8"?>
|
---
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
{% from "macros/feed.njk" import feed %}
|
||||||
<title>Games • {{ meta.siteName }}</title>
|
{{ feed(meta, collections.game, page.date, permalink, title, filterTag) }}
|
||||||
<subtitle>{{ meta.siteDescription }}</subtitle>
|
|
||||||
<link href="{{ meta.url }}/feeds/games.xml" rel="self" />
|
|
||||||
<link href="{{ meta.url }}/" rel="alternate" type="text/html" />
|
|
||||||
<id>{{ meta.url }}/</id>
|
|
||||||
<author>
|
|
||||||
<name>{{ meta.author }}</name>
|
|
||||||
</author>
|
|
||||||
{% for item in collections.game %}
|
|
||||||
<entry>
|
|
||||||
<id>{{ meta.url }}{{ item.url }}</id>
|
|
||||||
<title>{{ item.data.title | escape }}</title>
|
|
||||||
<link href="{{ item.url }}{{ post.url }}" />
|
|
||||||
<pubDate>{{ item.date }}</pubDate>
|
|
||||||
{%- for tag in item.data.tags | filter("game") %}<category term="{{ tag }}" />{%- endfor %}
|
|
||||||
<content type="html">{{ item.content | escape }}</content>
|
|
||||||
</entry>
|
|
||||||
{% endfor %}
|
|
||||||
</feed>
|
|
||||||
|
|
|
@ -1,26 +1,11 @@
|
||||||
---
|
---
|
||||||
permalink: /feeds/movies.xml
|
permalink: /feeds/movies.xml
|
||||||
|
title: Movies
|
||||||
|
filterTag:
|
||||||
|
- movie
|
||||||
layout: null
|
layout: null
|
||||||
eleventyExcludeFromCollections: true
|
eleventyExcludeFromCollections: true
|
||||||
excludeFromSitemap: true
|
excludeFromSitemap: true
|
||||||
---<?xml version="1.0" encoding="utf-8"?>
|
---
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
{% from "macros/feed.njk" import feed %}
|
||||||
<title>Movies • {{ meta.siteName }}</title>
|
{{ feed(meta, collections.movie, page.date, permalink, title, filterTag) }}
|
||||||
<subtitle>{{ meta.siteDescription }}</subtitle>
|
|
||||||
<link href="{{ meta.url }}/feeds/movies.xml" rel="self" />
|
|
||||||
<link href="{{ meta.url }}/" rel="alternate" type="text/html" />
|
|
||||||
<id>{{ meta.url }}/</id>
|
|
||||||
<author>
|
|
||||||
<name>{{ meta.author }}</name>
|
|
||||||
</author>
|
|
||||||
{% for item in collections.movie %}
|
|
||||||
<entry>
|
|
||||||
<id>{{ meta.url }}{{ item.url }}</id>
|
|
||||||
<title>{{ item.data.title | escape }}</title>
|
|
||||||
<link href="{{ item.url }}{{ post.url }}" />
|
|
||||||
<pubDate>{{ item.date }}</pubDate>
|
|
||||||
{%- for tag in item.data.tags | filter("movie") %}<category term="{{ tag }}" />{%- endfor %}
|
|
||||||
<content type="html">{{ item.content | escape }}</content>
|
|
||||||
</entry>
|
|
||||||
{% endfor %}
|
|
||||||
</feed>
|
|
||||||
|
|
|
@ -1,26 +1,11 @@
|
||||||
---
|
---
|
||||||
permalink: /feeds/posts.xml
|
permalink: /feeds/posts.xml
|
||||||
|
title: Posts
|
||||||
|
filterTag:
|
||||||
|
- post
|
||||||
layout: null
|
layout: null
|
||||||
eleventyExcludeFromCollections: true
|
eleventyExcludeFromCollections: true
|
||||||
excludeFromSitemap: true
|
excludeFromSitemap: true
|
||||||
---<?xml version="1.0" encoding="utf-8"?>
|
---
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
{% from "macros/feed.njk" import feed %}
|
||||||
<title>Posts • {{ meta.siteName }}</title>
|
{{ feed(meta, collections.post, page.date, permalink, title, filterTag) }}
|
||||||
<subtitle>{{ meta.siteDescription }}</subtitle>
|
|
||||||
<link href="{{ meta.url }}/feeds/posts.xml" rel="self" />
|
|
||||||
<link href="{{ meta.url }}/" rel="alternate" type="text/html" />
|
|
||||||
<id>{{ meta.url }}/</id>
|
|
||||||
<author>
|
|
||||||
<name>{{ meta.author }}</name>
|
|
||||||
</author>
|
|
||||||
{% for post in collections.post %}
|
|
||||||
<entry>
|
|
||||||
<id>{{ meta.url }}{{ post.url }}</id>
|
|
||||||
<title>{{ post.data.title | escape }}</title>
|
|
||||||
<link href="{{ meta.url }}{{ post.url }}" />
|
|
||||||
<pubDate>{{ post.date }}</pubDate>
|
|
||||||
{%- for tag in post.data.tags %}<category term="{{ tag }}" />{%- endfor %}
|
|
||||||
<content type="html">{{ post.content | escape }}</content>
|
|
||||||
</entry>
|
|
||||||
{% endfor %}
|
|
||||||
</feed>
|
|
||||||
|
|
|
@ -1,26 +1,11 @@
|
||||||
---
|
---
|
||||||
permalink: /feeds/shows.xml
|
permalink: /feeds/shows.xml
|
||||||
|
title: Shows
|
||||||
|
filterTag:
|
||||||
|
- tv
|
||||||
layout: null
|
layout: null
|
||||||
eleventyExcludeFromCollections: true
|
eleventyExcludeFromCollections: true
|
||||||
excludeFromSitemap: true
|
excludeFromSitemap: true
|
||||||
---<?xml version="1.0" encoding="utf-8"?>
|
---
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
{% from "macros/feed.njk" import feed %}
|
||||||
<title>Shows • {{ meta.siteName }}</title>
|
{{ feed(meta, collections.tv, page.date, permalink, title, filterTag) }}
|
||||||
<subtitle>{{ meta.siteDescription }}</subtitle>
|
|
||||||
<link href="{{ meta.url }}/feeds/shows.xml" rel="self" />
|
|
||||||
<link href="{{ meta.url }}/" rel="alternate" type="text/html" />
|
|
||||||
<id>{{ meta.url }}/</id>
|
|
||||||
<author>
|
|
||||||
<name>{{ meta.author }}</name>
|
|
||||||
</author>
|
|
||||||
{% for item in collections.tv %}
|
|
||||||
<entry>
|
|
||||||
<id>{{ meta.url }}{{ item.url }}</id>
|
|
||||||
<title>{{ item.data.title | escape }}</title>
|
|
||||||
<link href="{{ item.url }}{{ post.url }}" />
|
|
||||||
<pubDate>{{ item.date }}</pubDate>
|
|
||||||
{%- for tag in item.data.tags | filter("tv") %}<category term="{{ tag }}" />{%- endfor %}
|
|
||||||
<content type="html">{{ item.content | escape }}</content>
|
|
||||||
</entry>
|
|
||||||
{% endfor %}
|
|
||||||
</feed>
|
|
||||||
|
|
|
@ -1,29 +1,15 @@
|
||||||
---
|
---
|
||||||
permalink: /feeds/watching.xml
|
permalink: /feeds/watching.xml
|
||||||
layout: null
|
layout: null
|
||||||
|
title: Watching
|
||||||
|
filterTag:
|
||||||
|
- movie
|
||||||
|
- tv
|
||||||
eleventyExcludeFromCollections: true
|
eleventyExcludeFromCollections: true
|
||||||
excludeFromSitemap: true
|
excludeFromSitemap: true
|
||||||
---<?xml version="1.0" encoding="utf-8"?>
|
---
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
|
||||||
<title>Watching • {{ meta.siteName }}</title>
|
|
||||||
<subtitle>{{ meta.siteDescription }}</subtitle>
|
|
||||||
<link href="{{ meta.url }}/feeds/watching.xml" rel="self" />
|
|
||||||
<link href="{{ meta.url }}/" rel="alternate" type="text/html" />
|
|
||||||
<id>{{ meta.url }}/</id>
|
|
||||||
<author>
|
|
||||||
<name>{{ meta.author }}</name>
|
|
||||||
</author>
|
|
||||||
{% set movies = collections.movie %}
|
{% set movies = collections.movie %}
|
||||||
{% set tv = collections.tv %}
|
{% set tv = collections.tv %}
|
||||||
{% set data = movies.concat(tv) %}
|
{% set data = movies.concat(tv) %}
|
||||||
{% for item in data %}
|
{% from "macros/feed.njk" import feed %}
|
||||||
<entry>
|
{{ feed(meta, data, page.date, permalink, title, filterTag) }}
|
||||||
<id>{{ meta.url }}{{ item.url }}</id>
|
|
||||||
<title>{{ item.data.title | escape }}</title>
|
|
||||||
<link href="{{ item.url }}{{ post.url }}" />
|
|
||||||
<pubDate>{{ item.date }}</pubDate>
|
|
||||||
{%- for tag in item.data.tags | filter(["tv", "movie"]) %}<category term="{{ tag }}" />{%- endfor %}
|
|
||||||
<content type="html">{{ item.content | escape }}</content>
|
|
||||||
</entry>
|
|
||||||
{% endfor %}
|
|
||||||
</feed>
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue