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%} showsThat 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
@authortag; - 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.xmlA 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
--leftnavthe output ofwodoc blog-nav(the post list); - pass
--blog-config/--blog-baseto 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-feedonce 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.