bitbag/cms-plugin
BitBag CMS Plugin adds flexible CMS capabilities to Sylius stores: manage pages, reusable blocks, sections, and media with a WYSIWYG editor and customizable templates. Easily create and organize marketing content, landing pages, and site information without touching code.
Minimal install, in order:
composer require bitbag/cms-plugin (pin to the Sylius version you run — see Gotchas).BitBag\SyliusCmsPlugin\BitBagSyliusCmsPlugin in config/bundles.php.config/routes.yaml (typically bitbag_sylius_cms_plugin_shop and bitbag_sylius_cms_plugin_admin).config/packages/_sylius.yaml, then run bin/console doctrine:migrations:diff && doctrine:migrations:migrate (or doctrine:schema:update --force in dev).bin/console assets:install --symlink and bin/console cache:clear so the admin UI loads its JS/CSS.Where to look first:
docs/ in the repo — installation, fixtures, customization and "custom section type" guides are all there and more accurate than blog posts.src/Entity/Page.php, Block.php, Section.php — the whole feature set flows from these three resources.src/Twig/Extension/ and src/Twig/Runtime/ — the public render API you'll call from templates.src/Controller/PageController.php — how a page is resolved from a slug, channel and locale.src/Resources/config/ — grids, forms, routes, services; this is where you override almost everything.First use case: log into /admin, create a Block with code homepage_banner, assign it to your channel, add an HTML section, enable it. Then in templates/base.html.twig add {{ bitbag_cms_render_block('homepage_banner') }}. That single loop — create block, attach section, render by code — is 80% of day-to-day use.
Rendering in Twig. The plugin exposes render and lookup helpers: bitbag_cms_render_block('code'), bitbag_cms_render_page(page), bitbag_cms_render_section(section), plus bitbag_cms_get_page_by_code() / bitbag_cms_get_block_by_code() when you want the object instead of HTML (e.g. to read page.title in a <h1>). Always pass a code, not an ID — codes are stable across environments, IDs are not.
Page routing. Shop pages are served by bitbag_cms_show_page_by_slug with {slug}. Two common patterns: (a) use it as a catch-all fallback route registered last so product/category routes still win, or (b) generate explicit links with path('bitbag_cms_show_page_by_slug', {'slug': page.slug}). Never hardcode /page/... URLs.
Custom section types. For anything beyond text/image/HTML you implement SectionTypeInterface (getType(): string, getTemplate(): string) and tag the service bitbag.cms.section_type. The new type appears in the admin Section Type dropdown; the editor's input lands in section.content, and your template handles presentation. This is the cleanest extension point — it keeps marketing copy in the CMS and markup in code.
Per-page templates. The Page entity has a template field whose choices come from plugin config. Register additional templates there so editors can pick a layout (landing page vs. plain content page) without touching Twig.
Extending entities. All three resources are mapped superclasses. Create App\Entity\Page extends BitBag\SyliusCmsPlugin\Entity\Page, add your fields, and point sylius_resource.resources.bitbag_sylius_cms_plugin.page.classes.model at it. Do the same for Block/Section if you need extra editorial fields.
Programmatic access. Outside Twig, inject PageRepositoryInterface, BlockRepositoryInterface or the renderer services. Use findOneEnabledByCode() in consumers (e.g. a product page controller) so disabled content doesn't leak, and let the renderer services handle template selection rather than duplicating it.
Fixtures. Use the shipped install command for demo data, but for project fixtures extend the plugin's abstract fixtures and reference blocks/pages by code — it keeps staging, production and CI consistent.
Collections and Media. Collections group pages/blocks for "related articles"-style listings; Media holds uploaded files. Both are resources you can query from custom controllers when a Section isn't flexible enough.
^1.12, ^1.13, etc.). Check composer.json in the tag before upgrading either side; mismatched Sylius versions manifest as obscure resource-bundle or form-type errors, not clean messages.enabled + channel assignment are both required. A block that silently renders nothing is almost always missing a channel, missing enabled: true, or has a stale cache. findOneEnabledByCode() returning null is the tell.Section.content is translatable in the tag you installed before promising multi-language copy — in older tags it isn't, which surprises editors.templates/bundles/BitBagSyliusCmsPlugin/..., not by editing vendor/. Clearing the Symfony cache after adding an override is mandatory; the Twig loader caches paths.cache:clear (or restart the container in dev).AbstractPageType etc. and override the grid in sylius_grid config instead of rewriting them; you keep upstream bug fixes that way.assets:install again — admin JS changes between releases and a stale asset causes broken editors on the Section form.How can I help you explore Laravel packages today?