This documentation is also published as Markdown for efficient machine reading: the whole site is indexed at /llms.txt, and every page has a clean Markdown copy under /_llms/. These are generated from the same source and cost far fewer tokens to read than this rendered HTML.

Skip to main content Skip to navigation
Guides

Mark drafts, schedule posts, tag pages, and control sort order

Hide unfinished pages, embargo posts until a release date, attach grouping keywords, and choose where a page lands in its sidebar section using front-matter keys.

To keep an unfinished page out of navigation, embargo a post until a release date, attach grouping keywords to a page, or change where a page appears within its sidebar section, set one of four front-matter keys.

A draft is excluded from build output. isDraft: true (and an unreached future date:) keeps the page visible under dotnet run for preview, but dotnet run -- build drops it from the static site entirely — no HTML file, and any xref: link targeting it dangles in the published build. Drafts are a "not yet shipping" flag, not a "shipped but unlisted" one. For the canonical key catalog and parse rules, see Front matter key reference.

Before you begin

  • A working Pennington site has markdown under Content/ (see Create your first Pennington site if not).
  • Each key needs a front-matter record that implements its backing capability — tags: requires ITaggable, order: requires IOrderable; isDraft: and date: are universal. The shipped records implement different subsets, so check the per-record matrix in Front matter key reference before reaching for a key.
  • The sidebar currently renders in file-order; TableOfContentsNavigation has not been customized.

Setting order: on a BlogSiteFrontMatter or BlogFrontMatter page has no effect — blog posts sort newest-first by date:. To reorder posts, adjust the date; to hide a post, use isDraft: true.

Options

Hide an unfinished page with isDraft: true

Setting isDraft: true drops the page from navigation, search, and llms.txt. Under dotnet run it stays served and xref: links to it resolve, so you can preview it; under dotnet run -- build it is excluded from output entirely.

yaml
---
title: Coming soon
isDraft: true
---

The default is false. For the full key catalog, see Front matter key reference.

Schedule a post for the future with date:

A page whose date: is later than the build-machine wall clock is treated the same as a draft: visible in dotnet run so you can preview, excluded from dotnet run -- build output, feeds, and search. As soon as the clock crosses the date, the next build picks the page up — no flag flip required.

yaml
---
title: New feature announcement
date: 2030-11-14T09:00:00
---

The comparison uses the build server's local wall clock, so a date without a time component (date: 2030-11-14) releases at local midnight. CI that runs hourly will pick the post up on the first build after that boundary.

To override the wall clock — for tests, for re-running yesterday's build, or for previewing tomorrow's release — replace the registered TimeProvider in DI with a fixed one (the Microsoft.Extensions.TimeProvider.Testing package ships FakeTimeProvider for exactly this).

Tag a page for grouping

tags: accepts a string array read through ITaggable into RenderedContent.Tags, making it available to client-side filtering widgets. Tags do not produce /tags/<name> index pages on their own; to generate browse-by-tag pages from a tagged front-matter record, register a taxonomy — see Build browse-by-{field} pages with AddTaxonomy.

yaml
---
title: Deep dive
tags: [advanced, performance, pipeline]
---

Order a page inside its section

Lower order: values sort earlier within a section. Spacing like 10/20/30 leaves room for later inserts between existing siblings.

yaml
---
title: Install
order: 20
---

order: positions a page among its siblings; it does not position the folder that holds it. To set a section's own sort key — rather than letting it inherit the min-of-children value — drop a _meta.yml sidecar in the folder with its own order key; see Folder sidecar (`_meta.yml`). For how the navigation tree assembles those values, see Why the sidebar mirrors your folders.

Verify

  • Run dotnet run — the drafted page's URL still responds 200 but is absent from the sidebar and from the per-locale search index under /search/{locale}/ (for example /search/en/index.json)
  • A page with a future date: behaves the same way: URL responds in dev, absent from sidebar/search/RSS; dotnet run -- build lists it under "Skipped"
  • The tagged page's HTML carries the tag strings in its rendered output (inspect RenderedContent.Tags or the page body)
  • Sidebar entries within the section appear in ascending order: — swap two values and the order flips on next reload