Skip to main content

Documentation

No results found.
Features

Themes & Variants

WebProCMS ships Themes — complete, niche-specific starter sites you choose from when you install. A theme isn't just a color scheme: it's a full set of pages (home, about, contact, and more), real starter copy, navigation, and a matched loo...

WebProCMS ships Themes — complete, niche-specific starter sites you choose from when you install. A theme isn't just a color scheme: it's a full set of pages (home, about, contact, and more), real starter copy, navigation, and a matched look. Pick the Legal theme and you start with a law-firm site that already reads like one; pick the Storefront theme and you start with a working online shop whose homepage is built around your products; pick the Realty theme and you start with an MLS-driven real-estate site — property search in the hero, featured and recently-sold listings, a home-valuation lead form, and community pages; pick the Bistro theme and you start with a working restaurant site — a seeded starter menu with dish photos, a live /menu page, and online ordering at /order; pick the Tradeworks theme and you start with a complete service-business site (electrician copy out of the box, ready for any trade) — services, testimonials, service-area, FAQs, and quote-request pages with real photography; pick the Masthead theme and you start with a working online magazine — a lead-story homepage that fills itself from your articles (featured hero, trending strip, a section per category), ten ready-to-replace starter articles with cover photography, and a newsletter signup wired in; pick the Cornerstone theme and you start with a complete church site — service times and a Plan Your Visit page, sermons published as "Messages" with eight starter messages across three series, online giving at /donate (the Donations feature comes on automatically), and events + sermon-video sections that light up if you add those features; pick the Motorline theme and you start with a complete car-dealership site (the Automotive feature comes on automatically) — an inventory-search hero, featured vehicles and latest arrivals pulled live from your lot, browse-by-body-type tiles, a Sell Your Car trade-in page, and dealer-location cards, in a dark Apex performance look or a bright Showroom one; pick the Default theme and you get a clean general-purpose site. Either way you're editing real pages from minute one instead of staring at a blank canvas.

Themes work on three levels, each safe to change without losing your work:

  • Variants re-skin your site — colors, fonts, header, footer — in one click, never touching your content.
  • Switching themes swaps in a whole different starter site (its own pages and content), non-destructively: your old site is parked in its own folder, and you can switch back anytime.
  • The redesign workspace lets you build a new theme's site — editing its pages, previewing it privately — while your current site stays live, then flip it live when you're ready.

What a theme gives you

Every theme installs a working public site, not a template you have to assemble:

  • Real pages — home, about, contact, privacy policy, terms, a blog, locations, and a styled 404 — already wired to routes and navigation.
  • Niche-appropriate copy — headlines, intro paragraphs, practice-area cards, FAQs, and calls to action written for the theme's niche. You edit them like any other page; the starter text is just a head start.
  • A matched look — brand colors, heading and body fonts, and a header/footer that suit the niche.
  • At least one Variant, so there's a built-in way to change the feel without rebuilding anything.
  • Any features it depends on, turned on for you. A theme built around a premium feature declares that dependency, and installing the theme activates the feature automatically. The Storefront theme requires E-Commerce: pick it and the shop module is enabled, its database tables are migrated, and /shop is materialized before your homepage ever renders — no separate trip to Settings → Features.

Variants: change the look, keep the content

A Variant bundles a theme's look — brand colors, fonts, and the header/footer choice — separately from its content. Because every variant of a theme shares the same pages, switching variants is completely safe:

  • Your page content is never touched. Headlines, paragraphs, images, button labels, and every edit you've made stay exactly as they were. Only the colors, fonts, and header/footer change.
  • It's instant and reversible. Switch from Classic Serif to Modern Sans, decide you preferred the first one, switch back — your content is byte-for-byte unchanged either way.
  • No rebuilding. You're not re-picking a header or re-entering brand colors; the variant carries all of that and applies it in one step.

Preview a variant before applying it

Every variant card also has a Preview button. Click it and WebProCMS opens your live site in a new tab with that variant's colors, fonts, header, and footer overlaid — only you see it. Visitors (and teammates who aren't previewing) keep seeing your current design, and nothing is written until you click Apply. A small "Previewing variant" badge floats at the bottom of the site with an Exit preview link, the card shows a Previewing badge back in the dashboard, and Stop preview ends it whenever you're done browsing. It's the same private-preview channel used for parked themes, scoped down to just the look.

Save your current design as a variant

