Adding a blog

wodoc can host an ultra-simple blog on a documentation site, with no extra tooling: a blog post is just a plain .mld page, like a manual page. wodoc lists the posts (newest first) in the navigation, can show the latest ones on any page, and generates an Atom feed for syndication. This page walks through setting one up and adding an article.

1. Declare the blog

Add a (blog …) stanza to your doc/wodoc config:

(blog
 (dir blog/posts)   ; where the post .mld files live (relative to this config)
 (out posts)        ; output subdirectory under the blog root: /…/posts/<slug>.html
 (heading "Blog")   ; the heading of the generated navigation section
 (latest 5))        ; how many recent posts {%wodoc:blog-latest%} shows

That is the only configuration the blog needs. See the configuration manual for the full stanza reference.

2. Write an article

A post is a plain .mld file in the (dir …) directory, named YYYY-MM-DD-slug.mld. The date in the file name is the publication date — there is no metadata file to keep in sync, and posts sort newest-first on it automatically. For example, blog/posts/2026-06-14-hello-world.mld:

{0 Hello, world}

@author Jane Doe

This first paragraph becomes the excerpt shown in the post list and the feed.

{1 A section}

The rest of the article: text, code, images, links — anything odoc supports.
  • the title is the page's {0 …} heading;
  • the author is odoc's standard @author tag;
  • the excerpt (shown in listings and the feed) is the first paragraph.

To add an article, just drop a new dated .mld file in that directory and rebuild — wodoc picks it up, lists it and adds it to the feed. Nothing else to edit.

3. Show the latest posts on a page

Put the marker {%wodoc:blog-latest%} wherever the recent-posts list should appear — typically the blog's landing page, but also a site home page:

{0 Our blog}

The latest articles:

{%wodoc:blog-latest%}

wodoc replaces it with a <ul class="wodoc-blog-list"> of the most recent posts (title, date, author, excerpt), styled by your theme (see Styling). On a page built with a stock odoc it is simply dropped, so the source stays portable.

4. The generated navigation

wodoc builds a navigation section (the (heading …) you configured, one entry per post, newest first) and adds it to the left column automatically — you do not list posts by hand.

5. Syndication: the Atom feed

wodoc blog-feed produces an Atom feed of the posts, ready for aggregators such as the OCaml Planet:

wodoc blog-feed --config doc/wodoc --base-url https://example.org \
                --blog-path /blog --feed-path /feed.xml \
                --title "My Blog" --author "Me" > feed.xml

A post's link is base-url ^ blog-path ^ "/" ^ <post path>; the feed advertises itself at base-url ^ feed-path.

Turn-key build vs. a flat site

If your project is built with the turn-key wodoc build, the (blog …) stanza is all you need: wodoc build compiles every post, splices the navigation section and expands {%wodoc:blog-latest%} on the landing — no script.

If instead your blog is part of a flat site built with the lower-level wodoc assemble (as the Ocsigen website is), assemble each post page and:

  • pass --leftnav the output of wodoc blog-nav (the post list);
  • pass --blog-config/--blog-base to expand a {%wodoc:blog-latest%} marker on a page (e.g. the site home);
  • pass --byline "<date> — <author>" to show the post's date and author under its title;
  • run wodoc blog-feed once for the feed.

Styling

wodoc emits only semantic markup; the look lives in your stylesheet. The classes to style are .wodoc-blog-list (the <ul>), .wodoc-blog-card (each <li>), .wodoc-blog-title (the link), .wodoc-blog-meta (the date — author line) and .wodoc-blog-excerpt.