Static sites generated with Clojure

If the malleability provided by the configuration and templates isn't enough for your needs, here are your options.

Leverage Cryogen config and hooks to add, modify, or derive new template parameters and modify content

You can invoke cryogen-core.compiler/compile-assets-timed with a custom config to:

  1. Override any settings from config.edn
  2. Add any additional parameters that will be made available to your pages (ex.: {{my-custom-key}}) (Similarly as you can do with custom keys in the article (i.e. page or post) metadata but for all articles.)
  3. Derive new / modify existing page parameters (available in your Selmer templates) by supplying under :extend-params-fn a function of the signature (fn [params site-data] params). See the code for the available site-data.
  4. Add or modify data of any "article" (a page or a post) or exclude it from further processing by supplying under :update-article-fn a function of the signature (fn [article, config] article). Return nil to exclude that article.
  5. Post-process the HTML :content of any article right before it is written to the disk by supplying under :postprocess-article-html-fn a function of the signature (fn [article, params] article).


Add counts of tag occurrences

We want to show not only tags but also how frequent they are at /tags/. So let's first find that out:

   (fn extend-params [params site-data]
     (let [tag-count (->> (:posts-by-tag site-data)
                          (map (fn [[k v]] [k (count v)]))
                          (into {}))]
         params :tags
         #(map (fn [t] (assoc t
                         :count (tag-count (:name t))))

And in tags.html:

- <li><a href="{{tag.uri}}">{{}}</a></li>
+ <li><a href="{{tag.uri}}">{{}}</a> ({{tag.count}})</li>

See the cryogen 0.2.3 auto-link customization gist.

Override the default URI based on a custom article metadata

You have the post 2019-12-31-my-awesome-post.asc, which would normally be displayed at but you don't want to have the date in the URL. (You could simply move the date from the file name into the :date metadata but let's assume you don't want to for a reason.) So you have added the desired URL slug to the post:

{:title "Awesome!" :slug "my-awesome-post"}
My blog post is the greatest!

Now let's tell Cryogen to use the slug instead of the default :uri:

   (fn update-article [{:keys [slug] :as article} config]
       (if slug
         (assoc article :uri (str "/" slug "/"))

VoilĂ , is there!

Post-process article content with Selmer

Having a post like this:

{:title "Test of markdown with Selmer templating"
 :date "2020-11-26"
 :my/postprocess? true}

Selmer test - it says: {{HELLO}}

and configuring Cryogen with this postprocess-article-html-fn:

      (fn postprocess-article [article params]
        (require 'selmer.parser)
        (if (:my/postprocess? article)
          (update article :content selmer.parser/render {:HELLO "Nazdar!"})

we end up with HTML including

<p>Selmer test - it says: Nazdar!</p>

Extra pages / posts

You can leverage the functions in cryogen-core.compiler and write your own, invoking them from your cryogen.core/-main and cryogen.server/init, to generate additional pages and posts in the same way as compile-assets-timed does.

Customizing the code

You can copy the cryogen-core.compiler namespace directly into your project (where it will override the one from the cryogen-core.jar) and modify it to your liking. It is not very long or complicated and is quite easy to modify. That is what we did for this site (although it uses a much older version of cryogen-core, you may still use the same strategy today).