Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Content Bundle Laravel Package

sylius/content-bundle

Sylius ContentBundle adds CMS-style content management to Sylius e-commerce applications. It provides entities and admin tools for creating and managing static pages, reusable content blocks, and rich text, helping storefronts publish informational content without custom development.

View on GitHub
Deep Wiki
Context7

Getting Started

Orient first: this is a Sylius/Symfony bundle, not a Laravel package. composer require sylius/content-bundle in a Laravel app will pull symfony-cmf/routing, Doctrine ORM mappings, and the Sylius ResourceBundle admin stack — none of which resolve against Eloquent, Laravel's container, or Laravel's router. The repo is also archived and read-only, so there are no upstream fixes and no PHP/Symfony version bumps. For a Laravel developer, the honest first step is deciding which mode you are in:

  • Reference mode (the realistic default): treat the bundle as a specification for "how a mature CMS page/static-content model looks" and port the ideas to Eloquent + Blade. This is the day-to-day value.
  • Interop mode: only relevant if you are maintaining a legacy Sylius app that already depends on it.

First 60 minutes, in order:

  1. Read src/Model/Page.php and src/Model/StaticContent.php plus their *Translation counterparts. That is the whole content model: a slug-bearing page entity with one translation row per locale, and a block entity (static content) with localized body HTML.
  2. Read src/Entity/ mappings — there are no shipped migration scripts, only Doctrine mappings, which tells you the schema is meant to be regenerated per-install and is a hazard to rely on.
  3. Look at Resources/config/routing.yml and Resources/config/routing/admin.yml to see the CRUD and admin surface SyliusResourceBundle generates.
  4. Read the Twig extension (src/Twig/) — this is where "render a page/block by slug" lives, and it is the smallest, most transferable piece.
  5. Skim the CMF wiring that resolves a slug to a content object; you are going to reimplement this as a catch-all route plus a cached resolver.

First use case to port: a marketing site inside a Laravel commerce app — pages (slug + layout + localized body + SEO meta) and blocks (keyed, localized fragments embedded in Blade layouts). That covers ~90% of what anyone actually used this bundle for.

If you genuinely need it in Sylius: require the 1.x line matching your Sylius minor, register in config/bundles.php, import both routing files, declare page and static_content classes under sylius_content, run doctrine:migrations:diff (you must author the migrations yourself), and wire symfony-cmf/routing-bundle's dynamic router to the page repository. Expect Composer conflict resolution to fight you.

Implementation Patterns

1. Port the content model before the code. The transferable shape maps almost 1:1 onto Laravel:

Sylius/CMF concept Laravel equivalent
Page + PageTranslation pages (slug, layout, published_at) + page_translations (locale, title, body, meta)
StaticContent + translation blocks (key, type) + block_translations (locale, body)
CMF route registry content_routes (locale, slug, content_type, content_id)
CMF dynamic router Catch-all fallback route + SlugResolver service, cached
SyliusResourceBundle CRUD Resource controller + Filament/Nova resource
Twig render_page / render_block Blade components <x-cms.page slug="terms" />, <x-cms.block key="homepage-hero" />

2. Use a separate route registry, not just a slug column. The single most valuable idea in the bundle is that routes are polymorphic records pointing at content, not a column on the page. That gives you slug history, 301 redirects, per-locale slugs, and future non-page content types (products, landing pages) resolved through one path. Implement it as content_routes with a content_type/content_id morph, unique on (locale, slug), and a redirect table beside it.

3. Slug resolution as a fallback route. Replace the CMF router with a Laravel catch-all:

Route::fallback(SlugController::class)->middleware('cache.headers:public;max_age=300');

The controller asks SlugResolver for the current locale's slug, returns a 301 if a redirect row matches, 404s if nothing resolves, and caches the resolved content per (locale, slug). Invalidate on publish via Cache::tags(['cms'])->flush() (Redis/database driver required).

