sylius/cms-plugin
Sylius CMS Plugin adds content management to Sylius stores, letting you create and manage static pages and reusable content blocks with a WYSIWYG editor. Integrate CMS content into your storefront and edit marketing or informational pages without code.
Install the plugin and wire it into a Sylius application:
composer require sylius/cms-plugin
Register the bundle in config/bundles.php:
Sylius\CmsPlugin\SyliusCmsPlugin::class => ['all' => true],
Import the plugin configuration and routing (the plugin relies heavily on Sylius resource config, so both the app config and admin/test routes must be loaded):
# config/packages/_sylius.yaml
imports:
- { resource: "@SyliusCmsPlugin/Resources/config/app/config.yaml" }
# config/routes/sylius_cms.yaml
sylius_cms:
resource: "@SyliusCmsPlugin/Resources/config/routing.yaml"
# config/routes/sylius_admin_cms.yaml
sylius_cms_admin:
resource: "@SyliusCmsPlugin/Resources/config/admin_routing.yaml"
Run migrations and (optionally) load the CMS fixtures, then install assets:
bin/console doctrine:migrations:migrate
bin/console sylius:fixtures:load # if you have the cms fixtures enabled
bin/console assets:install
Where to look first: browse src/Resources/config/ inside the plugin to see the registered resources (Page, Block, Section, Collection), then src/Resources/views/ for the default templates you can override. Log into /admin and you'll find a CMS section with Pages, Blocks, Sections and Collections — that is the mental model: a Page is composed of Sections, each Section renders Blocks, and Collections group Blocks for reuse.
First use case: create a Block with code footer_contact, then render it in templates/bundles/SyliusShopBundle/layout/footer.html.twig:
{{ render_block('footer_contact') }}
Render content at specific points in the storefront. The plugin registers Twig functions/TwigExtensions that resolve blocks, pages, sections and collections by their code. Typical usage:
{# single block by code #}
{{ render_block('homepage_promo') }}
{# a page by its code/slug #}
{{ render_page('about-us') }}
{# a section (a layout template wrapping several blocks) #}
{{ render_section('homepage_hero') }}
{# a collection of blocks #}
{{ render_collection('featured_brands') }}
Compose marketing pages from Sections + Blocks. Think of a Page as a container; Sections (each with a template field) define the layout slices, and Blocks are the actual content pieces. In the admin, create the Page, add Sections, assign Blocks to Sections. This lets non-developers rearrange content without touching Twig. The template field on a Section maps to a Twig template under the plugin's views/ folder — add your own under templates/bundles/SyliusCmsPlugin/ to introduce new layouts.
Define custom block renderers. The Block entity has a template property that determines which Twig partial renders it. Override or add templates in templates/bundles/SyliusCmsPlugin/Block/ (e.g., my_banner.html.twig), then select that template in the admin block form (or fixtures) by name.
Seed content via fixtures. Use the plugin's fixture classes (Sylius\CmsPlugin\Fixture\BlockFixture, PageFixture, etc.) in your own AppFixtures or reference them in config/packages/_sylius_fixtures.yaml — handy for shipping a baseline of blocks (header, footer, homepage_*) with an application.
Extend via Sylius resource conventions. The plugin's forms, grids and controllers all follow the Sylius pattern with {resource}.yaml configs under config/packages/. Override a form type by aliasing sylius_cms.form.type.block (or similar) in your services.yaml, or extend the admin grid by importing and tweaking the plugin's grid YAML.
Frontend page routing. For user-facing pages, either use the plugin's PageController with the sylius_cms_page_show route (slug-based) or build a lightweight controller that fetches the Page via Sylius\CmsPlugin\Repository\PageRepositoryInterface::findOneByCode() and renders the plugin's Page/show.html.twig. Register the route in config/routes.yaml once and link from your navigation.
Programmatic access. Inject PageRepositoryInterface, BlockRepositoryInterface, CollectionRepositoryInterface, or SectionRepositoryInterface into your services/controllers when you need to pull CMS content outside Twig (e.g., in a JSON API response or an email template).
composer.json require block before composer update.routing.yaml and admin_routing.yaml — if you only import one, the admin screens or the frontend page display will 404 silently.template field is a string contract. A Block/Section only renders if its template value matches a real Twig file under SyliusCmsPlugin/.../views/ or a template you've overridden under templates/bundles/SyliusCmsPlugin/. A typo produces a silent render failure or a "template not found" — check var/log/dev.log and the Twig profiler.BlockTranslation, PageTranslation). If a code exists only in one locale, render_block() may return nothing in another locale. Always provide translations for every enabled Sylius channel/locale, or override the repository lookup in the Twig extension.bin/console cache:clear in dev if using a stale Twig loader, and check http_cache config in prod.config/packages/_sylius_fixtures.yaml or your AppFixtures.templates/bundles/SyliusCmsPlugin/Resources/views/.... Do not edit files inside vendor/ — they will be lost on composer update.sylius_cms.form.type.block and the related grid by key in your config/packages/. Because the plugin uses the generic Sylius admin controller, adding a grid column usually only requires YAML, but adding a form field requires a decorated form type and a DB migration on the corresponding entity.{{ dump() }} inside a custom block template to confirm the entity is being passed; check Sylius\CmsPlugin\Twig\Extension\* in the plugin source to see exactly what context is available (the entity, its translations, and any Collection/Section parent). This is the fastest way to understand what render_block() actually provides.sylius_cms.repository.page, etc.) rather than forking — the service IDs are stable across minor versions and let you swap implementations cleanly.How can I help you explore Laravel packages today?