Docs Admin Guide

Admin Guide

Everything you need to know about managing your Contento site from the admin panel.

Dashboard

The dashboard is your starting point after logging in. It provides an at-a-glance overview of your site, including:

  • Total Posts — Count of all posts across all statuses (draft, published, scheduled)
  • Published Posts — Number of currently live posts
  • Comments — Total comments and pending moderation queue count
  • Media Files — Number of files in the media library
  • Recent Activity — Latest posts, comments, and changes

Managing Posts

Creating a post

  1. Navigate to Posts in the sidebar.
  2. Click New Post.
  3. Enter a title. The slug is auto-generated but can be customized.
  4. Write content in the Markdown editor. The live preview updates in real-time.
  5. Optionally add: subtitle, excerpt, cover image, tags, category, and SEO metadata.
  6. Click Save Draft to save without publishing, or Publish to make it live.

Editing posts

Click any post title in the posts list to open the editor. Changes are autosaved as you type. The version counter increments on each save, and previous versions are tracked for recovery.

Publishing and scheduling

  • Publish — Immediately makes the post visible on the public site
  • Schedule — Set a future date/time. The post goes live automatically when the scheduled time arrives.
  • Unpublish — Reverts a published post back to draft status, removing it from the public site

Post statuses

StatusDescription
draftWork in progress. Only visible to admins.
publishedLive on the public site.
scheduledWill be auto-published at the set date/time.

Visibility options

VisibilityDescription
publicVisible to everyone.
privateOnly visible to logged-in users.
passwordRequires a password to view.

Bulk actions

In the posts list, select multiple posts using the checkboxes and use the bulk action menu to:

  • Publish selected posts
  • Unpublish selected posts
  • Delete selected posts
  • Assign a category to selected posts

Media Library

Uploading files

Navigate to Media in the sidebar. Drag and drop files onto the upload area, or click to browse. You can upload multiple files at once.

Supported formats

TypeFormatsMIME Types
ImagesJPEG, PNG, GIF, WebP, SVGimage/jpeg, image/png, image/gif, image/webp, image/svg+xml
DocumentsPDFapplication/pdf
VideoMP4video/mp4
Size limit: The maximum file upload size is 10 MB. Files exceeding this limit are rejected with a FILE_TOO_LARGE error.

Organizing media

The media library provides a rich set of tools for organizing your files:

  • Folders — Organize files into folders. Create folders and move files between them.
  • Grid/List view — Toggle between grid thumbnails and detailed list view (persisted via localStorage).
  • Bulk selection — Select multiple files with checkboxes for bulk delete or move operations.
  • Search & filters — Search by filename and filter by file type (images, documents, video) or folder.
  • Detail panel — Click any file to open a slide-out panel with metadata, alt text, caption, and a copy-URL button.
  • Focal point picker — For images, click to set a focal point. This ensures cropped thumbnails focus on the right area.
  • Infinite scroll — Media loads progressively as you scroll, powered by IntersectionObserver.

Responsive image variants

When you upload an image, Contento automatically generates optimized responsive variants using ImageSharp:

VariantWidthFormatPurpose
Thumbnail400pxWebPGrid previews and cards
Small640pxWebPMobile devices
Medium1024pxWebPTablets and small screens
Large1536pxWebPDesktop and retina displays

EXIF metadata is automatically stripped from all variants for privacy and reduced file size. The original file is preserved at full resolution.

Using media in posts

In the post editor, click the image button or use the Markdown image syntax. The media picker shows all uploaded files with search and filtering.

# Markdown image syntax
![Alt text](/uploads/your-image.jpg)

Categories

Creating categories

Navigate to Categories in the sidebar. Click New Category and provide a name (the slug is auto-generated). Optionally set a description and a parent category.

Hierarchical structure

Categories support unlimited nesting. Each category has:

  • Name — Display name
  • Slug — URL-safe identifier (auto-generated from name)
  • Description — Optional description
  • Parent — Optional parent category for hierarchy
  • Sort order — Controls display order within the same level

Assigning to posts

Each post can belong to one category. Set the category in the post editor's sidebar panel.

Comments

Moderation queue

New comments arrive with pending status and appear in the moderation queue. From the Comments page you can:

  • Approve — Makes the comment visible on the public post
  • Mark as Spam — Moves the comment to the spam bin
  • Delete — Permanently removes the comment

Comment statuses

StatusDescription
pendingAwaiting moderation. Not visible publicly.
approvedVisible on the post page.
spamFlagged as spam. Hidden from public.

Batch actions

