Site Builder

Build the whole site inside the CMS

Pages are records in a collection, and a routing middleware matches them as requests arrive. Nothing to generate, nothing to redeploy, no static build to wait on.

The Site Builder lets you build a complete frontend website inside Total CMS. A page is an object in the builder-pages collection carrying a URL route, a template name, and its metadata. Templates live in tcms-data/builder/, split into layouts, pages, partials and macros. No router files or PHP stubs are generated — PageRouterMiddleware runs inside T3’s request pipeline and matches URLs dynamically.

Routing has a fixed order, and it protects the CMS from your URLs. Slim matches API and admin routes first; only when nothing claims the URL does the middleware take over. It checks builder page routes — static matches, then dynamic patterns, then catch-alls — and if none match it tries collection URL patterns. If nothing matches at all, it looks for a page whose HTTP status is 404 and renders that. So a builder page at /collections can never collide with the API at /api/collections.

Routes can carry placeholders. /products/{id} captures one segment, /blog/{category}/{slug} captures two, and /docs/{path:.*} matches across slashes. Captured values reach the template as params.*. Builder-page matches receive the page record as page; when the URL matches a collection’s own URL instead, the template is pages/{collection-id}.twig and the record arrives as object.

Each page also declares the HTTP status it returns — 200, 301 and 302 with a redirect target, 404, 410, 451, or 503 for maintenance — and an opt-in list of Features that run before the template does. The built-in auth feature sends logged-out visitors to the login page and returns 403 to logged-in users outside the access groups you listed. Pages are not limited to HTML either: give one a route of /robots.txt or /llms.txt and the content type is set from the extension.

A concrete start: tcms builder:init blog copies the starter’s layouts, pages and partials into place, creates the builder-pages collection, and imports the starter’s JumpStart file — five pages and five sample posts. Visit the site and it renders. From there cms.builder.nav() builds the menu from your pages, and cms.builder.url('blog-post', {id: post.id}) resolves links by page id, so renaming a route rebuilds every link that points at it.

What you get

No build step

Pages are content, matched by the router as requests arrive. Add one in the admin and it is live — nothing to regenerate or redeploy.

Routes with placeholders

A route like /products/{id} gives every record its own URL. Catch-alls such as /docs/{path:.*} match across slashes for documentation and file viewers.

Start from a starter

tcms builder:init scaffolds minimal, blog, business or portfolio — templates, the pages collection, and demo content in one command.

Navigation builds itself

cms.builder.nav(), subnav() and navTree() read your page list and order file. cms.builder.url() resolves a page by id, so renamed routes never leave dead links.

Pages you can gate

Tick the auth feature to require a login, and name the access groups allowed through. Draft pages are not routable at all.

In practice

One snippet

{# tcms-data/builder/pages/blog-index.twig #}
{% extends 'layouts/default.twig' %}

{% block content %}
	<h1>{{ page.title }}</h1>

	{% for post in cms.collection.objects('blog') %}
		<article>
			<h2><a href="{{ cms.collection.objectUrl('blog', post) }}">{{ post.title }}</a></h2>
			<p>{{ post.summary }}</p>
		</article>
	{% endfor %}
{% endblock %}

A list page reads the collection directly and links to each record through the collection’s own URL.

FAQ

Common questions

Do I have to rebuild or redeploy after adding a page?

No. There is no generation step. Page records are matched by the routing middleware at request time, so a page renders as soon as it is saved.

Can a builder page conflict with the API or the admin?

No. Slim matches routes under /api/ and /admin/ before the builder middleware ever sees the request. A page at /collections is safe alongside the API at /api/collections.

Can I put a page behind a login?

Yes. Enable the auth feature on the page. Logged-out visitors are redirected to the login page and returned afterwards; logged-in users outside the access groups you listed get a 403 rather than a login loop.

Can Site Builder serve files that are not HTML?

Yes. A page with a route like /robots.txt, /llms.txt or /feed.xml is served with the content type matched to the extension, and the template has the full Twig surface available.