BarakoCMS.Pages
4.2.0
dotnet add package BarakoCMS.Pages --version 4.2.0
NuGet\Install-Package BarakoCMS.Pages -Version 4.2.0
<PackageReference Include="BarakoCMS.Pages" Version="4.2.0" />
<PackageVersion Include="BarakoCMS.Pages" Version="4.2.0" />
<PackageReference Include="BarakoCMS.Pages" />
paket add BarakoCMS.Pages --version 4.2.0
#r "nuget: BarakoCMS.Pages, 4.2.0"
#:package BarakoCMS.Pages@4.2.0
#addin nuget:?package=BarakoCMS.Pages&version=4.2.0
#tool nuget:?package=BarakoCMS.Pages&version=4.2.0
<div align="center"> <img src="https://raw.githubusercontent.com/BaryoDev/barakoCMS/master/assets/icon.png" width="96" height="96" alt="BarakoCMS.Pages logo" /> <h1>BarakoCMS.Pages</h1> <p><em>A page tree over a content type you already have: navigation, paths and breadcrumbs.</em></p> </div>
The blog blueprint creates a page type with a slug, a parent page, a navigation flag and an
order. This module adds what that shape cannot say on its own: a page may not be its own ancestor,
may not be nested too deep, and a top-level page may not take a reserved slug. It also answers the
two questions a renderer needs and cannot compute from a list: the site menu, and which page lives
at /about/team.
Enable it
dotnet add package BarakoCMS.Pages
builder.Services.AddBarakoCMS(builder.Configuration);
var app = builder.Build();
app.UseBarakoCMS();
The package reference plus a restart is the install. AddBarakoCMS finds every module in the
application's dependency context, and BarakoCMS:Modules:Enabled decides which of them run
(BarakoCMS__Modules__Enabled=Pages). To name it by hand instead, put
modules.Add(new BarakoCMS.Pages.PagesModule()) in the AddBarakoCMS callback. See MODULES.md in
the repository.
The module seeds nothing and stores nothing of its own. Create the page type first, for example by
applying the blog blueprint.
Configuration
Under Modules:Pages. The defaults match the blog blueprint's page type.
| Key | Default | Meaning |
|---|---|---|
ContentType |
page |
The content type holding the pages |
ParentField |
ParentPage |
Reference field naming the parent; empty means a top-level page |
ShowInNavigationField |
ShowInNavigation |
Boolean field that puts a page in the menu |
OrderField |
NavigationOrder |
Integer field ordering siblings; unset sorts last |
TitleField |
Title |
Field used as the title in the menu, breadcrumbs and tree |
MaxDepth |
8 |
Most ancestors a page may have |
ReservedSlugs |
none | Slugs a top-level page may not take, case-insensitive |
HomeSlug |
home |
The top-level page served at / |
MaxPages |
1000 |
Most pages one request reads; navigation and the tree say truncated when there were more |
The slug field is the one public delivery already uses: a field of type slug, else one named slug.
Rules on write
A create, update or rollback of the configured type is refused with 400 when:
- the parent field points at the entry itself, or closes a loop of any length;
- the page would have more than
MaxDepthancestors, or its parent's chain never reaches a root; - a top-level page takes a slug in
ReservedSlugs.
The parent walk runs inside the write's transaction under an advisory lock, so two concurrent saves cannot close a loop between them. Two siblings with the same slug are already refused by core, which refuses any slug another entry of the type holds.
Endpoints
| Method and path | Purpose | Access |
|---|---|---|
GET /api/public/pages/navigation |
Nested, ordered menu of published pages flagged for navigation | Anonymous |
GET /api/public/pages/resolve?path=/about/team |
The page at a path, with breadcrumbs; 404 on a miss | Anonymous |
GET /api/pages/tree |
Every page the caller may read, drafts included, for the console | Signed in, content read permission |
The two anonymous endpoints serve only what GET /api/public/{type}/{slug} would: published,
document-Public entries of a publicly deliverable type, with only Public fields. A page is left out of
the menu and does not resolve when any page above it is not served, so a published page under a
draft stays off the site. Tree fields are read from the Public fields only. Both answer 404 when the
type is not publicly deliverable, and both are cacheable for 60 seconds with Vary: X-Tenant.
A menu page whose parent is not in the menu sits under its nearest ancestor that is, and keeps its
real path. The home page has path /; /home does not resolve to it.
Every body carries contract, currently 1. It moves only on a breaking change to these bodies. A
renderer that does not know the number should show no menu rather than stop.
{ "contract": 1, "truncated": false, "items": [
{ "id": "...", "title": "About", "slug": "about", "path": "/about", "order": 1, "children": [
{ "id": "...", "title": "Team", "slug": "team", "path": "/about/team", "order": null, "children": [] } ] } ] }
{ "contract": 1, "path": "/about/team",
"entry": { "id": "...", "contentType": "page", "slug": "team", "data": { "Title": "Team" }, "createdAt": "...", "updatedAt": "..." },
"breadcrumbs": [
{ "id": "...", "title": "About", "slug": "about", "path": "/about" },
{ "id": "...", "title": "Team", "slug": "team", "path": "/about/team" } ] }
truncated is true when the type holds more than MaxPages published pages, counted before the
navigation flag is read. Pages are read oldest first, so the newer ones, and every page under them,
may be missing from the menu even though resolve still serves them. Raise MaxPages when a site
sees it.
entry is the same shape GET /api/public/{type}/{slug} returns.
{ "contract": 1, "truncated": false,
"options": { "contentType": "page", "parentField": "ParentPage", "showInNavigationField": "ShowInNavigation",
"orderField": "NavigationOrder", "titleField": "Title", "maxDepth": 8, "reservedSlugs": [], "homeSlug": "home" },
"items": [
{ "id": "...", "title": "About", "slug": "about", "path": "/about", "status": "Draft",
"showInNavigation": true, "order": 1, "children": [] } ] }
options is the Modules:Pages configuration in use, so a console that moves a page writes the
parent and order fields this site's type has, not the defaults. Only the tree carries it; the two
anonymous bodies do not.
In the tree, a page whose parent the caller cannot read, or whose chain loops, is listed at the top
level with path null, so it can be found and fixed.
Part of barakoCMS
This is an optional module for barakoCMS, an open-source
headless CMS for .NET 10. Every module is published under the barakocms-module tag, so a single
search on nuget.org returns the whole set.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- AspNetCore.HealthChecks.Npgsql (>= 9.0.0)
- AspNetCore.HealthChecks.System (>= 9.0.0)
- AspNetCore.HealthChecks.UI (>= 9.0.0)
- AspNetCore.HealthChecks.UI.Client (>= 9.0.0)
- AspNetCore.HealthChecks.UI.InMemory.Storage (>= 9.0.0)
- BarakoCMS (>= 4.2.0)
- BCrypt.Net-Next (>= 4.2.0)
- FastEndpoints (>= 8.3.0)
- FastEndpoints.Security (>= 8.3.0)
- FastEndpoints.Swagger (>= 8.3.0)
- IdentityModel (>= 7.0.0)
- JasperFx (>= 2.56.0)
- KubernetesClient (>= 18.0.13)
- Marten (>= 9.30.0)
- Microsoft.Extensions.DependencyModel (>= 10.0.11)
- Microsoft.Extensions.Http.Resilience (>= 10.9.0)
- Microsoft.IdentityModel.JsonWebTokens (>= 8.22.0)
- Otp.NET (>= 1.4.1)
- prometheus-net.AspNetCore (>= 8.2.1)
- Serilog.AspNetCore (>= 10.0.0)
- Serilog.Sinks.Console (>= 6.1.1)
- Serilog.Sinks.File (>= 7.0.0)
- System.IdentityModel.Tokens.Jwt (>= 8.22.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.2.0 | 48 | 9/18/2026 |