krz/orgo

Lightning fast org-mode static site generator.

clone: git clone https://gitbay.org/krz/orgo.git

v0.20.2: docs/guide/06-authoring.org · raw

  1#+TITLE: Authoring
  2#+DESCRIPTION: URLs, drafts, excerpts, tables of contents — the metadata that shapes a page.
  3#+LEDE: What to put at the top of a file, and what each keyword buys you.
  4
  5* URLs
  6
  7By default a source path becomes the matching output path: =blog/post.org=  8=blog/post.html=.
  9
 10=#+SLUG:= overrides the *filename*, never the directory:
 11
 12#+BEGIN_SRC org
 13,#+TITLE: AES Encryption
 14,#+SLUG: aes-encryption
 15#+END_SRC
 16
 17=blog/2018-11-28-aes-encryption.org= now publishes at =blog/aes-encryption.html=. This is
 18how a date-prefixed filename — useful for sorting in a file manager — becomes a clean
 19address.
 20
 21Slugs are reduced to a single safe path component, so a slug cannot escape the output
 22directory however it was written. Two pages claiming one URL is a build error rather than
 23one silently overwriting the other.
 24
 25Links follow slugs automatically: =[[file:blog/2018-11-28-aes-encryption.org]]= resolves
 26to =blog/aes-encryption.html=.
 27
 28* Drafts
 29
 30#+BEGIN_SRC org
 31,#+DRAFT: t
 32#+END_SRC
 33
 34The page is not written at all, and is absent from listings, tag pages and navigation —
 35not merely unlinked.
 36
 37It is also out of the symbol table, so a link *to* a draft is reported as a broken link.
 38That is deliberate: it is what that link would be on the published site, and better found
 39now than by a reader.
 40
 41#+BEGIN_SRC sh
 42orgo serve content -o _site --drafts
 43#+END_SRC
 44
 45The keyword is read forgivingly. =t=, =yes=, =1= and a bare =#+DRAFT:= all mean draft,
 46because writing the keyword at all is the signal. Only an explicit =nil=, =false=, =no=,
 47=0= or =off= means published — publishing someone's unfinished post because they typed
 48=yes= instead of =t= is the wrong way to be strict.
 49
 50* Dates
 51
 52#+BEGIN_SRC org
 53,#+DATE: <2026-02-02 Mon>
 54,#+DATE: [2025-09-05 Fri 10:21:00]
 55,#+DATE: 2024-05-01
 56#+END_SRC
 57
 58All three work. =page.date= keeps what you wrote, and =page.date_iso= is the
 59=YYYY-MM-DD= inside it — the value listings sort on and templates usually print.
 60
 61A page with no parseable date sorts *last* in a dated listing, in either direction, so a
 62draft with no date never leads an archive.
 63
 64* Excerpts
 65
 66=page.excerpt= is =#+DESCRIPTION:= when the page sets one, and its first paragraph
 67otherwise:
 68
 69#+BEGIN_SRC org
 70,#+DESCRIPTION: How the borrow checker thinks about lifetimes.
 71#+END_SRC
 72
 73The fallback matters more than the keyword: it means a listing has something to show
 74whether or not the author ever thought about summaries. Use =truncate= in the template to
 75cut a long paragraph to size.
 76
 77* Reading time
 78
 79=page.word_count= and =page.reading_time= (minutes at 200 wpm, rounded up) count *prose
 80only*. Source and example blocks are excluded, because a post that is mostly a shell
 81transcript should not read as an hour's work. =#+TITLE:= is metadata rendered as chrome,
 82so it is not counted either.
 83
 84* Tags
 85
 86#+BEGIN_SRC org
 87,#+FILETAGS: :rust:web:
 88#+END_SRC
 89
 90Available as =page.tags=, and the input to tag pages — see
 91[[file:03-collections.org][Collections]].
 92
 93* Table of contents
 94
 95Every page's heading tree is available as =page.toc= without any markup in the file. Turn
 96it off for one document the way org already does:
 97
 98#+BEGIN_SRC org
 99,#+OPTIONS: toc:nil
100#+END_SRC
101
102Or site-wide with =[html] toc = false=. Rendering it is the template's business; see
103[[file:04-templates.org][Templates]].
104
105* Section numbers
106
107Off by default, unlike Emacs. Turn them on for one document:
108
109#+BEGIN_SRC org
110,#+OPTIONS: num:t
111#+END_SRC
112
113Or site-wide with =[html] section_numbers = true=.
114
115* Your own metadata
116
117Every =#+KEYWORD:= reaches templates under its lowercased name:
118
119#+BEGIN_SRC org
120,#+SUBTITLE: A closer look
121,#+REVIEWED_BY: someone
122#+END_SRC
123
124#+BEGIN_SRC html
125{% if page.keywords.subtitle %}<p class="subtitle">{{ page.keywords.subtitle }}</p>{% endif %}
126#+END_SRC
127
128Nothing needs to be registered, and orgo needs no release to support a keyword you
129invented.
130
131* Assets
132
133Any non-=.org= file in the source directory is copied to the output, preserving layout:
134=content/img/diagram.png==_site/img/diagram.png=. Reference it from a page with an
135ordinary relative link, and from a template with ={{ root }}img/diagram.png=.
136
137Four things are *never* published:
138
139- Dot-entries such as =.git= and =.env=. A source directory is often a repository, and
140  publishing its history next to the homepage is a real way to leak a project.
141- =orgo.toml=, which is a build input.
142- The templates directory, likewise.
143- The output directory, when it lives inside the source — so =orgo build . -o _site=
144  does the obvious thing rather than copying its own output back into itself.
145
146Note that excluding dot-entries also means =.well-known/= cannot be published.