Skip to content

Extension Manifest Reference Since 3.5.0

Every extension requires an extension.json manifest file in its root directory. This file declares the extension’s identity, requirements, and capabilities.

{
"id": "acme/seo-pro",
"name": "SEO Pro",
"description": "Advanced SEO tools for Total CMS",
"reviewNote": "Adds SEO meta tags to your pages and registers a public sitemap endpoint. Uses only documented Total CMS APIs.",
"version": "1.2.0",
"icon": "icon.svg",
"requires": {
"totalcms": ">=3.5.0",
"php": ">=8.2",
"extensions": {
"acme/analytics": ">=1.0.0"
}
},
"min_edition": "standard",
"entrypoint": "Extension.php",
"settings_schema": "settings-schema.json",
"author": {
"name": "Acme Corp",
"url": "https://acme.example.com"
},
"links": [
{"label": "Documentation", "url": "https://docs.example.com/seo-pro"},
{"label": "Dashboard", "url": "/admin/ext/acme/seo-pro/dashboard"}
],
"license": "proprietary"
}

Unique identifier in vendor/name format. Must use lowercase alphanumeric characters and hyphens only.

"id": "acme/seo-pro"

Human-readable name displayed in the admin UI and marketplace.

"name": "SEO Pro"

Semantic version number (e.g. 1.0.0, 2.1.3).

"version": "1.2.0"

Short description of what the extension does.

"description": "Advanced SEO tools for Total CMS"

A plain-language note shown to the operator on the pre-enable review screen. If your extension uses any sensitive capability (public routes, event listeners, container services, MCP tools/resources) or contains high-risk code patterns, the operator sees a review screen before enabling — and your reviewNote leads it.

"reviewNote": "Receives Stripe webhooks at a public endpoint to confirm payments, and watches new orders to send notifications. No data leaves your site except the Stripe calls you configure."

Write it for the site owner, not a developer: say what the extension does and why it needs each sensitive capability, be specific about public endpoints and data access, and keep it to a sentence or two. Optional — but on an extension that uses sensitive capabilities, a clear note turns a nervous “Enable” into a confident one. See Stability & Safety for the full picture.

Version constraints for Total CMS, PHP, and other extensions.

"requires": {
"totalcms": ">=3.5.0",
"php": ">=8.2",
"extensions": {
"acme/analytics": ">=1.0.0"
}
}

Extensions listed under extensions are loaded before this extension (dependency ordering).

If the running Total CMS or PHP version doesn’t satisfy these constraints, the extension is listed on the admin Extensions page but cannot be enabled. A warning panel on the card explains which requirement failed (e.g. “Requires PHP >=8.4 (current: 8.2.10)”), and the Enable button is disabled. The CLI tcms extension:enable will exit with the same message. This means users can still see the extension and read its docs/links before upgrading their environment.

Constraint format: a comparison operator (>=, >, <=, <, =, !=) followed by a version. Constraints that don’t match this pattern are treated as “no restriction” so a typo doesn’t accidentally lock users out.

Minimum Total CMS edition required. The extension will not load on lower editions.

ValueDescription
liteAvailable to all editions (default)
standardRequires Standard or higher
proRequires Pro or higher
"min_edition": "pro"

Relative path to an icon image displayed on the extension card in the admin UI. Supports PNG, JPG, GIF, WebP, and SVG formats. The file must be under 64KB. These icons are embedded inline onto the webpage. Please keep them as small as possible.

"icon": "icon.svg"

If omitted, the card displays without an icon.

Relative path to the PHP file containing the ExtensionInterface implementation. Defaults to Extension.php.

"entrypoint": "Extension.php"

Relative path to a JSON Schema file that defines the extension’s settings. Used to render settings forms in the admin UI.

"settings_schema": "settings-schema.json"

Author information displayed in the admin UI and marketplace.

"author": {
"name": "Acme Corp",
"url": "https://acme.example.com"
}

Card-level links displayed on the extension’s tile in the admin Extensions page. Useful for documentation, support, or quick access to admin pages your extension registers.

"links": [
{"label": "Documentation", "url": "https://docs.example.com/seo-pro"},
{"label": "Support", "url": "https://example.com/support"},
{"label": "Dashboard", "url": "/admin/ext/acme/seo-pro/dashboard"}
]

Each entry must have a label and a url. Malformed entries are silently dropped during parsing.

External vs internal links:

  • URLs starting with http:// or https:// are treated as external and open in a new tab (target="_blank"). They are always shown — including when the extension is disabled or has unmet requirements — so users can read your documentation before deciding to enable.
  • All other URLs are treated as internal (admin pages your extension registers) and open in the current tab. Internal links are only shown when the extension is enabled, since the routes wouldn’t resolve otherwise.

If filtering leaves no visible links for the current state, the entire links row is hidden.

When true, the extension is excluded from the admin Extensions page and the tcms extension:list CLI output. It still loads, registers, and boots normally — it just doesn’t appear in the operator-facing management UI. Defaults to false.

"hidden": true

Useful for bundled page-middleware extensions (like protect, scheduled, maintenance) that are enabled per-page via the Features field rather than globally via the Extension Manager. There’s no toggle to show — the extension is always active; individual pages opt in.

Hidden extensions can still be targeted by tcms extension:enable and tcms extension:disable if you know the ID.

License identifier (e.g. MIT, proprietary).

"license": "MIT"

Capabilities describe what an extension does — registering Twig functions, adding admin pages, listening to events, and so on. Unlike traditional plugin systems, capabilities are not declared in the manifest. They are auto-detected from the calls your extension makes in its register() method (and from filesystem markers like a schemas/ directory).

When an extension is enabled, the system runs a trial registration to discover what it provides, then writes the detected capabilities to tcms-data/.system/extensions.json. Each capability becomes a toggleable permission that admins can switch on or off in the admin Extensions page. Toggling a permission off disables that part of the extension’s functionality without uninstalling it.

Capability keyDetection triggerDescription
twig:functions$context->addTwigFunction(...)Custom Twig functions
twig:filters$context->addTwigFilter(...)Custom Twig filters
twig:globals$context->addTwigGlobal(...)Twig global variables
cli:commands$context->addCommand(...)CLI commands
routes:api$context->addRoutes(...)Authenticated API endpoints
routes:public$context->addPublicRoutes(...)Unauthenticated public endpoints
routes:admin$context->addAdminRoutes(...)Admin pages
admin:nav$context->addAdminNavItem(...)Items in the admin sidebar
admin:widgets$context->addDashboardWidget(...)Dashboard widgets
admin:assets$context->addAdminAsset(...)CSS/JS loaded in the admin
frontend:assets$context->addFrontendAsset(...)CSS/JS loaded on public pages
events:listen$context->addEventListener(...)Content event subscribers
fields$context->addFieldType(...)Custom field types
schemasschemas/ directory exists in the extensionRead-only schemas (Pro+ only)
container$context->addContainerDefinition(...)DI container services
page-middleware$context->addPageMiddleware(...)Per-page middleware
form-actions$context->addFormAction(...)Custom form action types (Pro)

If a new version of an extension adds a capability it didn’t have before, Total CMS detects it on update and adds it to the permissions list turned off — the operator opts into the new feature from the extension’s settings. (For sideloaded extensions, an update whose code contains high-risk patterns disables the extension until the operator reviews it.) See Stability & Safety for how the review and update protections work.

For details on each capability and how to register it, see Extension Points.