You aren't limited to the variants a theme ships with. Tune your brand colors, fonts, header, and footer to taste, then click Save current design as variant and give it a name — your look is captured as a reusable variant of your theme. Custom variants sit alongside the built-in ones with a Custom badge, and you can rename, update from current design (re-snapshot after more tweaks), or delete them. It's the fastest way to bank a look you like before experimenting, or to keep a couple of seasonal palettes a click apart.

Switching themes after install

You are no longer locked into the theme you picked at signup. Any installed theme can become your live site — and because a theme brings its own pages and content, switching a theme is a real redesign, not a re-skin. WebProCMS makes that safe with a folder-per-theme model:

  • Install a theme "parked." From Available Themes, click Install on any theme. It's set up in its own folder alongside your live site — its pages and starter content are ready — but your live site is completely untouched. You can have several themes parked at once.
  • Switch to it when you're ready. Switch to this theme parks your current site into its own folder first — every page, all your content, your navigation, and your customized colors and fonts — then brings the new theme live. Nothing is deleted.
  • Switch back anytime. Because each theme keeps its own folder, going back to a previous theme restores it exactly as you left it — including the design tweaks you'd made. Flip between them as often as you like.

Variants and full theme switches are different tools for different jobs. A variant changes the look and keeps your content. A theme switch brings a whole different site — different pages, different starter content — with your old one safely parked. If you want the new theme's look but your content, the answer is usually a new variant, not a switch.

Manage the parked themes you're not using from the same screen: each shows how much disk space it's using, and you can delete one you no longer want (its stored content is cleaned up automatically; your live site is never affected).

The redesign workspace: build the new site while the old one stays live

The most powerful part of switching is that you don't have to do it blind. Once a theme is parked, click Edit pages to open its workspace — a full page list for the parked theme where you edit its pages in the normal page editor, and add, clone, or delete pages, all while your current site keeps serving visitors.

  • It's the real editor. Rows, content, design tools, media — everything works exactly as it does on your live pages. A page you're editing shows a clear Workspace badge so you always know you're working on the draft, not the live site.
  • Your live site is never affected. Nothing you do in the workspace changes what visitors see. The site-wide bands you share across pages (like your page-title header or call-to-action footer) are shown locked in the workspace — those belong to your live site and switch over automatically when you go live.
  • Flip it live when it's ready. When the redesign is done, Switch to this theme makes it your live site in one step — and your previous site parks away in case you change your mind.

This is the "start fresh" redesign flow: pick a new theme, build it out over days or weeks without any pressure or downtime, and launch it the moment it's ready.

Preview your draft privately, at real URLs

Building a redesign is one thing; seeing it is another. Click Preview on a parked theme and WebProCMS opens your site with the draft theme applied — its pages, its navigation, its colors and fonts, its header and footer — at your real web addresses. A small "Previewing draft theme" badge floats at the bottom so you always know it's the draft, with an Exit preview link to jump back to the live view.

The key is who sees it: only you do. While you're previewing, every ordinary visitor — and any teammate who hasn't turned preview on — keeps seeing your current live site, exactly as before. You get to click through the whole redesign as if it were live, on the real URLs, with zero risk of a visitor stumbling onto an unfinished page.

Save your current site as a theme

Any site you've built can become a reusable theme. Click Save current site as theme, give it a name, and WebProCMS captures your pages, content, navigation, media, and design into a theme bundle. From there it behaves like any other theme — install it parked, preview it, switch to it. Two things this is great for:

  • A restore point. Snapshot your site as a theme before a big redesign, and you always have a one-click way back to exactly how it looked.
  • A starting point for the next site. Built a great site for one client or location? Save it as a theme and start the next one from it instead of from scratch.

Start a new theme (duplicate)

Start new theme (next to Import theme) copies any theme you have — including the active one — into a brand-new theme under your own name, and parks it immediately. Open Edit pages on its card and build it out while your live site keeps running; switch when it's ready. The ⋯ menu on any Available Theme card has the same thing as Duplicate into a new theme…. This is how you start a redesign from your current look, or spin a client-specific variation off a base theme, without ever touching the live site.

Move themes between sites (export / import)

