Skip to content

MelisCms

The CMS back-office — sites, page tree, page editor, templates, styles and SEO, delivered as a React back-office. Package melisplatform/melis-cms.

Purpose

MelisCms is the back-office where you build and run your websites on the Melis platform. It provides the site page tree, the page editor (Edition, Properties, SEO, Languages tabs), the drag-and-drop plugin zones for composing content, and the administration tools for sites, templates, styles, languages, platform IDs, domains and redirects. It owns no database tables — it reads and writes everything through melis-engine, and page rendering (including the live editing preview) is handled by melis-front.

In Melis v6 the business logic is unchanged; the display layer is a React back-office (/melis-react). MelisCms ships one multi-brick bundle exposing nine tools: the page editor (a sidebar host: page tree + tabbed editor) and eight native React side tools. The only part that is still the classic UI is the page editor's Edition tab, loaded in an iframe.

The MelisCms / MelisFront / MelisEngine trio

These three modules form one tightly coupled system; a question about one usually involves the others.

  • MelisEngine — owns the entire CMS database model (pages, tree, sites, templates, languages, SEO, styles) and exposes it via table gateways and services. Defines MelisTemplatingPlugin, the base class every content block extends.
  • MelisFront — front-office rendering pipeline; turns a URL into a finished page and powers the live editable preview inside the back-office (renderMode/melis).
  • MelisCms (this module) — the back-office UI layer; drives the page lifecycle by firing events that engine and front listeners handle.

Load order: melis-coremelis-frontmelis-enginemelis-cms.

Enable it

Add to config/melis.module.load.php:

php
return [
    'MelisCms',
];

Requires melisplatform/melis-core, melisplatform/melis-engine and melisplatform/melis-front. It has no install SQL of its own; the CMS schema is part of melis-engine. Bricks appear in the React back-office only when MelisCms is active (discovery via GET /melis/react-api/react-modules).

The React back-office — one bundle, nine bricks

The bundle (public/ui-react/brick.js + brick.manifest.json) declares nine bricks that self-register in brick.tsx. All are native full-React except the page editor's Edition tab.

Brick idRoutemelisKeyKind
cms/melis-cms/pagemeliscms_pagePage editor (sidebar host: tree + tabbed editor)
cms-sites/melis-cms/sitesmeliscms_tool_sitesNative React (list + editor + 5-step wizard)
cms-templates/melis-cms/templatesmeliscms_tool_templatesNative React (list + form)
cms-styles/melis-cms/stylesmeliscms_tool_stylesNative React
cms-languages/melis-cms/languagesmeliscms_tool_languageNative React
cms-platform-ids/melis-cms/platform-idsmeliscms_tool_platform_idsNative React
cms-site-301/melis-cms/site-301meliscms_tool_site_301Native React
cms-mini-templates/melis-cms/mini-templatesmeliscms_mini_template_manager_toolNative React
cms-menu-manager/melis-cms/menu-managermeliscms_mini_template_menu_manager_toolNative React

The cms brick is special: it registers both a routed Component (the tabbed editor) and a Sidebar (the page tree), so the tree stays visible in the left sidebar while you work. Every side tool carries a New / Old toggle — New is the React UI, Old is the classic tool in an iframe (/melis/react-tool-page?key=<melisKey>).

The MelisCms section in the React sidebar — the PAGE TREE panel and the Site Tools group

Page tree (left sidebar)

The page tree is the map of your sites and every page inside them. Click a page to open it as a top tab in the editor; search finds pages not yet loaded and expands the tree to them; a node's right-click menu adds a child page, shows details, duplicates a page or a whole branch, or deletes. Move a page by drag-and-drop (server-side rights decide what you may move).

The React page tree — sites and pages, with draft, lock and site-root indicators

The tree reuses the legacy CMS endpoints (no backend change) via cms-tree-api.ts:

PurposeEndpoint
Children of a node (lazy)GET /melis/MelisCms/TreeSites/get-tree-pages-by-page-id?nodeId=<id> (-1 = site roots)
Search pages by namePOST /melis/MelisCms/Page/searchTreePages
Move / re-parentGET /melis/MelisCms/Page/movePage
Duplicate a treePOST /melis/MelisCms/TreeSites/duplicateTreePage
Delete a pageGET /melis/MelisCms/Page/deletePage?idPage=<id>

