Show navigationHide navigation
Public site and content reads
Public components#
Components for rendering CMS content on public pages are exported from octocms/components/public:
| Export | Purpose |
|---|---|
MarkdownContent | Render a markdown field value using react-markdown + remark-gfm + rehype-sanitize |
RichTextContent | Render a richtext field AST (RichTextDocument) to React |
SearchBox | Client-side search input that calls the /api/search route |
PublicSiteShell | Sample site layout wrapper (navigation, footer) |
getPostBlogHref, toPlainText, toExcerpt, getReadingMinutes, getSiteTimeZone, formatPostPublishedLabel | Content utility helpers |
tsximport MarkdownContent from 'octocms/components/public/MarkdownContent'; // or via barrel: import { MarkdownContent, RichTextContent, SearchBox } from 'octocms/components/public';
Query API and cached accessors#
A typical pattern is to create cached helpers that wrap query() with "use cache" and cacheTag():
tsimport { query } from 'cms/__generated__/query'; import { OCTOCMS_PUBLIC_CONTENT_CACHE_TAG } from 'octocms/lib/publicContentCacheTag'; import { cacheTag, cacheLife } from 'next/cache'; export async function getPublishedPosts() { 'use cache'; cacheTag(OCTOCMS_PUBLIC_CONTENT_CACHE_TAG); cacheLife('hours'); return query('post') .filter((p) => p.fields.publishedAt != null) .sort('publishedAt', 'desc') .toArray(); }
This keeps data loading in one place and matches what buildJsons() invalidates on save. See Query API — Caching for details.
Note: query() automatically excludes entries with sys.status of draft or archived before any user-defined filters run. Only published, changed, and merged entries are returned. See Entry status filtering.
Draft Mode#
To preview unpublished content, use .includeDrafts() with Next.js Draft Mode:
tsimport { draftMode } from 'next/headers'; import { query } from 'octocms/query'; export default async function BlogPage() { const { isEnabled } = await draftMode(); const q = query('post').sort('publishedAt', 'desc'); const posts = isEnabled ? await q.includeDrafts().toArray() : await q.filter((p) => p.fields.publishedAt != null).toArray(); // ... }
See Next.js integration guide — Draft Mode for the full setup (enable/disable routes, secret validation).
There is no queries map in cms/octocms.config.ts; public pages choose collections and filters in code.
See Content model for collection and field definitions.
On-demand revalidation endpoint#
GET /api/revalidate/<tag> expires a cache tag (use octocms:content to match OCTOCMS_PUBLIC_CONTENT_CACHE_TAG / buildJsons) for automation and webhooks. It is not needed for normal editing — Save, Add entry, and Delete already invalidate caches automatically.
Media#
GET /media/<uuid>.<ext> serves image bytes (from disk in dev, from GitHub in typical production setups). See Media.
Published time on the public site#
Home and blog pages show each post’s publishedAt using US English (en-US) medium date style, plus short time when the stored value includes a time. Formatting uses the IANA zone from the SITE_TIMEZONE environment variable (see Installation); the default is America/New_York. Invalid zone names fall back to UTC.
YYYY-MM-DD (date-only) values are interpreted as the first minute on that calendar date in the zone (normally local midnight; if a DST transition skips it, the first existing minute on that date). Resolution uses Intl.DateTimeFormat only—no extra date libraries. Full ISO 8601 date-times are absolute instants, then shown in the same zone. No request “wall clock”, so pages prerender normally on Node.js and Vercel.