Themes travel as plain .zip files. Export theme (on the active theme card, or the ⋯ menu on any Available Theme) downloads the whole bundle — pages, starter content, media, and variants. On another WebProCMS site, Import theme (next to Save current site as theme) uploads that zip; the theme appears under Available Themes, and the live site isn't touched until you install it parked and switch. This is the agency workflow: build a starter site once, export it, import it on each new client install. Imported themes always live in your site's own theme folder, safe from CMS updates. Only import themes from sources you trust — a theme contains the page templates your site will run. CLI equivalents: php artisan themes:export {slug} / php artisan themes:import {file.zip}.

Where you manage it

Dashboard → Design → Theme is the home for all of this (admin only):

  • Your installed theme and its details.
  • Its Variants as cards — each with Preview (see it live, only you) and Apply buttons — plus Save current design as variant and the rename / update / delete controls for your custom variants.
  • Available Themes — every other theme, each showing whether it's Installed (parked) or not. Parked themes get Switch to this theme, Edit pages (workspace), and Preview; not-yet-installed themes get Install. Save current site as theme lives here too.
  • An in-progress banner if a theme switch is ever interrupted, with Resume and (before the new theme goes live) Roll back — so a switch is always recoverable.

Every switch, delete, and save is confirmed first, so none of it is an accidental click.

Kept up to date automatically

Themes are shipped and maintained as part of the CMS. When you update WebProCMS, theme fixes and new themes arrive with the update — there's nothing separate to install or manage. A theme improvement made by the maintainers lands for new installs and newly inserted content; it never overwrites pages you've already edited. Your customizations always win. Themes you create yourself (via Save current site as theme) and parked instances live outside the update path, so they're never touched by an update either.


For site authors & the maintainer (technical notes)

Authoring workflows, bundle anatomy, distribution rules, and invariants live in the dedicated theme-authoring.md — update that doc when any of this changes.