Select multiple comments and approve, spam, or delete them in bulk.

Honeypot protection

Contento uses a honeypot field (website) in the comment form. If a bot fills in this hidden field, the comment is silently discarded without any error message. This reduces spam without CAPTCHAs.

AI spam scoring

In addition to the honeypot, Contento uses an AI-powered spam scoring system that analyzes comment content for spam patterns. Each comment receives a score from 0 to 1, where higher scores indicate more likely spam.

  • Auto-approve threshold — Configure in Settings. Comments scoring below this threshold are auto-approved.
  • Spam stats — View total approved, blocked, and checked counts in the Settings page.
  • Pattern detection — Regex-based keyword detection for common spam patterns.

Threaded replies

Comments support nested threading via the parentId field. Replies are displayed indented under their parent comment, with a depth value tracking nesting level.

Users

User roles

RolePermissions
ownerFull access to everything, including site deletion and user management
adminFull access to content, themes, plugins, and settings. Cannot delete site.
editorCan create, edit, and publish any post. Can moderate comments. Cannot manage users or settings.
authorCan create and edit own posts. Can submit for review. Cannot publish.
viewerRead-only access to the admin dashboard. Cannot create or edit content.

Managing accounts

Navigate to Users in the sidebar. You can:

  • Invite new users by email
  • Change a user's role
  • Deactivate accounts (sets isActive to false)
  • Reset passwords
Note: Deactivated users cannot log in or generate API tokens, but their authored content remains published.

Themes

Activating a theme

Go to Themes in the sidebar. Each theme card shows a preview and description. Click Activate to apply the theme to your public site. Only one theme can be active at a time.

CSS variable system

Themes work by injecting CSS variables into the page. These variables control fonts, colors, spacing, and other visual properties. See the Theme Development guide for the full variable reference.

Built-in themes

ThemeDescription
ShizenNature-inspired minimalism. Warm paper tones with organic typography.
KoyoAutumn leaves palette. Rich reds and warm browns evoking Japanese fall foliage.
YukiWinter snow theme. Clean whites with cool blue accents and crisp typography.
InkDark mode calligraphy theme. Deep blacks with high-contrast text.
GroveForest green palette. Earthy tones with serif typography for long-form reading.
NeonVibrant modern design. Bold colors with sans-serif type for tech and creative blogs.
FolioPortfolio-style layout. Minimal chrome that puts content and imagery front and center.
DuskTwilight color scheme. Muted purples and blues for a sophisticated evening mood.

Layouts

What are layouts?

Layouts define the structural arrangement of content regions on a page. Each layout has a JSON structure that describes which regions appear, their grid arrangement, and responsive behavior.

Built-in layouts

LayoutDescription
Standard BlogClassic blog layout with main content area, sidebar, header, and footer.
Full WidthSingle column layout that spans the full width. Ideal for landing pages and long-form articles.
MagazineMulti-column grid layout with featured post hero section. Great for content-heavy sites.
MinimalStripped-down layout with just header, content, and footer. Maximum reading focus.

Setting a default layout

One layout is marked as the default and is used for all posts that do not have a specific layout assigned. To change the default, click Set as Default on any layout.

Layout structure JSON

The structure field is a JSON object describing the page grid. See the Theme Development guide for the full JSON specification and examples.

Navigation Menus

Overview

Contento includes a full menu management system, similar to WordPress menus. You can create named menus, assign them to display locations (header, footer, or custom), and add items that link to custom URLs, posts, categories, or tags. Items can be nested one level deep for dropdown support.

Creating a menu

Navigate to Menus in the admin sidebar. Use the “Add Menu” form to create a new menu with a name and location:

  • Header — Renders in the public site header navigation
  • Footer — Renders in the public site footer
  • Custom — Available via the API for headless consumers

Adding menu items

Click Edit on a menu to manage its items. Each item has:

  • Type — Custom Link, Post, Category, or Tag
  • Label — The display text shown in the navigation
  • URL — For custom links; post/category/tag URLs are resolved automatically
  • Target — Open in same tab (_self) or new tab (_blank)
  • Parent — Nest under an existing top-level item for dropdown menus

Reordering

Use the Up and Down arrows next to each item to reorder. Changes take effect immediately on the public site.

Default menus

Contento seeds two menus on first run:

MenuLocationDefault Items
Main NavigationHeaderHome, Search
FooterFooterHome, RSS Feed
Tip: The public layout falls back to a single “Home” link if no header menu is configured. Headless consumers can fetch any menu via GET /api/v1/content/menu/{location}.

URL Redirects

Overview

