Collards Manual
Table of Contents
- 1 Introduction
- 2 Making your first site
- 3 Content Formats
- 4 CLI Commands
- 5 The Core API
- 6 Content Types
- 7 Glossary
[in package COLLARDS.DOCS]
1 Introduction
A static site generator for those who love Markdown and parens.
A long time ago, I wrote a blog engine called Coleslaw. It was written on a lark as I and two friends all resolved to get off Wordpress. We scheduled a lunch and learn for our unwritten blog engines a week later. The initial implementation was thrown together in a weekend. For many years, it was enough.
Collards is a simple static site generator. It offers:
Markdown blog posts with 3bmd
Custom pages built from markdown with 3bmd or lisp with Spinneret
Local preview with hot reloading via Hunchentoot
Deployment via Rsync with support for subdomains
CLI commands via Clingon to
build
,serve
, anddeploy
Optional RSS feeds, tag indexes, and year indexes
A straightforward API for custom content types
1.1 Links
[builds]: https://builds.sr.ht/~kingcons/collards The official repository and [CI builds][builds] are available.
-
- Version: 0.7.1
- Description: A static site generator
- Licence: MIT
- Author: Brit Butler
- Mailto: brit@kingcons.io
- Homepage: https://collards.kingcons.io
- Source control: GIT
- Depends on: 3bmd, 3bmd-ext-code-blocks, 3bmd-ext-wiki-links, cl-ppcre, cl-store, clingon, file-notify, hunchentoot, mgl-pax, nyaml, serapeum, spinneret, westbrook
2 Making your first site
2.1 Installation
While Collards should be portable to any OS that runs Lisp, it is only tested on Linux. Notably, the serve command may not work on non-linux OSes.
The only way to install Collards today is building it yourself.
Cloning the repository and running make app
should be enough.
After that, place bin/collards
anywhere on your $PATH
.
While the Makefile builds with SBCL by default, passing LISP=ccl
as an argument to make app
should be sufficient to build with Clozure CL.
Other lisps have not been tested.
For users of Guix, a package is provided in the repo so
running guix shell
will get you a working environment.
At some point, collards may become available via binaries or Quicklisp.
2.2 Creating a collards site
Once collards is installed, building a site involves creating a folder
(or git repo if preferred), adding a .collards
file, and then adding
markdown files to generate posts and pages, lisp files to generate
pages with custom templates, and feed
and collection
files to generate
RSS feeds or index pages.
When collards tries to build your site, it will look for a folder named "init" and load any lisp files within it that define custom templates or content types. Other than the init dir, collards will create a build dir and an assets dir if they are not present.
The assets dir is useful because any files placed under it are easy to
generate URLs for both in markdown content using wikilinks like so,
[[asset:example.jpg]]
, or from lisp with (site-url "asset:example.jpg")
.
The default templates expect a style.css
file within the assets folder
but if you don't want to have your CSS in assets you can customize the
templates by writing your init files however you like. Feel free to take
a peek at my init files as an example.
Once the config file is written, the collards
command can be run anywhere
within that site folder. Your config might be as simple as:
(:author "Melissa Rogers"
:domain "melissa.website"
:ignored ("drafts")
:title "Adventures in Code")
The config file itself strives to be small, requiring only values for an
Author, Domain, and Title. You can also provide a list of Ignored subfolders.
If you wish to use the deploy
command to rsync your build output to a
server, then you must also supply Server settings. Subdomains can optionally
be specified to send specific directories output to different paths on the
server.
An example config file can be viewed here. The other files in that
example
directory in the collards repo are used as data for the test suite.
For a look at a "production" site that may be more realistic, the repo for
my homepage may be of interest.
2.3 Adding Content
When collards builds a site, it will process all files that it recognizes and
copy any other files to an output directory. Then, that output directory can
be freely copied to a public webserver either with the deploy
command built
into collards or manually. The files in the output directory will be organized
the same way they were in the site folder. If all your markdown post files are
in a blog
folder, then the HTML files will go in a blog
output subfolder.
Collards recognizes files by extension (see: Content Types) and currently
knows about .lisp
files which are treated as pages, .md
files which are
treated as posts, and some custom files like rss.feed
which generates RSS
feeds and tag.collection
or recent.collection
which generate indexes of
posts with specific tags or posts in reverse chronological order.
As mentioned above, the examples folder in the project repo or my personal site may be useful to see examples of a live site.
2.4 Templates
init: https://git.sr.ht/~kingcons/kingcons.io/tree/collards/item/init Collards uses Spinneret for HTML generation. There are default templates lightly modified from my personal site that are provided as of verison 0.5 but you are encouraged to write your own by defining render methods in your init files if you are so inclined. My init files may be a useful guide.
No styling or CSS is provided by collards out of the box. The intent of this is merely to encourage people to design sites according to their own style. I think the web is better when we come to it authentically, offering a part of ourselves. I hope collards encourages that ethos.
Templates are methods on COLLARDS.CONTENT:RENDER
that take a content subclass
and a site instance as arguments and generate HTML using spinneret.
Collards will load all lisp files from the user's init
directory before
building so template definition and custom behavior can be defined there.
A simple post template with next/prev navigation might be:
;; Note: I recommend using package nicknames for convenience.
;; I.e. To allow for post:body instead of collards.post:body,
;; md:render-markdown instead of collards.markdown:render-markdown, etc
(defmethod content:render ((content post:post)
(site site:site))
(spinneret:with-html
(:doctype)
(:html
(:head
(:title "foo")
(:link :href css-path :rel "stylesheet" :type "text/css"))
(:body
(:div.navigation
(:p "Nav goes here"))
(:section
(:div.article-content
(:raw (md:render-markdown (post:body content))))
(:div.neighbors
(util:when-let (prev (registry:prev content))
(:a :href (content:url-for prev) (content:title prev)))
(util:when-let (next (registry:next content))
(:a :href (content:url-for next) (content:title next)))))
(:div.fineprint
(:hr)
"Unless otherwise credited all material CC-BY-SA"
(site:author site)))))
2.4.1 Template Utilities
[in package COLLARDS.TEMPLATES.HELPERS]
Writing custom templates for different content types is encouraged for Collards, but doing so without some helper utilities isn't a pleasant process. The following functions are provided to provide some quality of life tools and ensure you're able to focus on the styling of your site rather than getting basic details of content on the page.
[function] SITE-URL CONTENT-ID
Given a
CONTENT-ID
, return the URL for that content on the site.
[macro] SITE-LINK CONTENT-ID TITLE
Given a
CONTENT-ID
and aTITLE
, generate an A tag linking to the content.
[function] SHOW-NEIGHBORS CONTENT
Intended for use with Posts and Recent/Year collections. Given a
CONTENT
instance, generate HTML for a Section tag with links to the next and previous pieces of relevant content.
[function] SUMMARY POST &KEY (SHOW-TAGS
T
) (SHOW-SUMMARYT
)Intended for use when listing posts in a collection. Given a
POST
, return a Section tag with a link to the post and metadata showing the tags, date, and a summary of the post content if available.
[macro] WITH-LAYOUT (&KEY TITLE) &BODY BODY
Generate the HTML for a page with the supplied
TITLE
. TheBODY
will be placed in a Main tag surrounded by Hr tags. It is encouraged to redefineWITH-LAYOUT
to include navs and footers for your site if applicable.
[macro] WITH-PAGE (&KEY TITLE (CSS-ID "asset:style.css")) &BODY BODY
Generate an HTML page with the given
TITLE
,CSS-ID
, andBODY
.
3 Content Formats
As mentioned in Adding Content, Collards associates the extension of a file with a particular parser. Markdown is particularly noteworthy both because our parser provides some useful extensions and because it can be used to create Pages as well as Posts based on the frontmatter. A good example of how to write pages using Spinneret will be forthcoming in a future release.
3.1 Markdown
Since Collards uses 3bmd for markdown parsing, their docs will be the
most authoritative source of info on our markdown support. That said,
the behavior of frontmatter in .md
files is unique to collards and
it is valuable to have a brief overview of the useful extensions from
3bmd we have enabled.
3.1.1 Frontmatter
It is critical to supply metadata for content generated from markdown. All markdown files intended for processing by Collards are expected to have an initial frontmatter section written in YAML, which you may be familiar with from other blogware like Jekyll.
Example Post
Frontmatter is separated from the main content by ---
. For example:
---
title: Writing a Static Site Generator
tags: lisp, software-dev
date: 2025-02-03 08:00:00
draft: true
summary: Some experiences writing a static site generator for personal use.
---
## A Sensible Build System
In many ways, static site generators can be viewed as build tools to
turn arbitrary content formats into HTML...
This example demonstrates all the available metadata for our post format. Title is the only required field but comma-separated tags, date, draft, and summary are all supported. Collards does not handle actual Date parsing yet so a date format beginning with YYYY-MM-DD is recommended for now.
Example Page
example: https://git.sr.ht/~kingcons/kingcons.io/tree/main/item/init/slides.lisp
The only important attribute not demonstrated in the previous example is the
type
attribute. type
is an escape hatch to allow using markdown files for
generating Pages though nothing prevents you from using it to generate new
kinds of content defined in your config, like a remark.js powered
slideshow. My personal config actually does just that.
Much more common though is the desire to generate a Page from markdown which is useful since they don't participate in tag, year, or recent collections.
---
title: About Me
type: page
---
## Hobbies and Projects
...
3.1.2 Markdown Extensions
[pygments]: https://pygments.org/
Two 3bmd extensions are used: Code blocks and Wikilinks. Code blocks are
highlighted by Colorize but Pygments or Chroma can be used instead
by throwing one of the following snippets in your init files:
(setf 3bmd-code-blocks:*renderer* :pygments)
or
(setf 3bmd-code-blocks:*renderer* :chroma)
For further details, consult the 3bmd documentation.
Wikilinks will come in handy when you want to link between pieces of content
within a collards site. Using a Content ID between double brackets will look
up the specified content in the site registry and link to it. For example:
[[page:about]]
or [[post:2024-reflections]]
.
Additional arguments can be passed to wikilinks by separating them with the pipe character (|). The first argument will be used as the title, the second controls whether an 'a' tag or 'img' tag is used for the content. Thus, you can easily embed image assets in your posts: `[[asset:jurgen.jpg|jurgen|img]].
It is also possible for users to define their own markdown extensions by following the 3bmd grammar and enabling them in collards via the helper functions described in Markdown Utilities. One example to support easy bandcamp embeds can be seen here.
3.1.3 Markdown Utilities
[in package COLLARDS.MARKDOWN]
If you are writing custom templates or custom markdown extensions, these utility functions will support parsing frontmatter in markdown, rendering markdown, and enabling or disabling the user-defined extensions.
[function] ENABLE-EXTENSION SYMBOL
Ensure the 3bmd extension named by
SYMBOL
is bound toT
during rendering.
[function] DISABLE-EXTENSION SYMBOL
Ensure the 3bmd extension named by
SYMBOL
is not active during rendering.
[function] PARSE-FRONTMATTER HEADER
Parse the supplied
HEADER
as YAML returning a plist of initargs.
[function] RENDER-MARKDOWN MARKDOWN
Given a
MARKDOWN
formatted string, use 3bmd to render it and treat any wikilinks as objects to be looked up via URL-FOR in the registry.
4 CLI Commands
Answering the siren song of my own laziness, rather than laboriously writing docs about the CLI commands, I have repurposed the usage docs generated by Clingon. If anything is unclear, feel free to ask me questions via email or mastodon. I may be slow to respond.
4.1 The Collards command
[function] COLLARDS::COLLARDS/COMMAND
NAME: collards - A static site generator USAGE: collards [global-options] [<command>] [command-options] [arguments ...] OPTIONS: --help display usage information and exit --version display version and exit COMMANDS: build Build a collards site. serve Live reload changed site files and serve them locally. deploy Sync build output to the server specified in .collards. help Display help for collards. AUTHORS: Brit Butler LICENSE: MIT
4.2 The Build subcommand
[in package COLLARDS.BUILD]
-
NAME: build - Build a collards site. USAGE: build [options] [arguments ...] OPTIONS: --help display usage information and exit --version display version and exit -s, --site <VALUE> Path to the site to build [default: /home/build/collards/] -t, --timing Print the duration of each build step in milliseconds
4.3 The Serve subcommand
[in package COLLARDS.SERVE]
-
NAME: serve - Live reload changed site files and serve them locally. USAGE: serve [options] [arguments ...] OPTIONS: --help display usage information and exit --version display version and exit -p, --port <INT> The localhost port to use for site hosting. [default: 4242] -s, --site <VALUE> The path to the site to serve. [default: /home/build/collards/] -w, --swank-server Start a swank server to connect a REPL/editor to.
4.4 The Deploy subcommand
[in package COLLARDS.DEPLOY]
-
NAME: deploy - Sync build output to the server specified in .collards. USAGE: deploy [options] [arguments ...] OPTIONS: --help display usage information and exit --version display version and exit -n, --no-build Skip building the site. -s, --site <VALUE> The path of the site to build and deploy. [default: /home/build/collards/] -y, --assume-yes Rather than prompting, run all deploy commands immediately.
4.5 The Help subcommand
[in package COLLARDS.HELP]
Help takes a single topic as an argument and displays the documentation for that topic. If no topic is supplied, the list of available topics is shown.
-
NAME: help - Display help for collards. USAGE: help [options] [arguments ...] OPTIONS: --help display usage information and exit --version display version and exit
5 The Core API
It is time that we described the interfaces that power Collards.
The docs from this point forward are targeted towards developers more than users and describe the API of the data types and build process rather than details of using the CLI and building a site.
5.1 Building a Site
[in package COLLARDS.SITE]
Before doing anything else, collards needs a site object. The site object holds basic configuration info as well as a registry of Content Objects that will be used to build the site.
[config]: https://git.sr.ht/~kingcons/collards/tree/main/item/examples/.collards
A site can be built from any folder with a .collards
file which
serves as a configuration file that the site is created from.
An example collards config can be found [here][config].
-
An object to store configuration for the site under construction such as
AUTHOR
,DOMAIN
,TITLE
, and any other arguments. It also stores a registry, mapping @CONTENT-IDs to @CONTENT-OBJECTS which is queried during the build process.
[reader] SERVER SITE (:SERVER)
A plist of
:host
and:webroot
indicating the host and root path to deploy the build output to.
[reader] SUBDOMAINS SITE (:SUBDOMAINS)
An list of plists of
:path
and:domain
. This controls the subdomain to which specific paths in the build output will be deployed.
[reader] IGNORED SITE (:IGNORED)
A list of ignored top-level directories in the site. Assumed to be site-relative paths if they do not begin with '/'.
[reader] ASSET-DIR SITE (:ASSET-DIR)
A directory to store site assets in. Assumed to be a site-relative path if it does not begin with '/'.
[reader] BUILD-DIR SITE (:BUILD-DIR)
A directory to store the generated site in. Assumed to be a site-relative path if it does not begin with '/'.
[reader] INIT-DIR SITE (:INIT-DIR)
A directory in the source repo for user code. Lisp files in this directory are loaded first, non-lisp files are ignored. Assumed to be a site-relative path if it does not begin with '/'.
[accessor] REGISTRY SITE (= (SERAPEUM:DICT))
Used to store and lookup content during the site build.
The folder with the .collards
file is considered to be the 'site root'.
This is significant because Collards places rendered files in the build
folder relative to where they were under the site root.
As a consequence, it is essential that the .collards
file can be found
and useful to have helpers for determining the relative path of site files.
Errors will be raised if the .collards
file cannot be found or if there
are any missing arguments needed to construct a functioning site.
[function] RELATIVE-PATH PATHNAME
Given a
PATHNAME
under the site, return the relative path to the file. If a.collards
config file cannot be found from traversing the directories inPATHNAME
, aMISSING-CONFIG-ERROR
will be signaled.
[function] ABSOLUTE-PATH &REST ARGS
Build a path starting at the
ROOT-DIR
and appending all suppliedARGS
.
[condition] MISSING-CONFIG-ERROR ERROR
An error raised when no
.collards
file was found.
[condition] MISSING-SETTING-ERROR ERROR
An error raised when a required setting is undefined.
The *SITE*
instance is dynamically bound during the build process but
should not be interacted with by user code. LOAD-CONFIG
is used behind
the scenes to create the site instance.
[variable] *SITE* NIL
The
SITE
instance under construction.This should never be used directly by client code. All interactions with
*SITE*
are done through the documented interface and generally run from CLI tasks which dynamically bind the site.
[function] LOAD-CONFIG PATHNAME
Given a
PATHNAME
under a collards project, find and load the site config.
For situations where there is a need to iterate over the files in the site
a helper macro named DO-FILES
is provided. It automatically ignores the build,
asset, and init folders, any .git folder within the site, and hidden files.
A lower-level CALL-WITH-FILES
function is also provided for special cases.
[function] CALL-WITH-FILES DIRECTORY IGNORED FN
Walk the given
DIRECTORY
callingFN
on the files within each subdir. Hidden files and folders are excluded, along with any subpaths of theIGNORED
list.
[macro] DO-FILES (VAR) &BODY BODY
Iterate over the files within
*SITE*
, binding each toVAR
and then executingBODY
. Skips hidden files and folders as well as the subpaths ofIGNORED
.
5.2 Content Objects
[in package COLLARDS.CONTENT]
Content Objects are what collards uses to represent files it will render, usually to HTML, to build the site. All Content objects must have at least a source file they are loaded from and a title used to generate a slug.
-
A simple base class for any object that will be routable within collards. Relies on the title and slug to generate an identifier.
[accessor] MODIFIED-DATE CONTENT (= NIL)
The timestamp when source file was last written to disk.
[accessor] MODIFIED CONTENT (:MODIFIED)
A bool indicating if content changed since the last build.
As part of HTML generation, collards finds all files to process in the site
folder and builds content objects with them. To make a content object, we
first determine the file extension and call PARSE
on it, then take the result
of parsing and give that to GET-TYPE
which determines what class to BUILD
an instance of. NOTE
: The collection and feed types are treated
specially since they generate multiple HTML files from a single input file
and are also populated dynamically based on other registered content.
Consequently, user-defined content types can be created by defining:
A new subclass of
CONTENT
A
GET-TYPE
method with an eql-specialized file extension returning the class to instantiateA
PARSE
method on that extension returning a plist of initargsA
RENDER
method to accept an instance of the content and generate HTML (i.e. a template)
Nothing is required to "inform" collards about the new content type because we introspect the content methods at runtime to determine what files have the necessary machinery for parsing and building.
All this can be done in an init file so no upstream modification to collards is needed.
[generic-function] GET-TYPE METADATA EXTENSION
Given
METADATA
and anEXTENSION
, return the symbol of a class to instantiate.METADATA
can supply a:type
key to override the result.
[generic-function] PARSE PATHNAME EXTENSION
Read
PATHNAME
to parse metadata for the givenEXTENSION
.
[generic-function] RENDER CONTENT SITE
Generate HTML for the given
CONTENT
usingSITE
if needed.
[function] FIND-SUBCLASS NAME
Search for an appropriate subclass of
CONTENT
matchingNAME
.
[function] KNOWN-TYPE? PATHNAME
Search for an applicable
PARSE
method forPATHNAME
. If a match is found, return the extension as a keyword.
[function] BUILD PATHNAME
Make a content object from the supplied
PATHNAME
.
Since pages need to have unique, safe URLs we provide ID
and PATH
functions that help determine where content should reside on the site
and provide a shorthand for uniquely identifying it. SLUGIFY
is run on
the TITLE
of all content during BUILD
to help determine its output path.
[function] ID CONTENT
Generate a unique identifier for
CONTENT
based on the class name and slug of the content. See: @CONTENT-ID and @SLUG.
[function] PATH CONTENT
Return the relative path of
CONTENT
under the site.
[function] SLUGIFY STRING
Transform
STRING
by first substituting dashes for whitespace as defined bySERAPEUM:WHITESPACEP
, then removing any non-alphanumeric chars besides '-' or '/', and downcasing the result.
Finally, there are some internal helpers for determining urls and whether URLs should be relative or absolute, mostly for the build and serve commands.
[variable] *RELATIVE-URLS* NIL
This controls whether
URL-FOR
generates relative or absolute URLs. It is used to ensure that the serve command produces a working local site.
[generic-function] OUTPUT-PATH-FOR CONTENT &KEY EXTENSION
Generate an absolute path for
CONTENT
under the build dir.
[generic-function] URL-FOR CONTENT &KEY EXTENSION
Generate a URL for
CONTENT
.
5.3 The Site Registry
[in package COLLARDS.REGISTRY]
The Registry supports storing and retrieving content objects along with a number of utility functions useful for building the site.
The most relevant functions are REGISTER
and LOOKUP
for storage and retrieval.
There is also a low-level macro, DO-CONTENT
, for iterating over the registry
items matching a condition, utility functions to FETCH
or PURGE
all content
matching a condition, and SIBLINGS
for finding other items of the same type.
[generic-function] LOOKUP CONTENT-ID
Given a
CONTENT-ID
, search for a matching piece of content in the registry. If no match is found,MISSING-CONTENT-ERROR
is signaled.
[generic-function] REGISTER CONTENT
Register the
CONTENT
. If existing content is found with the sameCONTENT-ID
but a different source file, signalDUPLICATE-ID-ERROR
.
[macro] DO-CONTENT (VAR &KEY (TEST '
IDENTITY
) (KEYNIL
)) &BODY BODYFilter the content in the registry using the
TEST
function. IfKEY
is given, call theTEST
function with the result of applyingKEY
. Once finished, iterate over the items, binding each toVAR
and executingBODY
.
[function] FETCH TEST &KEY KEY
Given a
TEST
function, usually for a content type, traverse the site registry collecting all content objects matchingTEST
. If supplied,KEY
is applied to each object beforeTEST
.
[function] PURGE PREDICATE
Remove all content matching
PREDICATE
from the registry
[function] SIBLINGS CONTENT
Return a list of all registered items with the same type as
CONTENT
.
Because it is often interesting to view "related" content, content types
can define a method on the RELATED-KEY
generic function. RELATED-KEY
should
return an accessor for the content type suitable for use with SORT
.
Currently, all sorting is performed by STRING>
to support chronological order
for posts, year collections, etc. To make it easier to write templates that
link to other content objects, PREV
and NEXT
functions take content and
return the previous or next content object according to RELATED-KEY
.
[generic-function] RELATED-KEY CONTENT
Given a piece of
CONTENT
, return a function suitable as aKEY
argument for sorting that content.
[function] PREV CONTENT
Given a
CONTENT
object, find its predecessor in the registry.
[function] NEXT CONTENT
Given a
CONTENT
object, find its successor in the registry.
There are conditions signalled in the event of failed lookups or attempts to
register duplicate content IDs and a condition handler to LIST-CONTENT-IDS
.
[condition] MISSING-CONTENT-ERROR
Signaled when a piece of content could not be located.
[condition] DUPLICATE-ID-ERROR ERROR
When content is supplied for registration and uses a @CONTENT-ID that has already been registered, a DUPLICATE-ERROR is signaled. It is not signaled if both the original and new content have the same path.
[function] LIST-CONTENT-IDS CONDITION
A condition handler for
MISSING-CONTENT-ERROR
that lists out available Content IDs matching the content type of the missing content.
6 Content Types
6.1 Static Assets
[in package COLLARDS.ASSET]
-
ASSET
s are intended for larger files, usually media or binary files that need convenient linking but are best kept in cloud storage.
[function] ASSET? OBJECT
Returns t if
OBJECT
is anASSET
.
- [function] BUILD PATHNAME
6.2 Pages
[in package COLLARDS.PAGE]
-
PAGE
s are user-defined static web pages with custom layout. They are intended to provide maximum flexibility by allowing user-supplied code to generate arbitrary content as part of the build process.
-
Optional markdown content for producing a page. The POST template is used instead of
RENDER-FN
when aBODY
value is present.
[function] PAGE? OBJECT
Returns t if
OBJECT
is aPAGE
.
[macro] DEFINE-PAGE &KEY TITLE RENDER-FN
Given a
TITLE
and a symbolRENDER-FN
accepting aPAGE
object and aSITE
, supply the page metadata for access by LOAD-CONTENT.
6.3 Blog Posts
[in package COLLARDS.POST]
-
POST
s are collards way of representing articles with a common template, usually grouped by topic and date, and part of a journal.
[function] POST? OBJECT
Returns t if
OBJECT
is aPOST
.
6.4 RSS Feeds
[in package COLLARDS.FEED]
-
A generic feed class for generating Atom or RSS.
[function] FEED? OBJECT
Returns
T
ifOBJECT
is aFEED
.
6.5 Collections
[in package COLLARDS.COLLECTION]
Most sites have interest in grouping subsets of content together by different means. Tags are one way to accomplish this but collards also models groupings by date as a kind of collection. You may decide to define other groupings.
Collections are created in a second phase after all other content is loaded.
Currently tag, yearly, and reverse chronological collections are supported.
Only post objects participate in collections but it is possible to define
custom collection subclasses in your site that specialize on other types.
(Or to override the GATHER
and POPULATE
methods for the existing collections.)
Since collections are special-cased in the build process, it makes sense to
share some of those details here. First, type.collection
files are found
during the regular content loading step. Second, after site content is loaded,
GENERATE
is called to build and register instances matching the supplied type.
So if the filename was tag.collection
it would build instances of TAG
.
Because collections usually generate multiple HTML files from a single input
file, collards cannot rely on its normal convention of computing a slug from
the input file. As a result, each collection implements GATHER
to query the
registry for how many pages a collection will have and their titles. (E.g. A
list of distinct tags, or months when posts were made.) GENERATE
then uses
this information to produce a list of the instances to build and finally calls
POPULATE
on each one to fill them with matching content before registration.
[class] COLLECTION CONTENT:CONTENT
A simple wrapper class for managing groups of content.
[function] COLLECTION? OBJECT
Returns t if
OBJECT
is aCOLLECTION
.
[function] DESCENDANT? OBJECT
Determine if
OBJECT
is a descendant ofCOLLECTION
.
[reader] KIND COLLECTION (:KIND)
The kind of collection to build after content is loaded.
[accessor] ITEMS COLLECTION (:ITEMS)
The content IDs of items in the collection.
[generic-function] GATHER COLLECTION-CLASS
Return eligible registry content for
COLLECTION-CLASS
.
[generic-function] POPULATE COLLECTION-CLASS FILE
Group the eligible content for
COLLECTION-CLASS
into collections with the same relative path asFILE
and register them.
-
Generate collections from the registry after all other content is loaded.
7 Glossary
[glossary-term] Content Objects
A Content Object represents a file
collards
will process that produces a unique URL on the site. A content object must store at least the path to its source file and a title to use during URL generation.
-
A Content Type is a data type representing a kind of file that collards knows how to recognize (parse) and generate a page for (render). Out of the box, Collards has the following content types: Pages, Posts, Feeds, Collections, and Assets.
It is possible for users to define their own Content Types in their init files by supplying a subclass of
COLLARDS.CONTENT:CONTENT
along with aCOLLARDS.CONTENT:GET-TYPE
method, aCOLLARDS.CONTENT:PARSE
method, and aCOLLARDS.CONTENT:RENDER
method returning HTML.The
GET-TYPE
method should beEQL
-specialized on the file extension, for example:md
for markdown files, and return the class to instantiate (e.g. withFIND-CLASS
), not a symbol.The
PARSE
method should read the supplied file and return a plist of metadata including at minimum:file
and:title
attributes.
-
A Content ID is a string uniquely identifying a piece of content managed by
collards
. It is constructed from the Content Type and Slug of a piece of content, joined by a ':'. For example,page:about
orpost:favorite-albums-of-2023
.A notable limitation of the current scheme for content IDs is that titles must form a unique slug for all content of the same type. i.e. There cannot be two pages with the same slug, even if they are in different folders.
-
A Slug is the unique identifying part of a web address, such as '/favorite-albums.html'. Collards does not consider file extensions as part of slugs and generates a slug for each piece of content when it is registered by transforming the title with a SLUGIFY function.
Users can feel free to redefine
COLLARDS.CONTENT:SLUGIFY
within their init files since init files are loaded before site processing occurs.