These pieces are mostly relevant to whoever owns and ships the CMS, not day-to-day editors.

  • Themes live as repo files indexed to a database. Each theme is a directory under resources/themes/{slug}/ — a theme.json manifest, page blades, routes.php + navigation.php, a starter overrides.json of copy, optional bundled media/, one JSON file per variant under variants/, and optional feature-pages/{feature}/ page sources for feature modules (donations, ecommerce, real-estate, restaurant). The themes:index command reads these into the themes / theme_variants tables (the same repo-files-to-DB model the design library uses). See docs/theme-system-plan.md.
  • Installs scaffold from a theme. A fresh install runs App\Support\Themes\ThemeInstaller, which copies the theme's pages into place, seeds its starter content, applies the chosen variant, and compiles the site. It's idempotent and re-run-safe: it never overwrites existing pages and won't re-apply a variant (and clobber your branding) once a site is established. It deliberately ignores feature-pages/ — those sources are installed only by the owning feature's toggle-on generator, so feature-gated pages never appear on installs that haven't enabled the feature.
  • Custom variants. "Save current design as variant" runs App\Support\Themes\ThemeVariantSaver, which snapshots the live branding, fonts, header/footer, and shared-row roles via ThemeCapturer::captureVariantData(). On a normal install the snapshot is a DB-only theme_variants row flagged is_custom — the indexer's prune passes skip these, and a newly shipped variant that collides with a custom slug re-slugs the custom one out of the way rather than clobbering it. On an Author-Mode install the snapshot is instead written to variants/{slug}.json and registered in theme.json — a shipped, committable variant.
  • Parked instances (folder-per-theme). Installing a theme post-install runs ThemeInstaller::installParked(), which materialises the theme into resources/views/theme-instances/{slug}/ (pages tree + routes.php/navigation.php snapshots + an instance.json of metadata and design state) without touching the live site. Its content seeds globally into content_overrides; because every theme's row slugs are frozen and theme-namespaced, multiple themes' content coexists in the DB with no collision and no schema change. The tree sits under resources/views/ on purpose — the daily orphan-content GC scans there, so a parked theme's content is never swept while it waits. Registry: App\Support\Themes\ThemeInstances.
  • The workspace. Parked pages are editable in the page editor by path (theme-instances/{slug}/pages/…); the editor runs them in an admin-only workspace mode where every live-only side effect is disarmed (no page-scoped override sweep, no version snapshot, no live sidecar compile, no shared-row fan-out), and shared rows are locked because they belong to the live site. Page create/clone/delete for the workspace go through App\Support\Themes\ThemeWorkspace, which writes into the instance's own tree and routes.php snapshot, never the live routes.
  • The switch. App\Support\Themes\ThemeSwitcher performs a checkpointed, resumable swap journaled in the theme_switch_state Setting: snapshot the outgoing site into its instance folder (pages, routes, nav, seeded bookkeeping, and its live design state) → park it → promote the incoming instance → regenerate content-type and feature pages the new theme doesn't itself ship (guarded so a theme-shipped page is never clobbered) → apply design state → rebuild sidecars, search, and CSS. A previously-live theme restores its snapshotted design on the way back, so A→B→A is faithful including customised branding. Driven from the dashboard (queued) or via php artisan theme:switch {slug} [--resume|--rollback].
  • The admin preview channel (two settings). theme.active_slug is what the public sees; theme.admin_preview_slug designates a parked instance for preview. The ThemeAdminPreview middleware renders that instance's pages at their real URLs — with its navigation, branding, and header/footer overlaid per-request via Setting::withRequestOverrides() — but only for an Admin+ user with the per-session toggle on. Guests are structurally safe: authenticated users never touch the response cache (GuestOnlyCacheProfile), and preview responses are marked no-store. Static URLs are covered in v1; record-driven detail URLs fall through to the live route.
  • Custom + captured themes. "Save current site as theme" runs ThemeCapturer targeting resources/themes-custom/ on a normal install (gitignored, so it survives CMS updates and is protected by the package updater) or resources/themes/ under Author Mode (for shipping). ThemeManifest::scan() reads both roots; a custom theme whose slug collides with a shipped one loses. To make that collision impossible in practice, install-local captures get the reserved custom- slug prefix (Theme::CUSTOM_SLUG_PREFIX — applied automatically, never double-applied) and the authoring CLIs (themes:new / themes:capture) reject custom-* slugs, so no shipped release can ever shadow a client’s own theme. Captured bundles install parked and switch like any shipped theme.
  • Export / import. App\Support\Themes\ThemeTransfer zips a theme's source_dir (export) and does the guarded inverse (import): zip-bomb ceilings, traversal/NUL/realpath guards mirroring FeatureInstaller::installFromZip, staged extraction into a hidden dot-dir, then the normal IndexThemesJob validation — a bundle that fails any check leaves no trace. Imports ALWAYS land in cms.custom_themes_path, never the tracked tree (promote by moving the dir and re-indexing). Surfaced as Export theme / Import theme on the Theme page and as themes:export / themes:import. A theme whose slug already exists (either root) is rejected — so a shipped theme's zip imported elsewhere no-ops safely.
  • Duplicate. App\Support\Themes\ThemeDuplicator copies a theme under a new slug as a full RE-NAMESPACE: every frozen row slug in every blade and every overrides.json row_slug is rewritten (:{src}- → :{new}- — the same clone+reslug move the Legal theme was authored with), bundle refs are stripped from theme.json and build-map.json dropped (the copy is hand-managed, detached from the Page Library bundle system, so themes:build's drift guard never applies to it), then the copy is indexed/validated like any theme — a failing copy leaves no trace. The dashboard flow (Start new theme) applies the same root/prefix policy as capture (clients → custom tree + custom- prefix; AuthorMode → shipped tree) and auto-parks the copy via ThemeInstaller::installParked so it's immediately editable.
  • Feature dependencies (required_features). A theme's theme.json may declare "required_features": ["ecommerce"]. ThemeInstaller::assertRequiredFeaturesAvailable() gates installation (a parked install checks availability only — enabling, with its migrations and page generators, is deferred to the moment the theme goes live via enableRequiredFeatures() + FeatureActivator), and an unknown or unavailable feature aborts with a RuntimeException.
  • Content-type dependencies (content_types + starter_items). The content-type twin of required_features, introduced for the Masthead theme (whose data-driven homepage queries the blog). "content_types": ["blog"] makes a live install materialize each named type from the seed catalog — type + generated /{slug} pages + routes, via the same scaffold path as the install wizard's checkboxes — while a parked install creates the type definition only (page + route generation is a live-site write, run by ThemeSwitcher's regenerate step at switch time). An entry may also be an object {"slug": "blog", "name": "Messages", "singular": "Message"} when the theme rebrands the type — how Cornerstone publishes sermons on the blog plumbing; the override applies at CREATION only, so an install's existing type is never renamed. "starter_items": "starter-items.json" seeds shipped starter records (a magazine's articles, a church's messages — with categories, tags, excerpts, and cover photos from the theme's media/) through the normal ContentItem write path. Strictly one-shot, twice over: a type that already has ANY item is skipped (existing data means the owner owns it), and a durable per-theme Setting marker (theme.starter_items_seeded.{slug}) blocks every later re-run — so an update-time re-seed can never resurrect articles the owner deleted. Both keys are validated at index time (unknown type slugs, malformed or mistargeted starter items reject the theme).
  • Navigation seeding & authoring tools. A theme's navigation.php returns ['menus' => [...]] in the shape of the navigation.menus Setting; fresh installs and theme switches seed it, ordinary re-seeds and variant switches leave a user's menu edits alone. themes:new {slug} scaffolds an empty theme; themes:capture {slug} snapshots a live site into resources/themes/; themes:install {slug} --variant= installs one programmatically.
  • Frozen slugs. Theme pages use stable, theme-namespaced row identifiers (e.g. hero-split:legal-home-1) so shipped starter copy can be keyed to them and two themes can never collide. The indexer rejects any theme whose identifiers aren't namespaced or collide with another theme — the same guarantee that lets parked themes' content coexist in one database.
  • Theme-template saves are self-freezing. The author never manages frozen slugs by hand: editing a theme source page in the dashboard (Author Mode) and saving runs App\Support\Themes\ThemeSourceSync, which (1) re-freezes any freshly inserted row's random slug into the theme's {theme}-{page}-{n} namespace (existing conforming slugs are never touched, so shipped overrides.json keys stay bound), (2) prunes overrides.json entries for rows that no longer exist on any theme page, and (3) bundles media the page references from the authoring install's storage into the theme's media/ + manifest.json so fresh installs receive it. Deleting a hero and inserting a different one is therefore just: delete, insert, save.
  • Compose-at-build: theme pages compile from Page Library bundles. A theme page is no longer necessarily hand-managed. A theme.json page entry may carry a "bundle": "{category}/{name}" ref pointing at a shipped design-library page bundle, and php artisan themes:build {slug} (App\Support\Themes\ThemePageComposer) compiles each such page from the bundle's @rows — rendering every row's library template with a frozen, theme-namespaced slug and the standard page scaffold, so the output is byte-for-byte the kind of page themes:capture snapshots and the whole runtime (installer, switcher, preview, instances) is untouched. Frozen ids survive rebuilds through the build-map.json lockfile (identity: {page} : {row template} : {nth occurrence} → slug — a kept identity key is never renamed, which is what keeps overrides.json starter copy bound). The identity is positional per template, so this stability has one boundary: inserting, removing, or reordering rows of the same template by hand-editing a bundle's @rows shifts the nth counters — every later same-template row rebinds to its predecessor's frozen slug, and its starter copy silently lands on the wrong instance. Distinct-template edits are always safe. Don't hand-edit same-template row order in a bundle; make that kind of change through the stub editor (whose save runs capture-back, regenerating bundle + lockfile together in one consistent step). The lockfile also stores a sha1 per compiled page: a page edited directly since its last build refuses to rebuild without --force, and the stub editor shows a "Compiled from …" badge on bundle-backed pages so an author knows the next build overwrites direct edits there. To change a compiled page permanently, edit the bundle's rows in the design library and rebuild. Hand-tuned class heads (SEO Title, layout description) survive rebuilds; only the row markup and its ROW:php blocks are recomposed.
  • Bundle extraction (the migration tool). php artisan themes:extract-bundles {slug} --category= decomposes an existing theme's compiled pages into shipped design-library rows (deterministic {theme}-{page}-{template} names, carrying @requiresFeature / @requiresContentType gates from their source templates) plus one page bundle per page, wires the bundle refs into theme.json, seeds build-map.json from the pages' existing frozen slugs, then runs a verification build and asserts parity (identical slug set per page, byte-identical overrides.json). The four shipped themes were migrated this way — their home/about/contact/terms/404 pages now compile from bundles filed under custom (Default), law (Legal), ecommerce (Storefront), and service (Realty). Pages containing shared/role rows (each theme's privacy page) can't be expressed by an @rows bundle and stay hand-managed.
  • Author Mode. Only the repo-owning authoring install (CMS_AUTHOR_MODE=true) can edit tracked theme/design-library source files from the dashboard, and it's what redirects "save as variant/theme" to the committable source tree. On a normal install those writes go to the gitignored custom trees instead, so the working tree stays clean and CMS updates apply without conflict.

Full implementation detail and build history live in docs/theme-system-plan.md.