The tree listens for the melis:cms-tree-refresh event to refresh and reveal a page after Save/Publish/Delete.

Page editor

Open a page from the tree, or deep-link /melis-cms/page/:idPage. The editor has a native React chrome (title + status, action buttons, tab bar) around the tab content. The chrome is assembled from a server-merged structure (GET /melis/react-api/cms-page/structure?idPage=<id>{ header, tabs[], buttons[] }), so other modules can add tabs and buttons by merging config server-side.

Native tabs first, then any contributed by other modules: Edition · Properties · SEO · Languages · Historic · Page Analytics · Scripts · Open Graph · Link Checker · Google Analytics · Versioning · Comments. Action buttons: New page · Duplicate · Erase draft · Delete page · See · Display · Save · Publish (plus a Publish/Online status switch and modular buttons such as Workflow).

Properties tab (native React)

Set the page name, type (Page / Folder / Site…), template (layout), language (locked after creation), menu display, style and taxonomy keywords.

The React Properties tab — name, type, template, language, menu display, style and taxonomy

Edition tab (legacy drag-and-drop in an iframe)

The Edition tab fills the page: it renders live and you drag content blocks (plugins) into the template's zones. It is the classic editor loaded in an iframe inside the React chrome (/melis/react-tool-page?key=meliscms_page&idPage=<id>); the drag-drop, plugin menu, mini-template manager and rich-text editors are the same as in the classic back-office. Their content is auto-saved into the PHP session and written when you Save or Publish.

The Edition tab — the live page with the drag-and-drop overlay, inside the React editor chrome

The plugins panel — the content blocks you can drop onto the page; the list depends on the site's active modules

Drag-drop zone layouts — choose how to split a zone to place your blocks

SEO and Languages tabs (native React)

The SEO tab holds the friendly URL, meta title/description, canonical and redirect URLs. The Languages tab manages language versions of the page (each with its own content and SEO).

The React SEO tab — URL, meta title/description and redirect fields

Saving vs publishing

  • Save writes the draft (Properties + SEO + the Edition XML together, one action).
  • See → Preview / See online shows the draft or the live page.
  • Publish makes the current draft live; the status switch publishes / unpublishes.
  • Erase draft discards the draft back to the published version.

Save/Publish post to the legacy endpoints with the legacy field names: POST /melis/MelisCms/Page/savePage?idPage= and .../publishPage?idPage= (plus unpublishPage, clearSavedPage, deletePage); the Edition XML is read from the PHP session.

Side tools

Sites — create and manage websites

/melis-cms/sites. Each row is a whole website (ID, name, module, languages). + New site runs a 5-step wizard: Multilingual → Languages → Domains → Module → Summary. An existing site is managed through native React tabs: Properties · Module Loading · Domains · Languages · Site Config · Translations · Scripts.

The React Sites tool — search, Columns, Export, New/Old toggle and + New site

Site edit — Module Loading tab: per-module toggles with drag-to-reorder load order

Site edit — Site Config tab: General plus per-language key/value settings

Templates — page layouts

/melis-cms/templates. Native list and native form: Name / Type / Site, and Layout / Controller / Action (the .phtml layout the template maps to).

The React Templates list — KPI cards, controller/action, layout and site per row

Styles — CSS applied to pages

/melis-cms/styles. Manage CSS stylesheets (name, CSS path/source, site); attach a style to a page from the page Properties tab.

The React Styles list — status, name, CSS path and site per row

Front-office Languages

/melis-cms/languages. The master list of locales the platform knows (locale + name with flag).

Platforms IDs — page-id ranges per environment

/melis-cms/platform-ids. Reserves a distinct band of page and template IDs per environment so IDs never collide when moving content between dev / staging / production.

The React Platforms IDs list — page and template ID ranges per platform

/melis-cms/site-301. When a public URL changes, add a redirect (old URL → new URL, unique per site) so the old address still resolves.

The React 301 Redirects list — old URL to new URL per site

Mini-Templates & Menu manager

Mini-Templates (/melis-cms/mini-templates) are pre-built content blocks editors can drop onto a page in one click; the Menu manager (/melis-cms/menu-manager) organises them into categories so they are easy to find in the page editor's mini-template manager.