4. Translations: prefer JSON columns for small CMS bodies. The bundle uses Doctrine *Translation entities because Symfony's admin needs per-locale rows. In Laravel, unless editors work in a translation-heavy workflow, json: title, body, meta keyed by locale is simpler, keeps whereRaw('json_extract(...)') search viable, and avoids the N+1 join. Go relational only if you need per-locale drafts or per-locale review states.

5. Twig helpers → two small pieces. The bundle's Twig extension is thin; replicate it as:

  • A Blade component that accepts a slug or key and fails soft (renders nothing, logs a warning) when content is missing — matching the bundle's behavior of not exploding the storefront on a missing block.
  • A cached view-model so block lookups do not hit the DB per request: Block::keyed('homepage-hero') memoized in a request-scoped repository.

6. Admin integration. The Sylius admin CRUD is generated from resource config. In Laravel, this is a Filament resource with two forms — a page form with a translatable repeater, and a block form keyed by string. Add a publish/unpublish action and a Cache::tags('cms')->flush() on save; the bundle relied on Sylius's publish workflow and cache clear subscribers for the same behavior.

7. Borrow the composition idea for blocks. The bundle's static content is a flat key→body lookup, deliberately not a page builder. Keep that constraint. If you need richer layouts, layer Blade components over the block registry rather than building nested block trees — the bundle never supported nesting and the moment you add it, admin complexity expands by an order of magnitude.

Gotchas and Tips

Do not attempt to install it in Laravel. The failure mode is a container-compilation error or an unresolvable dependency tree that consumes a day before the conclusion "cannot work" is obvious. Every concept in the bundle is reimplementable in a few hundred lines of Laravel; the dependency tree is not portable and never will be.

Archived means total ownership. No CVE response, no PHP 8.x compatibility work, no issue triage. If you fork, record it in an ADR and assign a named owner. In reference mode there is nothing to own — you only copied patterns, which is why reference mode is the defensible one.

There are no migrations, only mappings. In Sylius that means you generate schema from Doctrine mappings, which is a footgun for upgrades. In Laravel, write real migrations from day one — the schema:update shortcut this bundle relies on is exactly the practice not to import.

Translations and the fallback locale. The bundle resolves _locale from the request and falls back through configured locales. Port the ordering explicitly (requested → app fallback → en), because silent fallback to the wrong locale on published pages is the most common content bug in production. Write a test per locale.

Cache invalidation is a correctness risk, not a performance one. Two failure modes to test explicitly: published content not appearing (missed flush), and drafts leaking to public routes (resolver ignoring published_at or status). The bundle delegated this to Sylius subscribers; in Laravel you must implement it in the model observer and test both directions.

Slug and redirect drift. Changing a page slug without writing a redirect row breaks inbound links silently. The bundle's CMF route registry supported this; a naive slug column does not. Enforce redirect creation in the admin (updating observer on Page), and validate the redirect map on any content migration.

Twig helper semantics to preserve. The bundle's render helpers fail soft — a missing block returns empty rather than throwing. Reproduce that in the Blade component (@if($block) {...} @endif with a Log::warning), otherwise a deleted block takes down the storefront during deployment windows.

Extension points are a trap. The bundle supports subclassing Page/StaticContent and overriding resource config — a real extension point in Sylius, but you are not in Sylius. Do not design Laravel equivalents as "swappable bundled resources"; use a plain model plus a BlockRenderer contract if you truly need variant rendering.

RTL, sanitisation, and media. The bundle stores HTML bodies and assumes editors sanitise. If you port it, put sanitisation (mews/purifier or an HTML sanitizer) in the model mutator and store media references as explicit columns, not inline <img> tags inside the body — otherwise every future asset migration becomes a regex job.

Where to stop. The justified investment is roughly one to two days reading the model and Twig layer, plus a day mapping it to Eloquent. Budgeting time to learn Sylius resources, CMF routing, or Symfony container debugging is spend with zero downstream return in a Laravel shop — reject it explicitly in the design decision.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource