Skip to content

Content Management System

Five flat editors over the storefront content the Customer Portal reads — themes, content categories, widgets, menus and pages — with no website selector, no preview and no publishing step: a row is live as soon as its status is active, and it touches neither stock nor the ledger. It is the older, generic view of the content CP Commerce Admin now edits website by website. Because this applet cannot say which website a page or theme belongs to, a theme saved here never appears on your website and a page saved here is missing from the website’s Posts tab — create anything website-specific in CP Commerce Admin.

Overview

The Content Management System applet is a set of five flat editors over the same storefront content that Customer Portal (CP Commerce) storefronts read: Theme (colour and font presets), Content Category (a hierarchy of content labels), Widgets (named instances of the platform’s widget catalogue), Menu (navigation items inside a menu list) and Pages (rich-text posts). Each editor is a listing with create, edit and delete; there is no website selector, no preview and no publishing step — a row is live for the storefront as soon as its status is ACTIVE.

It is the older, generic view of content that the CP Commerce Admin applet now edits per website, tab by tab. Both applets edit the same content (see Lifecycle and effects), so a menu item or content category saved here appears in CP Commerce Admin and vice versa — with one important difference: this applet cannot say which website a post or theme belongs to (see Troubleshooting). It writes nothing to stock or the General Ledger.

Where it fits

PositionApplet / systemWhy
ModuleE-Commerce, CRM & DigitalStorefront content
Same content, richer screensCP Commerce AdminIts Website › Menu List, Posts, Label List and Content Category tabs write the same menus, posts, label lists and content categories, scoped to a website. Its Layout Instance tab is what places widgets on a storefront page, and it picks each widget from a fixed list built into that applet — not from the widget instances named here
Reads what is saved hereCustomer Portal storefront (web and mobile app)Menus, posts, content categories and themes are rendered by the storefront’s widgets
ImagesMedia LibraryPost images uploaded from the Pages editor go to the post’s own image store, not to a Media Library drive
OrdersShopping Cart (Internal)Not connected: nothing here touches carts or documents; listed because readers arriving from the E-Commerce module expect it

Screens and menus

Sidebar: a CMS separator, then Theme, Content Category, Widgets, Menu, Pages, then Settings and Personalization entries (added 2026-10-05: before that the entry was Setting, matched no route, and landed you on the Theme listing). Opening the applet lands on Theme.

Every editor has the same shape: an ag-grid listing on the left with a + (create) action, a create form, and an edit form that opens from a row. Since the September 2026 build the listings page through the server with the shared advanced-search component, and the Content Category screens use the two-column layout of the newer applets.

MenuListing columnsCreate / edit formWhat it reads and writes
ThemeTitle, Template, Status, Creation Date, Updated DateTitle, Template (one of the platform’s theme templates), Description, Status, then fifteen colour and font-size controls; edit adds an image grid with Add ImageTheme templates (read only) and theme instances
Content CategoryName, Category Level, Status, Creation Date, Updated DateName, URL Key, Description, Status, optional Parent Category (nesting toggle)Label lists (read, first list only) and content categories
WidgetsTitle, Type, Status, Creation Date, Updated DateTitle, Widget Type (from the widget catalogue), Status; edit adds an image grid with Add ImageThe widget catalogue (read only) and widget instances
MenuTitle, Menu Level, Menu List, Sort Number, Link Type, Status, Creation Date, Updated DateTitle, Menu List, Link Type (Component, Page, Content Category, External Link), Link or External URL, Sort Number, Status, optional Parent Menu (nesting toggle); the menu icon is set for you, not chosen (see Fields); Redirect Type is present in the template but commented outMenu lists (read), menu items, and pages / content categories to fill the Link picker
PagesTitle, Author Name, Status, Creation Date, Updated DateTitle, URL Key, Status, Content Category, rich-text Content (Froala editor with inline image upload); Layout Type and Widget are present in the template but commented out; edit adds an image grid with Add ImageContent categories (read) and pages

Advanced search per listing: Pages by Page Title, Author Name, Status; the other four by their title/name and status.

Configuration