Contento includes built-in redirect management for handling moved or renamed content. Navigate to Redirects in the admin sidebar. Redirects are processed by middleware on all public GET requests, ensuring search engines and visitors are seamlessly sent to the correct URL.

Creating a redirect

Click Add Redirect and provide:

  • From Path — The old URL path (e.g., /old-post-slug)
  • To Path — The new destination (e.g., /new-post-slug)
  • Status Code — 301 (permanent) or 302 (temporary)
  • Notes — Optional note explaining why the redirect exists
  • Active — Toggle to enable or disable the redirect

Hit tracking

Each redirect tracks how many times it has been triggered and the timestamp of the last hit. This helps you identify which redirects are still in use and which can be safely removed.

Auto-redirects

When a post slug is changed, Contento can automatically create a 301 redirect from the old slug to the new one, preserving SEO value and preventing broken links.

Tip: The redirect middleware skips /api/, /admin/, and /health paths for performance. Only public GET requests are evaluated.

User Registration & Password Reset

Public registration

Contento supports public user registration. Visitors can create an account from the /Register page by providing an email, display name, and password (minimum 8 characters). New accounts are created with the viewer role by default.

Email verification

After registration, a verification email is sent with a unique token link. Users must verify their email before gaining full access. The email verification status is visible in the admin Users page.

Password reset

Users who forget their password can request a reset from the /ResetPassword page:

  1. Enter your email address and click Send Reset Link.
  2. A reset email is sent with a secure token (valid for 1 hour).
  3. Click the link and enter a new password.
Security: The password reset page always shows a success message regardless of whether the email exists. This prevents email enumeration attacks.

Gravatar avatars

User avatars are automatically loaded from Gravatar using the user's email address. If no Gravatar is configured, a default mystery-person icon is shown.

oEmbed & Rich Media

Overview

Contento automatically converts supported URLs in your content into rich embedded media. Paste a YouTube, Vimeo, Twitter, Spotify, SoundCloud, or CodePen URL into your post content and it will be rendered as an interactive embed on the public site.

Supported providers

ProviderURL Patterns
YouTubeyoutube.com/watch?v=..., youtu.be/...
Vimeovimeo.com/...
Twitter / Xtwitter.com/.../status/..., x.com/.../status/...
Spotifyopen.spotify.com/track/..., open.spotify.com/album/...
SoundCloudsoundcloud.com/...
CodePencodepen.io/.../pen/...

Caching

Embed lookups are cached in memory for 5 minutes to minimize external API calls. Unknown URLs are passed through unchanged.

Shortcodes

Overview

Shortcodes let you embed dynamic content in your posts using simple bracket syntax. Write [shortcode attr="value"] in your Markdown and Contento expands it to HTML at render time.

Built-in shortcodes

ShortcodeExampleDescription
[youtube][youtube id="dQw4w9WgXcQ"]Embeds a YouTube video player
[vimeo][vimeo id="123456"]Embeds a Vimeo video player
[button][button url="/signup" text="Sign Up"]Renders a styled call-to-action button
[callout][callout type="info"]Note text[/callout]Highlighted callout box (info, warning, tip)
[gallery][gallery ids="id1,id2,id3"]Image gallery grid from media IDs
[code][code lang="js"]var x = 1;[/code]Syntax-highlighted code block
[toc][toc]Auto-generated table of contents from headings

Custom shortcodes

You can register custom shortcodes at runtime via the plugin system. Custom shortcodes receive the tag name, attributes, inner content, and a context object with the current PostId, SiteId, and BaseUrl.

Plugins

Plugin overview

Plugins extend Contento's functionality by running JavaScript code in a sandboxed environment (Jint). They can modify rendered post content by hooking into the rendering pipeline.

Enabling and disabling

Navigate to Plugins in the sidebar. Each installed plugin shows its name, version, author, and status. Toggle the switch to enable or disable a plugin.

Installing via the UI

  1. Click Install Plugin on the Plugins page.
  2. Provide the plugin name, slug, version, and JavaScript entry point code.
  3. Click Install. The plugin is enabled immediately.

Plugin settings

Each plugin has a JSON settings object. Click the gear icon on a plugin card to open the settings editor. Settings are passed to the plugin as the global PLUGIN_SETTINGS object.

For more details on building plugins, see the Plugin Development guide.

Settings

Site configuration

Navigate to Settings in the sidebar to configure core site properties:

