krz/orgo

Lightning fast org-mode static site generator. fast go org-mode static-site-generator

guide/03-collections.html

212 lines · 46880 bytes

  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4<meta charset="utf-8">
  5<meta name="viewport" content="width=device-width, initial-scale=1">
  6<title>Collections &middot; orgo</title>
  7<meta name="description" content="Generated pages — blog indexes, tag pages, pagination and RSS feeds.">
  8<link rel="icon" href="../favicon.svg" type="image/svg+xml">
  9<link rel="stylesheet" href="../theme.css">
 10<link rel="stylesheet" href="../syntax.css">
 11<link rel="stylesheet" href="../style.css">
 12</head>
 13<body>
 14<header class="site">
 15<a class="site-title" href="../index.html">orgo</a>
 16<nav>
 17<a href="../install.html">Install</a>
 18<a href="../quickstart.html">Quick start</a>
 19<a href="index.html">Guide</a>
 20</nav>
 21</header>
 22<main>
 23<h1>Collections</h1>
 24<p class="lede">The one kind of output that is not a translation of some input.</p>
 25<nav class="toc" aria-label="On this page">
 26<h2>On this page</h2>
 27<ul>
 28<li><a href="#a-blog-index">A blog index</a>
 29<ul>
 30<li><a href="#sorting">Sorting</a></li>
 31<li><a href="#grouping-a-listing-by-year">Grouping a listing by year</a></li>
 32<li><a href="#full-content-feeds">Full-content feeds</a></li>
 33<li><a href="#nav-true">nav = true</a></li>
 34</ul></li>
 35<li><a href="#tag-pages">Tag pages</a>
 36<ul>
 37<li><a href="#grouping-by-anything">Grouping by anything</a></li>
 38<li><a href="#two-tags-that-would-collide-are-an-error">Two tags that would collide are an error</a></li>
 39</ul></li>
 40<li><a href="#pagination">Pagination</a></li>
 41<li><a href="#an-rss-feed">An RSS feed</a></li>
 42<li><a href="#every-setting">Every setting</a></li>
 43<li><a href="#incremental-behaviour">Incremental behaviour</a></li>
 44</ul>
 45</nav>
 46<p>A blog index exists because a set of posts exists, not because someone wrote <code class="verbatim">index.org</code>. A <code class="verbatim">[[collections]]</code> block declares one: a source directory in, an output file out, through a template.</p>
 47<p>Keeping it declarative means an RSS feed is the same mechanism with an XML template rather than a second feature.</p>
 48<h2 id="a-blog-index">A blog index</h2>
 49<pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span>
 50<span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>blog<span class="punctuation definition string end toml">&quot;</span></span>             <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> directory to list; empty means every page
 51</span><span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>blog/index.html<span class="punctuation definition string end toml">&quot;</span></span>  <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> where to write it
 52</span><span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>list.html<span class="punctuation definition string end toml">&quot;</span></span>      <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> template file name
 53</span><span class="variable other key toml">title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>Blog<span class="punctuation definition string end toml">&quot;</span></span>
 54<span class="variable other key toml">sort</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>date<span class="punctuation definition string end toml">&quot;</span></span>               <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> date | title | path
 55</span><span class="variable other key toml">order</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>desc<span class="punctuation definition string end toml">&quot;</span></span>              <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> desc | asc
 56</span><span class="variable other key toml">nav</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span>                  <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> put this page in the site nav</span></span></code></pre>
 57<p>The template receives the collection's entries as <code class="verbatim">pages</code>, already sorted, plus the usual <code class="verbatim">site</code>, <code class="verbatim">nav</code> and <code class="verbatim">root</code>:</p>
 58<pre><code class="language-html highlight"><span class="text html basic">{% extends &quot;base.html&quot; %}
 59{% block content %}
 60<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">&gt;</span></span>
 61  {% for post in pages %}
 62  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
 63    <span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">time</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">datetime</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ post.date_iso }}<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>{{ post.date_iso }}<span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">time</span><span class="punctuation definition tag end html">&gt;</span></span>
 64    <span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ root }}{{ post.url }}<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>{{ post.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">&gt;</span></span>
 65    <span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">&gt;</span></span>{{ post.excerpt | truncate(180) }}<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">&gt;</span></span>
 66  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
 67  {% endfor %}
 68<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">&gt;</span></span>
 69{% endblock %}</span></code></pre>
 70<h3 id="sorting">Sorting</h3>
 71<p><code class="verbatim">sort</code> is <code class="verbatim">date</code> (default), <code class="verbatim">title</code> or <code class="verbatim">path</code>; <code class="verbatim">order</code> is <code class="verbatim">desc</code> (default) or <code class="verbatim">asc</code>.</p>
 72<p>Date sorting uses <code class="verbatim">page.date_iso</code>, the <code class="verbatim">YYYY-MM-DD</code> extracted from <code class="verbatim">#+DATE:</code> whatever org syntax it was written in — <code class="verbatim">[2025-09-05 Fri 10:21:00]</code>, <code class="verbatim">&lt;2024-05-01 Wed&gt;</code> or a bare <code class="verbatim">2024-05-01</code> all work.</p>
 73<p><strong>Pages with no parseable date sort last in either direction</strong>, so an undated draft never leads a dated archive.</p>
 74<h3 id="grouping-a-listing-by-year">Grouping a listing by year</h3>
 75<p>An archive usually wants year headings, and that is a <strong>template</strong> decision rather than a config one — the entries are already in the right order, they just need breaking up. <code class="verbatim">page.year</code> exists for exactly this, because minijinja's <code class="verbatim">groupby</code> takes an attribute name and cannot slice a date itself:</p>
 76<pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">ul</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">post-list</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
 77{% for year, posts in pages | groupby(&quot;year&quot;) | reverse %}
 78  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">post-list-year</span><span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>{{ year if year else &quot;undated&quot; }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
 79  {% for entry in posts %}
 80  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">time</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">datetime</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ entry.date_iso }}<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>{{ entry.date_iso }}<span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">time</span><span class="punctuation definition tag end html">&gt;</span></span>
 81      <span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ root }}{{ entry.url }}<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>{{ entry.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
 82  {% endfor %}
 83{% endfor %}
 84<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">&gt;</span></span></span></code></pre>
 85<p><code class="verbatim">groupby</code> sorts its groups ascending, so <code class="verbatim">| reverse</code> puts the newest year first — matching the <code class="verbatim">order = "desc"</code> the entries themselves already use, and leaving undated pages in a group of their own at the end.</p>
 86<p>Name that group in the template rather than with <code class="verbatim">groupby</code>'s <code class="verbatim">default=</code> argument, which covers an attribute that is <strong>missing</strong> and not one that is null — an undated page has a <code class="verbatim">year</code>, and it is <code class="verbatim">none</code>.</p>
 87<h3 id="full-content-feeds">Full-content feeds</h3>
 88<p>A feed usually carries whole posts, and a subscriber handed excerpts instead has lost something. <code class="verbatim">include_content</code> gives the template each entry's rendered HTML as <code class="verbatim">entry.content</code>:</p>
 89<pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span>
 90<span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>blog<span class="punctuation definition string end toml">&quot;</span></span>
 91<span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>feed.xml<span class="punctuation definition string end toml">&quot;</span></span>
 92<span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>feed.xml<span class="punctuation definition string end toml">&quot;</span></span>
 93<span class="variable other key toml">include_content</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span></span></code></pre>
 94<pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">description</span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag sgml html"><span class="punctuation definition tag html">&lt;!</span><span class="constant other inline-data html">[CDATA[{{ post.content | safe }}]]</span><span class="punctuation definition tag html">&gt;</span></span><span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">description</span><span class="punctuation definition tag end html">&gt;</span></span></span></code></pre>
 95<p>Off by default, because it costs a render of every listed page each time the listing is rebuilt. That cost is only paid when the listing is <strong>not</strong> cached, and the listing's cache key covers its entries' content — so a body edit reaches the feed, and an unchanged site pays nothing.</p>
 96<p>Everywhere else <code class="verbatim">entry.content</code> is <code class="verbatim">none</code>, since carrying every page's body in every listing context would be most of a site's memory for nothing.</p>
 97<h3 id="nav-true">nav = true</h3>
 98<p>The listing page joins the site navigation. This is how a section landing page — <code class="verbatim">/blog/</code>, <code class="verbatim">/notes/</code> — gets into a nav built from top-level pages, and it points at the right thing: the section, not any one post in it.</p>
 99<h2 id="tag-pages">Tag pages</h2>
100<p>Add <code class="verbatim">group_by</code> and the collection emits one page <em>per group</em> instead of one page total, plus an optional index of the groups:</p>
101<pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span>
102<span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>blog<span class="punctuation definition string end toml">&quot;</span></span>
103<span class="variable other key toml">group_by</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>tags<span class="punctuation definition string end toml">&quot;</span></span>                  <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> &quot;tags&quot;, or any #+KEYWORD: name
104</span><span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>tags/{tag}.html<span class="punctuation definition string end toml">&quot;</span></span>         <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> {tag} becomes each group&#39;s slug
105</span><span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>tag.html<span class="punctuation definition string end toml">&quot;</span></span>
106<span class="variable other key toml">title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>Tagged: {tag}<span class="punctuation definition string end toml">&quot;</span></span>
107<span class="variable other key toml">index_output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>tags/index.html<span class="punctuation definition string end toml">&quot;</span></span>
108<span class="variable other key toml">index_template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>tags.html<span class="punctuation definition string end toml">&quot;</span></span>
109<span class="variable other key toml">index_title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>Tags<span class="punctuation definition string end toml">&quot;</span></span>
110<span class="variable other key toml">nav</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span>                         <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> adds the *index*, not every tag</span></span></code></pre>
111<p>A group page receives its own posts as <code class="verbatim">pages</code> and itself as <code class="verbatim">group</code>:</p>
112<pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">&gt;</span></span>{{ group.name }} ({{ group.count }})<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">&gt;</span></span>
113{% for post in pages %}<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ root }}{{ post.url }}<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>{{ post.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">&gt;</span></span>{% endfor %}</span></code></pre>
114<p>The index receives <code class="verbatim">groups</code>, sorted by name:</p>
115<pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">&gt;</span></span>{% for tag in groups %}
116  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span><span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ root }}{{ tag.url }}<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>{{ tag.name }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">&gt;</span></span> ({{ tag.count }})<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">&gt;</span></span>
117{% endfor %}<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">&gt;</span></span></span></code></pre>
118<h3 id="grouping-by-anything">Grouping by anything</h3>
119<p><code class="verbatim">group_by = "tags"</code> is multi-valued: a post appears under every tag it carries. Any other value names a single-valued <code class="verbatim">#+KEYWORD:</code>, so <code class="verbatim">group_by = "category"</code> buckets pages by <code class="verbatim">#+CATEGORY:</code> with no extra machinery.</p>
120<h3 id="two-tags-that-would-collide-are-an-error">Two tags that would collide are an error</h3>
121<p><code class="verbatim">web_dev</code> and <code class="verbatim">web@dev</code> both slugify to <code class="verbatim">web-dev</code>, so one page would silently overwrite the other. That is a build error naming both values.</p>
122<h2 id="pagination">Pagination</h2>
123<pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span>
124<span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>blog<span class="punctuation definition string end toml">&quot;</span></span>
125<span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>blog/index.html<span class="punctuation definition string end toml">&quot;</span></span>
126<span class="variable other key toml">paginate</span> <span class="keyword operator assignment toml">=</span> <span class="constant numeric toml">10</span>
127<span class="variable other key toml">paginate_output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>blog/page/{n}.html<span class="punctuation definition string end toml">&quot;</span></span>   <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> {n} is the 1-based page number</span></span></code></pre>
128<p><strong>Page 1 stays at <code class="verbatim">output</code></strong>, so a section's canonical URL never moves as its page count changes. Only pages 2..N are named by <code class="verbatim">paginate_output</code>.</p>
129<p>The template gets a <code class="verbatim">paginator</code>:</p>
130<pre><code class="language-html highlight"><span class="text html basic">{% if paginator and paginator.total &gt; 1 %}
131<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag block any html">nav</span><span class="punctuation definition tag end html">&gt;</span></span>
132  {% if paginator.prev_url %}<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ paginator.prev_url }}<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Newer<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">&gt;</span></span>{% endif %}
133  {% for pg in paginator.pages %}
134    <span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ pg.url }}<span class="punctuation definition string end html">&quot;</span></span></span>{% <span class="entity other attribute-name html">if</span> <span class="entity other attribute-name html">pg.current</span> %} <span class="meta attribute-with-value html"><span class="entity other attribute-name html">aria-current</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>page<span class="punctuation definition string end html">&quot;</span></span></span>{% <span class="entity other attribute-name html">endif</span> %}<span class="punctuation definition tag end html">&gt;</span></span>{{ pg.number }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">&gt;</span></span>
135  {% endfor %}
136  {% if paginator.next_url %}<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ paginator.next_url }}<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>Older<span class="meta tag inline a html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">&gt;</span></span>{% endif %}
137<span class="meta tag block any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag block any html">nav</span><span class="punctuation definition tag end html">&gt;</span></span>
138{% endif %}</span></code></pre>
139<table>
140<thead>
141<tr><th>Field</th><th>Meaning</th></tr>
142</thead>
143<tbody>
144<tr><td><code class="verbatim">current</code>, <code class="verbatim">total</code></td><td>This page's number, and how many there are.</td></tr>
145<tr><td><code class="verbatim">per_page</code>, <code class="verbatim">total_entries</code></td><td>As configured, and across the whole listing.</td></tr>
146<tr><td><code class="verbatim">prev_url</code>, <code class="verbatim">next_url</code></td><td><code class="verbatim">none</code> at the ends.</td></tr>
147<tr><td><code class="verbatim">first_url</code>, <code class="verbatim">last_url</code></td><td>Always present.</td></tr>
148<tr><td><code class="verbatim">pages</code></td><td><code class="verbatim">[{number, url, current}]</code> for a numbered strip.</td></tr>
149</tbody>
150</table>
151<p>Every URL is relative to the page carrying it, so links work from page 1 (<code class="verbatim">page/2.html</code>) and from page 5 (<code class="verbatim">../index.html</code>, <code class="verbatim">6.html</code>) without the template knowing where it sits. An unpaginated collection has no <code class="verbatim">paginator</code> at all, so <code class="verbatim">{% if paginator %}</code> is a reliable test in a shared template.</p>
152<p>Grouping and pagination compose: each group paginates independently, which is why <code class="verbatim">paginate_output</code> needs <code class="verbatim">{tag}</code> as well as <code class="verbatim">{n}</code> on a grouped collection.</p>
153<h2 id="an-rss-feed">An RSS feed</h2>
154<p>A feed is a listing page with an XML template. Templates load by full filename and any extension, so:</p>
155<pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span>
156<span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>blog<span class="punctuation definition string end toml">&quot;</span></span>
157<span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>feed.xml<span class="punctuation definition string end toml">&quot;</span></span>
158<span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>feed.xml<span class="punctuation definition string end toml">&quot;</span></span>
159<span class="variable other key toml">title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">&quot;</span>Feed<span class="punctuation definition string end toml">&quot;</span></span></span></code></pre>
160<pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag preprocessor xml html"><span class="punctuation definition tag begin html">&lt;?</span><span class="entity name tag xml html">xml</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">version</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>1.0<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">encoding</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>utf-8<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">?&gt;</span></span>
161<span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">rss</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">version</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>2.0<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">xmlns:atom</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>http://www.w3.org/2005/Atom<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>
162<span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">channel</span><span class="punctuation definition tag end html">&gt;</span></span>
163  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">&gt;</span></span>{{ site.title }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">&gt;</span></span>
164  <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">&gt;</span></span>{{ &quot;index.html&quot; | absolute }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">&gt;</span></span>
165  <span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">atom:link</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>{{ page.url | absolute }}<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">rel</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>self<span class="punctuation definition string end html">&quot;</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>application/rss+xml<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">/&gt;</span></span>
166  {% for post in pages %}
167  <span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">item</span><span class="punctuation definition tag end html">&gt;</span></span>
168    <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">&gt;</span></span>{{ post.title }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">&gt;</span></span>
169    <span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">&gt;</span></span>{{ post.url | absolute }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">&gt;</span></span>
170    <span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">guid</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">isPermaLink</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">&quot;</span>true<span class="punctuation definition string end html">&quot;</span></span></span><span class="punctuation definition tag end html">&gt;</span></span>{{ post.url | absolute }}<span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">guid</span><span class="punctuation definition tag end html">&gt;</span></span>
171    <span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;</span><span class="entity name tag other html">pubDate</span><span class="punctuation definition tag end html">&gt;</span></span>{{ post.date_iso | rfc822 }}<span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">pubDate</span><span class="punctuation definition tag end html">&gt;</span></span>
172  <span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">item</span><span class="punctuation definition tag end html">&gt;</span></span>
173  {% endfor %}
174<span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">channel</span><span class="punctuation definition tag end html">&gt;</span></span>
175<span class="meta tag other html"><span class="punctuation definition tag begin html">&lt;/</span><span class="entity name tag other html">rss</span><span class="punctuation definition tag end html">&gt;</span></span></span></code></pre>
176<p>This needs <code class="verbatim">site.base_url</code>, because a feed with relative links is invalid everywhere it is read. <code class="verbatim">orgo init</code> writes this template and leaves the collection commented out until there is a base URL to make absolute links from.</p>
177<h2 id="every-setting">Every setting</h2>
178<table>
179<thead>
180<tr><th>Key</th><th>Default</th><th>Meaning</th></tr>
181</thead>
182<tbody>
183<tr><td><code class="verbatim">source</code></td><td>=""</td><td>Directory to list. Empty means every page.</td></tr>
184<tr><td><code class="verbatim">output</code></td><td><code class="verbatim">"index.html"</code></td><td>Where to write. Needs <code class="verbatim">{tag}</code> when grouped.</td></tr>
185<tr><td><code class="verbatim">template</code></td><td><code class="verbatim">"list.html"</code></td><td>Template file name.</td></tr>
186<tr><td><code class="verbatim">title</code></td><td><code class="verbatim">"Index"</code></td><td><code class="verbatim">{{ page.title }}</code>. <code class="verbatim">{tag}</code> is substituted when grouped.</td></tr>
187<tr><td><code class="verbatim">group_by</code></td><td>=""</td><td><code class="verbatim">"tags"</code>, or a <code class="verbatim">#+KEYWORD:</code> name. Empty means one page.</td></tr>
188<tr><td><code class="verbatim">index_output</code></td><td>=""</td><td>Where to write the group index. Empty means none.</td></tr>
189<tr><td><code class="verbatim">index_template</code></td><td><code class="verbatim">"tags.html"</code></td><td>Template for the group index.</td></tr>
190<tr><td><code class="verbatim">index_title</code></td><td><code class="verbatim">"Tags"</code></td><td>Title for the group index.</td></tr>
191<tr><td><code class="verbatim">sort</code></td><td><code class="verbatim">"date"</code></td><td><code class="verbatim">date</code>, <code class="verbatim">title</code> or <code class="verbatim">path</code>.</td></tr>
192<tr><td><code class="verbatim">order</code></td><td><code class="verbatim">"desc"</code></td><td><code class="verbatim">desc</code> or <code class="verbatim">asc</code>.</td></tr>
193<tr><td><code class="verbatim">paginate</code></td><td><code class="verbatim">0</code></td><td>Entries per page. <code class="verbatim">0</code> means no pagination.</td></tr>
194<tr><td><code class="verbatim">paginate_output</code></td><td>=""</td><td>Where pages 2..N go. Needs <code class="verbatim">{n}</code>.</td></tr>
195<tr><td><code class="verbatim">nav</code></td><td><code class="verbatim">false</code></td><td>Add this page — or its index, when grouped — to the nav.</td></tr>
196</tbody>
197</table>
198<h2 id="incremental-behaviour">Incremental behaviour</h2>
199<p>A listing page is cached on the entries it lists, so:</p>
200<ul>
201<li>Adding a post re-renders that post, its section index, its tag pages and the tag index whose counts changed. Nothing else.</li>
202<li>Editing a post's <strong>body</strong> changes no listing metadata, so the index is not touched at all.</li>
203<li>Retitling a post does re-render the listings that display the title.</li>
204</ul>
205<p>A tag page depends on its own posts and not on the other groups, which is why <code class="verbatim">groups</code> is given to the index and not to every group page: a page that can see every group would depend on every group, and one new post would re-render every tag page.</p>
206<p>When a collection shrinks below a page boundary, the pages that no longer exist are deleted rather than left serving stale content.</p>
207</main>
208<footer class="site">
209Built with orgo &mdash; these docs are an orgo site.
210</footer>
211</body>
212</html>