Before you can use it

  • Theme templates — at least one theme template on the tenant. The Theme form’s Template picker is filled from it and a theme cannot be saved without one. Templates are platform data; no screen in this applet or in CP Commerce Admin creates them.
  • A label list — the Content Category form silently uses the first label list the tenant has. If the tenant has none, every category save fails because no label list is set. Label lists are created per website on the CP Commerce Admin Label List tab.
  • A menu list — a menu item cannot be saved without one. Menu lists are created on the CP Commerce Admin website Menu List tab.
  • Widget catalogue — the platform’s widget catalogue fills the Widget Type picker; nothing in this applet adds to it.
  • Server-side permissions on the CMS endpoints: API_TNT_DM_ERP_CMS_THEME_INSTANCES_*, API_TNT_DM_ERP_CMS_MENUS_*, API_TNT_DM_CMS_LABEL_*, TNT_API_CMS_POST_* and TNT_API_CMS_WIDGET_INSTANCE_* (CREATE / READ / UPDATE / DELETE, plus ADMIN / OWNER). This applet has no permission screens of its own; assign them from an applet that has (CP Commerce Admin › Settings, or Tenant Admin).

Applet settings

Two controls, both added on 2026-10-05 with the applet’s internationalisation work. Settings → Default Selection saves DEFAULT_LANGUAGE_CODE, DEFAULT_BRANCH and DEFAULT_LOCATION as applet settings, and Personalization saves the same three per user; the applet reads only the language code, to switch its own labels. The rest of the Settings screen is the shared module: Field Settings shows eight toggles (Unit Discount, SST/VAT/GST, WHT, Blanket Order, Segment, G/L Dimension, Profit Center, Project) that are bound to nothing and save nothing, and Webhook, Feature Visibility and the four permission screens are the shared ones. No CMS screen reads a branch or location setting.

Document behaviour settings

Not applicable — the applet creates no documents.

Settings in other applets that control this applet

SettingWhere it is setEffect here
Website › Content Category label listCP Commerce Admin › Website › DetailsDecides which label list the storefront reads categories from. This applet always writes categories into the tenant’s first label list, which is not necessarily the one a website points at
Website › Menu ListCP Commerce Admin › Website › Menu List tabCreates the menu lists offered by the Menu form’s Menu List picker
Website › Layout InstanceCP Commerce Admin › Website › Layout InstanceThe place widgets are put on a storefront page. A layout node chooses its widget from a list built into CP Commerce Admin and carries its own settings; it never points at a widget instance saved here

Feature visibility / permissions

No client-side permission is read anywhere in the applet, and it registers none. Access is decided entirely by the server-side permissions listed above; a login without …_READ on an endpoint sees an empty listing and no error.

Fields

Required-ness below is what the backend validators enforce; the form’s own required markers are listed separately where they differ.

Two things hold on every editor. Status starts empty on every create form, and Save stays greyed out until you pick ACTIVE or INACTIVE. INACTIVE keeps the row in the listing and off the storefront, while Delete takes it out of every listing for good — so to take a menu item or page down for a season and bring it back later, set it INACTIVE rather than deleting it. And no create screen here shows the server’s refusal: none of the five create forms handles an error, so a refused save leaves the form open with no message. If Save appears to do nothing, go back to the listing; no new row means the save was refused, and Troubleshooting names the usual causes.

Theme

The form insists on Title, Description, Status and Template before Save lights up, although the server needs only Template and Status. Title is what the Theme listing shows; Description stays on the theme and appears nowhere else in this applet.

FieldRequired (backend)Notes
TemplateYes — …THEME_HDR_GUID_IS_NULL_OR_EMPTY, …DOES_NOT_EXISTPicker filled from the platform’s theme templates; the picked template’s title is also stored as the theme’s type
StatusYes — …STATUS_IS_NULL_OR_EMPTYACTIVE / INACTIVE
Primary, Secondary, Background, Card Background, Header Background, Header Text, Title Font, Subtitle Font, Normal Text Font, Login/Register Background, Login/Register Text colours; Header, Title, Subtitle, Normal Text font sizesNoColour pickers and text inputs, stored together as one theme configuration; edit rewrites the matching entries in place
WebsiteYes — …WEBSITE_HDR_GUID_IS_NULL_OR_EMPTY, …DOES_NOT_EXISTNot on the form. Create writes a constant website identifier built into the applet; see Troubleshooting

Content Category

The form insists on Name, URL Key, Description and Status; the server insists on Name and Status.