The React Menu manager — a drag-reorderable tree of categories and their mini-templates

React API endpoints

Routes are declared in config/react-api.php under /melis/react-api/…; controllers are in src/Controller/MelisReactApi*Controller.php. Every action is guarded by CapabilityGuardTrait (denyUnlessAccess() for MelisCoreRights::canAccess(MELIS_KEY), then denyUnlessCan('<action>')). The contract everywhere is { success, data } on OK and { success:false, error } on failure; every fetch sends X-Requested-With: XMLHttpRequest with credentials.

ControllerGuard (melisKey)BaseActions
MelisReactApiPageControllermeliscms_page/cms-pagestructure, properties, seo, refs, languages, ancestors, save-properties, save-seo
MelisReactApiCmsSitesControllermeliscms_tool_sites/cms-siteslist, meta, get, config, modules, create
MelisReactApiSiteRedirectControllermeliscms_tool_site_301/site-redirectslist, stats, sites, get, save, delete
MelisReactApiTemplateControllermeliscms_tool_templates/templateslist, stats, sites, get, save, delete
MelisReactApiCmsLanguageControllermeliscms_tool_language/cms-languageslist, stats, get, save, delete
MelisReactApiCmsPlatformIdControllermeliscms_tool_platform_ids/cms-platform-idslist, stats, get, save, delete
MelisReactApiCmsStyleControllermeliscms_tool_styles/cms-styleslist, stats, sites, get, save, delete
MelisReactApiCmsMiniTemplateControllermeliscms_mini_template_manager_tool/cms-mini-templateslist, stats, sites, item, save, delete
MelisReactApiCmsMenuManagerControllermeliscms_mini_template_menu_manager_tool/menu-managersites, languages, tree, saveTree, category, saveCategory, deleteCategory
ts
// GET the styles list (keyset), then POST a 301 redirect
const r = await fetch('/melis/react-api/cms-styles?limit=25', {
  headers: { 'X-Requested-With': 'XMLHttpRequest' }, credentials: 'include',
})
const { success, data } = await r.json()   // { success, data: { items, total, nextCursor } }

await fetch('/melis/react-api/site-redirects/save', {
  method: 'POST',
  headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json' },
  credentials: 'include',
  body: JSON.stringify({ id: null, siteId: 1, oldUrl: 'old', newUrl: 'new' }),
})

Capabilities

Declared in config/react.capabilities.php under melisReactToolCapabilities, keyed by each tool's rights-bearing melisKey (export only where the tool has an Export button):

php
'meliscms_tool_site_301'                    => ['list','create','edit','delete','export','test'],
'meliscms_tool_templates'                   => ['list','create','edit','delete','export'],
'meliscms_tool_styles'                      => ['list','create','edit','delete','export'],
'meliscms_tool_language'                    => ['list','create','edit','delete'],
'meliscms_tool_platform_ids'                => ['list','create','edit','delete','export'],
'meliscms_tool_sites'                       => ['list','create','edit','delete','export'],
'meliscms_mini_template_manager_tool'       => ['list','create','edit','delete','export'],
'meliscms_mini_template_menu_manager_tool'  => ['list','create','edit','delete'],

The page editor is keyed under meliscms_page as a structured tree so its buttons and tabs each become a capability:

php
'meliscms_page' => [
  'actions' => ['create','save','clear','publish','status','delete','duplicate','view','display'],
  'tabs'    => ['edition','properties','seo','languages'],
],

Each contributing module adds its page tabs/buttons under this same meliscms_page key (Laminas merge), and CmsPage.tsx filters them via useCaps('meliscms_page').can(cap). Two related keys in the same file expose the editor's rights: melisReactRightsTools injects a rights-only meliscms_page ("Page edition") node into Users → Rights, and melisReactSidebarHostSections keeps the MelisCms section visible so the page tree is reachable even for a user with only page rights.

Modular extension seams

Other modules contribute page-editor tabs and cross-tab saves without touching MelisCms:

ts
// Register a page-edit tab (link-check, Open Graph, GA, historic, script-editor…)
window.__melisRegisterPageTab(key, ({ idPage }) => <MyTab idPage={idPage} />)
// Register a cross-cutting save hook, run by the global Save/Publish
window.__melisRegisterPageSaveHook(key, async (idPage) => { /* persist my tab */ })

