aimeos/pagible
Aimeos Pagible is a Laravel/PHP package for creating and managing content pages with reusable blocks, flexible layouts, and a simple structure for editable site content. It integrates with Laravel apps and the Aimeos ecosystem.
Pagible is a full CMS that lives inside your Laravel app rather than beside it — you get the admin UI, content storage, routing, and the delivery APIs (JSON:API + GraphQL) from one package. Treat it like a first-class part of the app, not a bolt-on.
Minimum viable setup:
composer require aimeos/pagible
php artisan vendor:publish --provider="Aimeos\Pagible\PagibleServiceProvider"
php artisan migrate
Publishing typically drops a config/pagible.php, route definitions, and theme/template stubs into your app. Run php artisan vendor:publish with no arguments first to see the available tags (config, migrations, assets, themes) rather than guessing — Aimeos packages usually group them by tag, and publishing only what you need keeps upgrades clean.
Where to look first, in this order:
config/pagible.php — this is where multi-site, locale, storage disk, cache TTL, and API enablement are decided. Read it fully before writing a single line of code; most "why doesn't this work" questions are answered here.vendor/aimeos/pagible/routes/ — know exactly which URLs the package claims. This determines whether your catch-all /{slug} route or theirs wins.vendor/aimeos/pagible/src/ — specifically the service provider (bindings, view namespaces, route middleware) and the models/migrations if you need to extend content types./admin) after seeding a first user — log in and create a page by hand before touching code.First use case to prove the integration end-to-end: create a page in the admin with two content blocks, assign it a template from the default theme, then render it at its slug through your own controller and fetch it via the JSON:API endpoint. If both paths return the same content, your config, caching, and routing are all correct, and you have a working mental model for everything after.
For headless setups, confirm the API routes are enabled in config and check php artisan route:list --path=api — the JSON:API surface is the fastest way to see what the package actually models.
Pages as compositions, not rows. The productive pattern is to keep Page thin (slug, locale, template, status, SEO fields) and push all variability into blocks/elements referenced by the page. Editors reorder blocks; you never migrate content again. When a client asks for a new layout, you add a block type and a Blade partial — not a schema change.
Template and theme workflow. Keep your project's templates in resources/views/ and let the package fall back to its own. Register your theme in config rather than editing vendor files, and compile theme assets through Vite like any other frontend asset so hashing and cache busting stay consistent. If the package ships its own asset pipeline, disable it as soon as you adopt Vite — two pipelines is a guaranteed source of stale CSS in production.
Routing. Two viable strategies:
Route::get('/{slug}', [PageController::class, 'show'])->where('slug', '.*') calling into Pagible's resolver. More control, easier to mix with bespoke controllers, and lets you inject middleware (locale detection, A/B tests, auth) before resolution.Pick the app-owned route for anything with a login area or e-commerce.
API consumption. Use JSON:API for a headless frontend or mobile app: fetch collections with include= for blocks/media and fields[page]= sparse fieldsets to keep payloads small. Use GraphQL when a client needs a single query spanning pages, navigation, and settings — it eliminates three round-trips. Cache the GraphQL responses on the client, not in Laravel, so editor publishes invalidate predictably.
Editorial workflow. Create Laravel policies/gates that map to the package's roles. Editors get publish rights on their site/locale only; developers get template management. Multi-site tenants should be separated by a config-driven site key resolved from the hostname in middleware, not by duplicating the app.
Caching. Content reads should be cached and invalidated on save. Listen to the package's model events (or a publish event if one exists) and flush a tagged cache keyed by page:{id} and site:{key}. Use Cache::tags() only if your store supports it — otherwise version your cache key with a counter incremented on publish.
Deployment. This is billed as cloud-native, so expect stateless containers: keep uploads on S3 or similar, run migrations as a release step, and never write to the filesystem outside storage/. Warm the content cache post-deploy so the first request isn't a cold render.
/login, /api/*, or your own resource routes. Run php artisan route:list after install and after every package upgrade. If the admin UI 404s, a catch-all is almost always the cause.resources/views or config/ shadows future package updates. Publish the minimum, and keep a short note in your repo listing exactly what you've shadowed and why.composer.json, read the changelog before bumping, and run the migration diff first (php artisan migrate --pretend). Keep content migrations — slug rewrites, block type renames — as your own idempotent Artisan commands, never as ad-hoc SQL.include is opt-in; clients that omit it get shallow objects, and clients that request deep includes can generate expensive queries. Audit slow endpoints with Telescope/Clockwork and consider caching the assembled response rather than the models.View::prependNamespace), model binding overrides in the container, and custom block/template registration. Aimeos packages generally expose these; a fork will cost you every future upgrade.How can I help you explore Laravel packages today?