FieldRequired (backend)Notes
NameYes — the save is refused without itEvery category is saved with the same fixed code, so the name is the only thing that tells two categories apart, and nothing refuses a second category with a name already in use. Pages record their category by name (see Pages), so renaming a category does not follow through to pages already saved — whoever renames it reopens each page under the old name and picks the category again.
URL KeyNo (form: yes)Nothing checks that another category does not already use it. A menu item that links to this category keeps its own copy of the URL Key as it was when the link was chosen, and that copy changes only when someone picks the link again (read from the code, not tried). After changing a URL Key, open each menu item that links here and choose the link again.
Parent CategoryNoOnly when the nesting toggle is on. The picker offers top-level categories from every label list, not only the one this category is written into. The category level becomes 2 (1 when no parent). Editing a nested category and saving makes it top-level again: the edit form never fills its Parent Category list, and a save with no parent picked in that session writes level 1 and no parent (read from the code, not tried). Test it on one nested category — open it, Save, and read Category Level in the listing. Until it is fixed, whoever maintains the storefront’s categories checks that column after every edit and nests the category again on CP Commerce Admin’s Content Category tab.
—Yes (code, label list)The form fixes a code, a category type and the label list (always the tenant’s first); none is editable

Widgets

The form insists on Title, Widget Type and Status; the server insists on Status only. Nothing in the screens read points at a widget instance, by title or otherwise: the only link a page could carry to one is the Pages Widget box, which is commented out, and CP Commerce Admin’s layout nodes pick their widget from a list built into that applet. Before building widget instances here, ask whoever runs the storefront what on it reads them; if nobody can say, they change nothing a shopper sees.

FieldRequired (backend)Notes
Widget TypeNo (form: yes)Picker from the widget catalogue; the catalogue title is stored as the instance’s type
ThumbnailChecked by the backend (…PIX_THUMBNAIL_GUID_IS_NULL_OR_EMPTY)Not on the form; the Add Image screen uploads it after creation

Menu

The form insists on Title, Menu List, Link Type, Sort Number and Status; the server insists on Title, Menu List, Link Type, Status and the level.

FieldRequired (backend)Notes
Menu ListYes — refused when empty or when the list does not existPicker from the tenant’s menu lists
Link TypeYes — …MENU_LINK_TYPE_IS_NULL_OR_EMPTYCOMPONENT, PAGE, CONTENT CATEGORY, EXTERNAL LINK (Product and Product Category are not offered)
Link / External URLNoA Page or Content Category target, or an external URL; Page picker from pages, category picker from content categories. For a Page or Content Category the item stores the target and a copy of its URL Key as it was at that moment; the copy is refreshed only when the link is picked again (read from the code, not tried)
Sort NumberNo (form: yes)The box accepts any text, but the server stores a whole number, so type digits only; anything else will not save, and — like every create here — the screen shows no message (read from the code, not tried)
Parent MenuLevel yes — …MENU_LEVEL_IS_NULL_OR_EMPTY; parent must existNesting toggle; the menu level becomes 2 (1 without). The picker offers top-level items from every menu list, not only the list chosen above, so check the parent belongs to the same list. Editing a nested item and saving makes it top-level again unless you pick the parent again in that session (read from the code, not tried): after any edit of a nested item, read Menu Level in the listing
Menu iconNot on the formSet for you from the link: a Component link takes that component’s built-in icon, a Page or Content Category link clears it, and an External Link sets none. The listing does not show it. To change an icon, change what the item links to

Pages

FieldRequired (backend)Notes
TitleNo (form: yes)The backend checks identifiers, status and references only — not the title
URL KeyNo (form: yes)Nothing checks that another page does not already use it — the server compares identifiers, status and references, not URL Keys. A menu item linking to this page keeps its own copy of the URL Key (see Menu › Link), so after changing it, pick the link again on those items
Content CategoryNo (form: yes)The page stores the category’s name as text, not a link to the category, so the server’s category check never applies to pages saved here and a later rename of the category does not reach them. The picker lists categories from every label list by name, so two categories with one name look identical here
Layout Type, Widget—Not on the form — both controls are commented out of the create and edit templates. A page’s layout is assigned in CP Commerce Admin › Posts › Layout Instance
ContentNoFroala rich text; inline images are uploaded to the post’s own image store (JPEG/PNG)
AuthorNoName and identity from the signed-in user’s profile; edit records who modified it
——The form fixes the post type (page) and a code; not editable
WebsiteOnly validated when presentNever set by this applet — see Troubleshooting
Images (edit › Add Image)—The post’s own image store, with an Image Type of Main Image or Additional Image; JPEG/PNG only