SettingDescriptionExample
Site NameThe name displayed in the header, feeds, and metadataMy Awesome Blog
TaglineA short description or subtitleThoughts on software engineering
LocaleLanguage and region codeen-US, ja-JP
TimezoneTimezone for date display and schedulingUTC, America/New_York
Custom DomainYour own domain name for the siteblog.example.com

Spam protection

The Settings page includes a spam protection section where you can:

  • Auto-Approve Threshold — Slider from 0-100%. Comments scoring below this threshold are auto-approved. Higher = more lenient.
  • Spam Statistics — View total approved, blocked, and checked comment counts.
  • Moderation Queue — Quick link to the Comments moderation page.

Newsletter

Overview

The Newsletter section lets you manage email subscribers and campaigns. Navigate to Newsletter in the sidebar.

Subscribers

The Subscribers tab shows all newsletter subscribers with their status:

  • Active — Currently subscribed and receiving emails
  • Unsubscribed — Opted out of newsletters

Subscribers sign up via the public newsletter form in the site footer. You can also view subscriber email, signup date, and membership tier.

Campaigns

Create email campaigns from the Campaigns tab:

  1. Click New Campaign.
  2. Enter a subject line and compose the email body.
  3. Preview the campaign before sending.
  4. Click Send to deliver to all active subscribers, or save as draft.

Campaign statuses: draft, scheduled, sent.

Membership

Overview

The Membership section manages paid subscriptions powered by Stripe. Navigate to Membership in the sidebar.

The membership admin has four tabs:

Dashboard tab

Shows key metrics at a glance:

  • Total Subscribers — All registered members (free + paid)
  • Paid Members — Subscribers with an active paid plan
  • Active Plans — Number of plans currently enabled

Plans tab

Create and manage membership plans:

  • Plan Name — Display name (e.g., Premium, VIP)
  • Slug — URL-safe identifier
  • Price — Amount in dollars
  • Billing Interval — Monthly, Yearly, or Lifetime
  • Stripe Price ID — Link to your Stripe price object (e.g., price_...)
  • Trial Days — Number of free trial days before billing starts
  • Access Level — Integer level for content gating (higher = more access)
  • Features — Bullet-point list displayed on the public pricing page

Members tab

View all subscribers with their membership details: email, tier (free/premium/VIP), status (active/expired), Stripe customer ID, expiry date, and join date.

Settings tab

Configure membership behavior:

  • Grace Period — Number of days to maintain access after expiration
  • Dunning Email Template — Email sent when a payment fails. Use {portal_url} placeholder.
  • Drip Content Delay — Default delay before new members access drip content

Multi-Site Management

Contento supports running multiple sites from a single installation. Navigate to Sites in the sidebar.

How it works

Each site has its own content, themes, settings, and domain. Sites are resolved by the Host header using domain-based routing. If no domain matches, the primary site is used as fallback.

Managing sites

  • Create Site — Provide a name, slug, and optional domain. A new site starts with default settings.
  • Set Primary — Mark one site as the primary (default) site.
  • Delete Site — Remove a site and all its content. Cannot delete the primary site.

Site switcher

The admin navigation includes a site switcher dropdown, allowing you to switch between sites without logging out.

Task Scheduler

The Task Scheduler automates recurring operations. Navigate to Scheduler in the sidebar.

Creating tasks

  • Task Name — A descriptive name for the scheduled task
  • Task Type — Choose from 6 built-in types (e.g., cache clearing, sitemap generation)
  • Cron Expression — Standard cron syntax for scheduling, with quick presets (every hour, daily, weekly)
  • Enabled — Toggle tasks on/off

Monitoring

Each task shows its last run time, next scheduled run, and current status. You can manually trigger any task from the admin UI.

Custom Post Types

Beyond standard blog posts, you can define custom content types. Navigate to Post Types in the sidebar.

Creating a post type

  • Name — Display name (e.g., Recipe, Portfolio, Review)
  • Slug — URL-safe identifier
  • Icon — Emoji or icon identifier for the sidebar
  • Field Schema — JSON schema defining custom fields for this content type

Posts can then be assigned to a post type, and the editor will show the appropriate custom fields.

Audit Log

The audit log records every significant action performed in the admin panel. Navigate to Audit Log in the sidebar to view a chronological list of changes.

Each audit log entry records:

  • Timestamp — When the action occurred (UTC)
  • User — Who performed the action
  • Action — What was done (create, update, delete, publish, etc.)
  • Entity type — What type of object was affected (post, comment, user, theme, etc.)
  • Entity ID — The ID of the affected object
  • Details — Additional context about the change
Tip: The audit log is read-only and cannot be cleared or modified. It serves as a permanent record of all administrative actions for security and compliance.