docs/content/features/feeds.md (3501B)
1 +++
2 title = "Feeds"
3 description = "One Atom feed per language, from the dates you put in front matter"
4 weight = 30
5 toc = true
6 +++
7
8 Give a page a `date` and it enters that language's feed.
9
10 ```toml
11 +++
12 title = "Release 0.2.0"
13 description = "What changed"
14 date = 2026-07-26
15 +++
16 ```
17
18 ```
19 public/
20 ├── feed-en.xml
21 └── feed-ko.xml
22 ```
23
24 ## No dates, no feed
25
26 A language with no dated pages gets no file, and templates get no
27 `site.feed` to link. An empty feed is worse than an absent one: a subscriber who
28 sees nothing arriving reads it as broken rather than as empty on purpose.
29
30 This documentation has no dated pages, so this site publishes no feed. That is
31 the feature working.
32
33 ## Autodiscovery
34
35 ```html
36 {% if site.feed %}
37 <link rel="alternate" type="application/atom+xml" title="{{ site.title }}" href="{{ site.feed }}">
38 {% endif %}
39 ```
40
41 `site.feed` is the current language's feed, or nothing. The `if` is not
42 defensive — it is the whole rule.
43
44 ## Atom, not RSS 2.0
45
46 RSS dates are RFC 2822: `Tue, 26 Jul 2026 00:00:00 +0000`. That format needs a
47 day-of-week we would have to compute and English month names we would have to
48 embed — including in a Korean feed, where `Jul` is simply wrong.
49
50 Atom uses RFC 3339, which is the shape a TOML date already has. Less code, one
51 fewer thing to get subtly wrong, and every reader written this century handles
52 Atom.
53
54 ## What is in it
55
56 The 20 most recent dated pages, newest first, each with a title, a permalink, an
57 `updated` timestamp, and the `description` as its summary. Twenty is a cap, not
58 a coincidence — a feed that grows without limit eventually becomes a download.
59
60 Pages that land on the same instant are ordered by title, so they come out in
61 the same order on every build. Since a bare date becomes midnight UTC, in
62 practice that is every pair of posts written on the same day.
63
64 A date with no time becomes midnight UTC. Atom will not accept a bare date, and
65 a reader that cannot parse a timestamp drops the entry without telling anyone.
66
67 An offset is carried through as written — `2026-07-26T09:00:00+09:00` stays that,
68 because RFC 3339 accepts any offset and rewriting it as `Z` would publish a
69 morning in Seoul as an evening in Seoul. Ordering still compares instants rather
70 than the text, so a `+09:00` morning sorts before a `Z` afternoon of the same day.
71
72 A `date` that TOML reads as a time with no date — `10:30:00` — is an error rather
73 than a value quietly dropped. You wrote a date; the build should not disagree in
74 silence.
75
76 ## Sorting by date
77
78 ```toml
79 # content/posts/_index.md
80 +++
81 title = "Posts"
82 sort_by = "date"
83 +++
84 ```
85
86 **Newest first**, unlike `weight` and `title`, which ascend. It is the order
87 anyone reading a dated list expects. Pages without a date go last rather than
88 first, which is what happens if you sort a missing date as zero.
89
90 ## Showing the date
91
92 There is no date filter and no format string. `page.date` is the parts:
93
94 | | |
95 |---|---|
96 | `page.date.year` | `2026` |
97 | `page.date.month` | `7` |
98 | `page.date.day` | `26` |
99 | `page.date.date` | `2026-07-26`, for `<time datetime>` |
100 | `page.date.iso` | `2026-07-26T00:00:00Z` |
101
102 ```html
103 {% if page.date %}
104 <time datetime="{{ page.date.date }}">{{ page.date.year }}년 {{ page.date.month }}월 {{ page.date.day }}일</time>
105 {% endif %}
106 ```
107
108 A format-string filter would mean shipping a date-formatting mini-language and
109 then owning locale rules for every language someone writes in. The parts are
110 data, and a template already knows how to arrange data.