A GrapesJS-based visual editor extended with TruCMS blocks, live shortcodes, a template library, data-bound sections and an optional AI assistant. This page explains the pieces; the how-to guides are in the Extend section.
In the user guide: Page Builder, Template Library in the Builder, Dynamic Blocks & Shortcodes and Data-Bound Sections.
/admin/pages/{page}/edit-content?locale=en
PageController@editContent -> view page-builder.editor
|-- loads the saved content + styles of ONE locale into #tru-page-builder
|-- window.PageBuilderSettings (page url, widget areas, AI config)
|-- grapesjs.init({ plugins: [webpage preset, image editor, style-bg, TruCMS plugin, html-code, AI agent] })
| pluginsOpts[TruCMS plugin]:
| templateLibrary -> admin.page-builder.load / categories (JSON)
| shortcodes -> ShortcodeRegistry::all() (embedded JSON)
| shortcodeCategories, shortcodesApi, bakeApi
| boundSources -> BindingSourceRegistry::editorPayload()
|-- canvas styles: editor.scss + Google Fonts + compiled theme CSS (so the canvas shows real colours)
Save (AJAX) -> PageController@updateContent -> clean_page_builder(content) -> page_translations.content/stylesThe editor code is in resources/themes/admin/assets/js/grapesjs/:
| File | Role |
|---|---|
index.js | The TruCMS GrapesJS plugin: default blocks, labels, categories, loads the modules below |
components.js, traits.js, styles.js | Bootstrap-aware components, trait panels and style manager sections |
dynamic-shortcodes.js | Turns each server-side shortcode definition into a GrapesJS component type with traits and a live preview |
shortcode-base.js | Registration helper for shortcode components (x-shortcode-{id} tag, preview URL, traits) |
block-categories.js | Block panel categories and their priority scale |
template-library.js | The template-library lightbox (search, categories, kind filter, insert, preview) |
bound-sections.js | Data-bound sections: pick records, bake markers, re-bake on change |
section-divider.js, animations.js, rellax-traits.js | Shape dividers, entrance animations and parallax traits |
ai-agent.js | The in-editor AI assistant |
A shortcode in TruCMS is a Blade component tag named <x-shortcode-{id}>, written into the saved HTML with its configuration as attributes. At save time nothing is expanded; at render time PageSlugRenderer runs Blade::render() over the content, so the component executes with fresh data.
ShortcodeContract returns a ShortcodeDefinition: id, display name, tag, category, icon, default attributes, traits (the editor's form fields), assets and AI metadata.Shortcode::registerIfMissing(MyShortcode::class) in a provider's boot(); categories are registered with Shortcode::category().admin.page-builder.shortcodes.preview (or render-shortcode) with the current attributes.Core shortcodes (app/Shortcodes): blog, blog-cards, adslot, contact, social-share and widget-area. Booking and TruCommerce register many more (see the catalogue). To build your own, follow Shortcodes.
The editor's Templates panel lists rows from the page_templates table (App\Models\PageTemplate): kind = section or page, category, thumbnail, html, is_premium, is_new. The listing endpoint never returns HTML (so locked premium markup cannot leak); Insert calls admin.page-builder.templates.show, which renders the template's Blade components, returns the HTML, the template CSS and the module assets it needs. Premium templates return HTTP 403 without the extended licence.
resources/themes/echo/page-templates/sections/, composed by catalog.php; module layouts live in Modules/{Name}/resources/page-templates. Seeders (PageTemplatesSeeder and the modules' *PageTemplatesSeeder) upsert them with deterministic UUIDv5 keys, so re-seeding is idempotent.template_assets (the shared ui-* kit plus per-layout .css siblings). TemplateAssets reads the classes used in a page's markup and CssPurger outputs only the matching rules, via <x-template-styles>.lm- prefix for motion layouts, no hard-coded hex values — enforced by tests. See Template library and website templates.A section can display real records (products, posts, services…) while remaining a normal editable section. The wrapper carries data-bound="source" and the editor writes data-bound-ids; elements inside carry data-bind* markers. When the author changes the selection the editor calls admin.page-builder.shortcodes.bake, which fills the markers with current data and returns HTML that still contains the markers. A hourly job (pages:refresh-bound) plus model observers re-bake saved pages when the underlying records change. Full details: Data-bound sections.
The page form (resources/themes/admin/components/pages-form.blade.php) stores a settings JSON object. Header options such as floating/sticky/dark/shadow/width and menu choices reach the header as request-scoped theme options through override_theme_options(). A page that pins primary_menu therefore ignores later changes to the site's primary menu — test menu work on a page without that setting.
When the page_builder_ai_enabled setting is on, a provider is fully configured and the user holds edit page, the editor adds a chat panel. (The settings keys and the ProviderModelSelect / EncryptedPassword field types exist, but no core settings section currently registers an admin screen for them — see AI assistant integration.) Requests post to admin.page-builder.ai.generate (throttle page-builder-ai, default 20/minute). PageBuilderAiManager builds a prompt containing a capability catalogue of every registered shortcode, so a plugin shortcode is AI-usable by default; a definition opts out with ->ai(['enabled' => false]). Providers are OpenAI, Anthropic, Gemini, Azure OpenAI and any OpenAI-compatible endpoint; credentials are stored encrypted. See AI assistant integration.
{{ and @php with a zero-width space.href, src, style, class, id, on* and srcdoc as targets of data-bind-attr.config/page_builder.php).