Concepts
This page explains the design decisions and mental models behind CMS Block Builder. Read it to understand why the plugin works the way it does, not just how to use it.
The problem: Shopware CMS blocks are fixed by default
Shopware 6 ships with a set of pre-built CMS blocks (e.g. two columns, image with text, product slider). These blocks are registered by Shopware core or by installed plugins as compiled code. A merchant who needs a different layout — say, a three-column block where the first column is wider than the others — must:
- Write a Shopware plugin that registers the new block in PHP and JavaScript.
- Create a Twig template for the storefront.
- Deploy the plugin and rebuild the administration.
This is a developer task, typically costing hours of agency time. CMS Block Builder eliminates this dependency by letting merchants register new block types through the admin UI.
What a custom block is
A custom block is a named, reusable grid layout composed of existing Shopware CMS element types. It has:
- A technical name — the identifier that becomes the block type string
ssd-custom-<technicalName>. This is permanent because it is stored in every CMS page that uses the block. - A grid configuration — a JSON description of which areas exist on the 12-column CSS Grid canvas, per breakpoint.
- A slot assignment — a mapping from each area ID to a CMS element type (e.g.
image,text,product-slider).
When a merchant places the block on a page in the Shopping Experiences editor, Shopware stores ssd-custom-my-block as the block type in its cms_block table. The actual layout data (which element goes where) lives in ssd_custom_block.
Elements vs blocks
Shopware CMS has two composition layers:
- Elements are individual content widgets: a text area, an image, a product slider. Each element manages its own data and rendering.
- Blocks are layout containers that hold one or more elements arranged in columns or areas.
CMS Block Builder works at the block layer. It composes elements into a grid but does not create new element types. Every element you place inside a custom block is a standard Shopware element with all its standard configuration options.
This is by design: the plugin gains all future Shopware element improvements for free, and existing element templates handle their own data loading, caching, and SEO.
The 12-column CSS Grid canvas
The grid always has 12 columns, matching the Bootstrap 12-column grid Shopware's storefront uses. Row count is configurable (default: 4) and can be extended.
Areas are defined by rowStart, rowEnd, colStart, colEnd — zero-indexed coordinates in CSS Grid terms. An area spanning columns 0–6 on row 0–1 occupies the left half of the first row.
The admin Block Composer renders this grid directly as a CSS Grid and lets merchants draw areas by click-dragging. The Twig storefront template translates the same JSON into grid-column and grid-row inline styles.
Structure locking
Once a custom block is placed on one or more CMS pages, its structure is locked. This means:
- You cannot add, remove, or rearrange areas.
- You cannot apply presets or clear all areas.
- You cannot change the number of rows.
The reason is referential integrity. Each cms_block row in the Shopware database references the block type string and stores element configuration per slot name. If you removed a slot, the stored element configuration would become orphaned. If you added a slot, there would be no content for it on pages that already use the block.
What you can do on a locked block:
- Swap element types in existing slots (the slot ID stays the same).
- Adjust tablet/mobile layout positions.
- Change the block name, category, and position.
If you need a different layout, create a new block with the updated grid, then manually replace the old block on each affected page.
Breakpoints and responsive design
Each block stores three independent layout configurations: desktop, tablet, and mobile. On the Desktop tab, you define the canonical layout and element assignments. On the Tablet and Mobile tabs, you define how those same slots are positioned for smaller screens.
Element content is shared across breakpoints. Only the grid positions differ. This matches how responsive CSS Grid works — the same content is re-laid-out, not duplicated.
The storefront renders all three grid containers in HTML. CSS (compiled from Bootstrap mixins) hides and shows the appropriate container for the current viewport. If a breakpoint layout is empty, the desktop layout serves as the fallback.
Block registration at runtime
Custom blocks are not baked into the theme at build time. They are loaded dynamically:
- Admin side: When the Shopping Experiences editor loads, a JavaScript override (
ssd-cms-block-registry.js) fetches all active custom blocks from the API and callscmsService.registerCmsBlock()for each one. This makes them appear in the block picker alongside built-in blocks. - Storefront side:
CustomBlockRegistrationSubscriberlistens to theCmsPageLoadedEvent. For eachssd-custom-*block on the page, it looks up the matchingssd_custom_blockentity and attaches the grid config as a Twig extension. The genericcms-block-ssd-custom-block.html.twigtemplate reads this extension to render the grid.
Because registration is runtime-dynamic, activating or deactivating a block takes effect immediately without a cache clear or admin rebuild.
Technical name immutability
The technical name becomes part of the block type string ssd-custom-<technicalName>. This string is stored in the Shopware cms_block table for every instance of the block on every page. Changing it would orphan all existing usages — the storefront would not know how to render blocks of the old type.
For this reason the Technical Name field is editable only during block creation and becomes read-only after the first save.
Uniqueness validation
On creation, the plugin checks the technical name against two sources:
- The Shopware CMS block registry (core blocks + plugin-registered blocks) to prevent naming conflicts with existing block types.
- The
ssd_custom_blockdatabase table to prevent duplicate custom blocks.
The check runs with a short debounce as you type, so you see inline feedback before saving.