Lifecycle and effects

Saving. Save writes the whole record back, not only the fields you changed; the listings and pickers page through the server like every other applet’s.

Statuses. There is no draft/final lifecycle. Each row carries ACTIVE or INACTIVE as chosen on the form; the storefront treats INACTIVE as hidden. Delete is immediate — the edit forms call the service on the first click with no confirmation dialog. Deleted rows disappear from every listing.

What it writes. Theme instances and their configuration (Theme), content categories (Content Category), widget instances and their images (Widgets), menu items (Menu), posts and post images (Pages). It reads — and never creates — theme templates, the widget catalogue, label lists and menu lists.

Shared with CP Commerce Admin. That applet’s Menu List tab creates menu lists, and its menu items are the same menu items edited here (link types there include Layout Instance); its Posts tab writes posts tagged with the open website; its Label List and Content Category tabs write label lists and content categories. CP Commerce Admin does not edit themes or widget instances, so Theme and Widgets are edited only here.

Posting proof block. Not a document applet: no document type, no journal posting, no stock processor, no documents. Amount and quantity signums do not apply; nothing to void.

Related applets

  • CP Commerce Admin — the per-website editor for the same menus, posts and labels, and the only place that creates menu lists, label lists and page layouts; prefer it for anything website-specific.
  • Media Library — drives and categories for storefront media; this applet’s image uploads bypass it.
  • Shopping Cart (Internal) — the document a storefront checkout produces; unrelated to content but the next step in the E-Commerce module.

Troubleshooting

SymptomCauseFix
A theme saved here never appears on your websiteThe applet writes a constant website identifier, built into it, on every theme instance; the form has no Website fieldUntil the applet is fixed, themes cannot be assigned to a tenant’s website from this screen
Theme save fails because the website does not existThe hard-coded website GUID is not a website on this tenantSame as above
A page created here is not listed on the CP Commerce Admin Posts tabPosts here are saved with no website; the Posts tab filters by the open websiteCreate website posts from CP Commerce Admin › Website › Posts
Content category save fails because no label list is set, or the category is missing on the storefrontThe form uses the tenant’s first label list; a tenant with none cannot save, and a website that points at another list will not see the categoryCreate a label list on the website first; create website-scoped categories from CP Commerce Admin › Website › Content Category
Menu save fails because no menu list is setMenu List left emptyPick a menu list (created on the CP Commerce Admin website Menu List tab)
There is no Layout Type or Widget box on a pageBoth controls are commented out of the formAssign a layout to a post from CP Commerce Admin › Posts › Layout Instance
Save does nothing and no message appearsThe server refused the save; no create form in this applet shows the refusalCheck the causes above — theme website, label list, menu list, a non-numeric Sort Number
A nested category or menu item shows level 1 after an editThe edit form saves no parent unless one is picked again in that sessionFor a menu item, pick its parent again on the edit form and save. A category cannot be re-nested here: the edit form’s parent list is never filled, and saving it writes level 1 with no parent, so an edit here un-nests the category. Nest it again on CP Commerce Admin’s Content Category tab, which edits the same categories and does fill the parent list. Read the level column after every edit of a nested row
Theme › Add Image saves nothingThe upload step is switched off in the applet; the screen only navigates backNo image can be attached to a theme from this applet
Toast Please Select Valid Image format (JPEG or png)!Post or widget image upload with any other typeConvert to JPEG or PNG
Clicking Setting in the sidebar opens the Theme listingA build from before 2026-10-05: that entry matched no route, and the applet falls back to the Theme listingNothing to fix on the tenant; the current build has a Settings screen (above)
A row vanished after one click on DeleteDelete is immediate; no confirmation dialog is shownRe-create the row; the storefront reflects the change at once
A listing is empty but the CP Commerce Admin tab shows rowsThe login lacks the …_READ permission for that content; the applet shows no errorGrant the permission set from an applet that has permission screens

Related documentation

Last updated on