refineddigital/cms
A flexible content management package for Laravel by Refined Digital, offering page and block management, media handling, SEO tools, and an admin interface to build and maintain site content quickly.
Install and confirm compatibility first. This package has essentially no adoption signal (0 stars, 0 dependents), so its composer.json is your only contract:
composer require refineddigital/refined-cms-core
composer show refineddigital/refined-cms-core # inspect requires + version
Check the illuminate/* constraints against your Laravel version before installing. A low-traffic CMS core is usually pinned to an older Laravel major, and composer require failing on constraints is your first and cheapest signal that you'll be maintaining a fork rather than consuming a package.
Publish, migrate, boot.
php artisan vendor:publish --provider="RefinedDigital\CMS\Providers\RefinedCmsServiceProvider"
php artisan migrate
php artisan route:list
Confirm the actual provider class name from vendor/refineddigital/refined-cms-core/composer.json (extra.laravel.providers) — don't trust a guessed FQCN. If auto-discovery is absent, register it manually (config/app.php on Laravel ≤10, bootstrap/providers.php on 11+).
Where to look first. Treat vendor/refineddigital/refined-cms-core/src/ as the documentation:
| Path | Why |
|---|---|
routes/ |
Reveals the admin prefix, middleware stack, and whether there's a catch-all front-end route |
src/Http/Controllers |
How content is resolved and passed to views |
src/Models |
Base models/traits you'll extend |
config/ |
The real set of extension knobs |
database/migrations |
Schema you inherit, and whether migrations are publishable |
resources/views |
View namespace used for overrides |
First use case. Stand up a page-driven site end to end: install → migrate → locate the admin route from route:list → create a page → hit it on the front end. This single loop exercises routing, model resolution, view rendering, and auth in one pass, and it will surface 80% of the integration friction immediately.
Never edit vendor code — extend it. This package is a dependency with no community to absorb your patches. Keep all customization in app/:
$table, $fillable, and casts explicitly.AppServiceProvider rather than editing the original.resources/views/vendor/{namespace}/ — never touch the package's Blade.Model your content types as first-class app code. Rather than pushing everything through a generic page record, define your own Eloquent models + migrations for structured content, and use the package purely for the admin surface and page/template plumbing. This keeps you portable if you ever drop the package.
Template/partial convention. Most CMS cores of this shape map a page to a template name, then render resources/views/templates/{template}.blade.php. Verify the resolution order in the controller, then standardize on it for your team — one place where template names are declared (a config array or a small registry class), not scattered string literals.
Route ordering is the integration point. If the package registers a catch-all front-end route, register your own application routes before it loads. Prefer a single explicit Route::get('/{slug}') in your routes/web.php delegating to the package's resolver over relying on implicit ordering.
Guard the admin area explicitly. Don't assume the package's middleware is sufficient. Wrap the admin prefix in your own auth + role/ability middleware in a service provider or route group, and add a feature test asserting a guest gets a redirect/403.
// tests/Feature/AdminAccessTest.php
$this->get('/admin')->assertRedirect('/login');
Local patching workflow. If you need changes upstream can't provide, use a Composer path repository so the package lives in your monorepo as a real, diffable dependency:
"repositories": [{ "type": "path", "url": "packages/refined-cms-core" }]
Pin the version exactly ("refineddigital/refined-cms-core": "1.2.3") and commit composer.lock. With 0 dependents, an unexpected patch release will not be caught by anyone else.
Seeding and testing. Build factories for the package's content models so feature tests can assert real rendered pages with RefreshDatabase, rather than mocking the resolver.
Abandonment is the primary risk, not bugs. Before committing, check the repo's last commit date, open issue count, and whether the Laravel constraint matches current Laravel. Budget for "we own this code" from day one. Mirror the repository (or vendor the src/) so a deleted GitHub repo doesn't break your build.
Migrations may be load-only or publishable — know which. If they're registered via loadMigrationsFrom, you cannot modify them; add your own follow-up migrations for schema changes. If they're publishable, publishing creates a permanent fork point: once deployed, editing a published migration silently diverges from environments that already ran it.
Catch-all routes break route:cache and swallow new routes. A Route::get('{any}') fallback is common in CMS cores. Symptom: a newly added route 404s or renders a CMS page instead. Debug with php artisan route:list --path=your-segment -v and check ordering. Closure-based catch-alls also make route caching unreliable.
Config caching hides your edits. If you edit published config and see no change, run php artisan config:clear. Also confirm the package reads its config with a default fallback — if it calls config('refined-cms.x') without a default, an unpublished config file means null at runtime, not the package's shipped defaults.
View override not taking effect: the namespace is the usual culprit. Confirm with php artisan view:clear and check View::getFinder()->getHints(); the publish tag may target resources/views/vendor/{vendor}/{package} rather than .../{package}.
Admin route surface. Run php artisan route:list --columns=method,uri,middleware and store the output in your repo's docs. With no external documentation, this list is your API reference, and diffing it on upgrade is the fastest way to spot breaking changes.
Audit the security-relevant surface yourself. A single-maintainer CMS with a file upload / media component deserves a read of: mass-assignment ($guarded vs $fillable), upload MIME + extension validation, storage path construction (traversal), and whether admin routes enforce CSRF and authorization per-action rather than per-prefix.
Upgrade procedure. Since there's no semver guarantee, diff vendor/refineddigital/refined-cms-core between versions in a scratch branch before bumping, and run your feature-test suite against a real rendered page — not just a 200 status.
Extension points to prefer, in order: published config → published views → model subclassing → container rebinding → service provider hooks/events. Reaching for the last two before exhausting the first three is how projects end up unable to upgrade.
How can I help you explore Laravel packages today?