Server-side, the same extension points remain available:

  • melis_cms_page_tabs_alter — add or remove tabs in the page editor.
  • modify_page_properties_form_config — alter the Properties form to add custom fields.

Key services

Resolve with $sm->get('<alias>'). Business logic stays server-side (Laminas services); React is presentation plus API calls.

Service aliasRole
MelisCmsPageServiceWrite the page model: savePage(), savePagePublished(), savePageSaved(), savePageSeo(), savePageLang(), savePageStyle(), savePageTree(), saveProperties().
MelisCmsSiteServiceSite CRUD and page-per-site queries.
MelisCmsPageGetterServicegetPageContent($pageId) — returns cached rendered HTML of a page.
MelisCmsRightsBack-office permission checks: isAccessible(), isActionButtonActive().
MelisCmsSitesDomainsServicePer-environment domain management.
MelisCmsSitesPropertiesServiceSite-wide key/value settings (Site Config tab).
MelisCmsSiteModuleLoadServicePer-site module loading (Module Loading tab).
MelisCmsMiniTemplateService / MelisCmsMiniTemplateGetterServiceMini-template library and category management.
MelisCmsPageExportService / MelisCmsPageImportServiceExport/import a page tree as a file.

Database tables

MelisCms owns no tables. The CMS schema is defined in melis-engine and accessed via its gateways and services. Never query the CMS tables directly — use the engine gateways/services so caching and the rest of the ecosystem stay consistent.

Page lifecycle events

The page lifecycle is implemented through 19 listeners wired in Module.php::onBootstrap. These events are the primary extension point — hook them instead of calling MelisCmsPageService directly so history, caches and other modules stay in sync.

ActionEvents
Save draftmeliscms_page_save_start / _end (+ …savetree_*, …saveproperties_*, …saveedition_*, …saveseo_*)
Publishmeliscms_page_publish_start / _end
Unpublishmeliscms_page_unpublish_start / _end
Deletemeliscms_page_delete_start / _end (+ …deleteseo_*, …delete_page_*)
Movemeliscms_page_move_start / _end
Duplicatemeliscms_page_duplicate_start / _end
Plugin sessionmeliscms_page_savesession_plugin_*, meliscms_page_removesession_plugin_*
php
// React to a page being published — in Module.php::onBootstrap or a listener's attach()
$eventManager->getSharedManager()->attach(
    'MelisCms',
    'meliscms_page_publish_end',
    function (\Laminas\EventManager\EventInterface $e) {
        $idPage = $e->getParams()['idPage'] ?? null;
        // log, sync, clear a custom cache, notify…
    },
    50
);

Adding a new content block

Every content block extends MelisTemplatingPlugin (defined in melis-engine). Implement front() to render on the live site and back() to render the edit container, then register the plugin. The News, Slider and Category2 modules are reference implementations.

Dashboard widget

MelisCmsPagesIndicatorsPlugin shows site and page counts (published vs not) on the back-office Dashboard.

The Indicators dashboard widget — sites, pages, and pages published vs unpublished

Key files

ConcernPath
Module bootstrap + listener wiringvendor/melisplatform/melis-cms/src/Module.php
React API routes + controllersvendor/melisplatform/melis-cms/config/react-api.php
React capabilitiesvendor/melisplatform/melis-cms/config/react.capabilities.php
Brick source (all 9 tools)vendor/melisplatform/melis-cms/ui-react/src/
Built bundle (committed)vendor/melisplatform/melis-cms/public/ui-react/brick.js + brick.manifest.json
Page servicevendor/melisplatform/melis-cms/src/Service/MelisCmsPageService.php
Site servicevendor/melisplatform/melis-cms/src/Service/MelisCmsSiteService.php
Rights servicevendor/melisplatform/melis-cms/src/Service/MelisCmsRightsService.php
All listeners (19)vendor/melisplatform/melis-cms/src/Listener/
Dashboard widgetvendor/melisplatform/melis-cms/src/Controller/DashboardPlugins/MelisCmsPagesIndicatorsPlugin.php

See also

  • melis-engine — owns the CMS data model and all table gateways.
  • melis-front — front-office rendering and live preview.
  • melis-core — auth, rights, events and base config.