The Settings menu in the CMS is extensible. A page you write appears in the same sidebar as Cendia's own (Configuration, Users, Content Types and the rest), opens with the same header, and is protected the same way. You can add it to an existing group or start a new one, and choose where it sits in that group.
There is no registration call and no menu file to edit. The page's location and one attribute are all the CMS needs.
What the CMS does for you
For every Razor Page in your site's Extensions/Settings/ folder, the CMS:
- serves it at
/cms/settings/<name>, where<name>is the file name in lowercase; - draws it inside the CMS shell: top bar, Settings sidebar, and the standard page header;
- makes it Administrator-only, like every other Settings screen. You cannot forget this and you cannot turn it off.
A page that also carries [SettingsPage] is listed in the sidebar.
Step 1: create the page
Add a Razor Page, the .cshtml and its PageModel, to Extensions/Settings/ in your site. This
example is Extensions/Settings/Corporate.cshtml, so it is served at /cms/settings/corporate.
YourSite/
Extensions/
Settings/
_ViewImports.cshtml ← ships with the Starter
Corporate.cshtml
Corporate.cshtml.cs
The Starter already includes Extensions/Settings/_ViewImports.cshtml. If your site predates it,
create it:
@using Cendia.Settings
@namespace YourSite.Extensions.Settings
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Do not add a _ViewStart.cshtml or set Layout. The CMS supplies the layout for this folder.
Step 2: put it on the menu
Give the PageModel [SettingsPage]. It takes three things: the group to list it under, the
menu name, and a subtitle.
using Cendia.Settings;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace YourSite.Extensions.Settings;
[SettingsPage("People", "Corporate", "Accounts that are billed together on one corporate invoice.",
Title = "Corporate Accounts", Order = 5)]
public class CorporateModel : PageModel
{
public void OnGet() { }
}
| Argument | Required | What it does |
|---|---|---|
group |
yes | The sidebar heading it is listed under. Cendia's groups are Site, People, Content model and Designer. Matching is case-insensitive. |
menuName |
yes | What the sidebar says. |
subtitle |
yes | One line under the page title saying what the page is for. Every Settings page has one. |
Title |
no | The page heading, when it should say more than the menu name. Defaults to the menu name. |
Order |
no | Where it sits in its group. See step 3. |
You can put the attribute in the .cshtml instead, with @attribute [SettingsPage(...)]. Use
one place, not both.
Step 3: choose where it sits
Cendia numbers its own entries 10, 20, 30… within each group, in the order they appear. Your
Order places your page among them:
Order |
Result, in the People group (Users 10, Groups 20, Permissions 30) |
|---|---|
5 |
Above Users |
15 |
Between Users and Groups |
25 |
Between Groups and Permissions |
| (left out) | At the bottom, after Permissions |
If your page has the same number as a Cendia entry, Cendia's entry comes first. Two pages of your own with the same number are sorted by menu name.
A new group. Use a group name Cendia does not have, such as "Integrations", and it becomes a
new heading after Cendia's own groups. Several new groups appear in the order the CMS first finds
them. Use Order to arrange the pages inside a group.
Step 4: write the page body
Do not write a title or subtitle in the page. The CMS draws both from [SettingsPage], so every
Settings screen opens the same way. Write only what goes beneath them.
@page
@model CorporateModel
@{
ViewData["CmsWidth"] = "narrow";
}
@section PageActions {
<button type="button" class="btn btn-primary btn-sm">+ New Account</button>
}
<form method="post">
<label asp-for="AccountName" class="form-label">Account name</label>
<input asp-for="AccountName" class="form-control" />
<button type="submit" class="btn btn-primary mt-2">Add</button>
</form>
@section PageActions: buttons and links shown at the right-hand end of the header, beside the title. Optional.ViewData["CmsWidth"]: how much of the column the page uses.- Leave it out for the full width (up to 1400px). This suits wide tables and editors.
"medium"uses about two thirds. This suits a settings form with sections."narrow"uses about half. This suits a short form or a short list.
- Forms, handlers (
OnPost,OnPostSave…), tag helpers andRedirectToPage()all work as they do in any Razor Page. Anti-forgery tokens are added to<form method="post">automatically.
Step 5: run it
Restart the site, sign in as an Administrator, and open Settings. The page is listed in its
group, highlighted when you are on it, and served at /cms/settings/corporate.
Detail pages and sub-pages
A page in Extensions/Settings/ without [SettingsPage] is still served and still
Administrator-only, but it is not listed in the sidebar. Use this for a screen you reach from
your listed page, such as an edit screen for one record:
Extensions/Settings/Corporate/Index.cshtml → /cms/settings/corporate (listed)
Extensions/Settings/Corporate/Edit.cshtml → /cms/settings/corporate/edit (not listed)
A folder's Index page is served at the folder's address. A sub-page under a listed page keeps
that page highlighted in the sidebar.
Because an unlisted page has no attribute to take its header from, it sets its own:
@{
ViewData["Title"] = Model.Account.Name;
ViewData["Subtitle"] = "A corporate account and the users billed to it.";
}
Rules to know
- Names must not collide. Cendia's own Settings pages use
/cms/settings/configuration,/cms/settings/usersand so on. Do not name your file after one of them. - Addresses are lowercase.
Corporate.cshtmlis/cms/settings/corporate. Link to it by that address rather than withasp-page, since the page is not in thecmsarea. - It lives in Extensions, not Models. A Settings page is configuration for your
installation, not part of your content model, so it belongs beside your other extensions
(
Extensions/Jobs,Extensions/Fields). - The Starter has a worked example.
Extensions/Settings/SettingsPage.Example.csand.cshtmlship commented out. Rename them and uncomment them to try it, then delete them once you have a page of your own.