whitecube/nova-page
Laravel Nova package for managing static pages with customizable templates, SEO fields, and flexible content blocks. Lets editors build and organize site pages directly from Nova, with translatable fields, slug handling, and publishing controls for fast, structured page management.
Architecture fit
The package is a thin content layer bolted onto Laravel Nova, and its architecture is the reason a TPM can advocate for it without a platform bet. Three pieces define the shape: a pages table where content lives as a JSON payload keyed by a template handle (no per-field columns), a Template base class you subclass per page archetype to declare Nova fields plus SEO fields, and a config file that maps a permanent handle to a template class and a Blade view. That is the whole system — a competent engineer can read it in an afternoon, which matters because it means the "what happens if the maintainer walks away" question has a cheap answer (fork) rather than an expensive one (re-platform).
The architectural consequence a TPM should internalize: content structure lives in code, not in the database. Adding a field to every legal page is a deploy touching one template class and one Blade view — a fifteen-minute PR, not a schema migration. That is the core trade the package makes, and it buys exactly the thing that usually derails "let marketing edit pages" initiatives: no per-content-type migration review, no DBA dependency, no backfill coordination. The cost is that content owners cannot invent new layouts without an engineer. That is a scope boundary, not a defect, and it belongs in writing before adoption (see Operational Impact).
Fit is strongest where the page set is enumerable and bounded: marketing landing and campaign pages, legal/terms/privacy, about/team, docs-style static content, localized brochure sites. Fit is poor for anything with freeform authoring, editorial workflow, or multichannel delivery — the package has draft/published as a boolean and nothing else.
Integration feasibility
Feasibility hinges on two facts that should be verified on day zero, not during a composer update. First, the Nova constraint: v0.4.0 was a single community PR adding Nova 5 compatibility, and the release notes do not state whether that was additive (Nova 4 and 5 both supported) or replacing (Nova 4 dropped). Run composer show whitecube/nova-page --all and read the require block. That one line decides whether upgrading Nova is optional or a forced, coupled migration — and since our own Nova version determines it, this is a schedule input, not an engineering detail. Second, Nova itself is a paid, closed-source commercial dependency. If we already run Nova, this is additive and cheap; if we don't, the true cost of this package is a Nova license plus the admin platform decision, and the package should be eliminated from the shortlist immediately.
Beyond that, integration is genuinely low-friction: composer require, one vendor publish (config, migration, PageResource), register the resource in NovaServiceProvider, php artisan migrate. The install path is measured in hours, and a first vertical slice — one "Standard page" template rendering end-to-end at a real URL — is a half-day of engineering. That number is worth quoting to stakeholders because it reframes the initiative from "build a CMS" to "configure one."
Two integration decisions must be made early because they are expensive to reverse: routing ownership and slug permanence. On routing, letting the package register its frontend route is fine for greenfield; in an existing app we should disable it and own a catch-all controller placed last, because that is the only place to control 404 semantics, cache headers, draft preview, reserved-prefix exclusion (/admin, /api, /blog), and redirect history. On slugs, there is no redirect table — renaming a slug silently breaks every inbound link. Choose the mitigation (a page_redirects table checked by the controller, or an explicit redirect step in the editorial runbook) before launch, not after a campaign URL has been emailed.
Technical risk Ranked by what would actually hurt:
fields() and existing rows still hold the old key. Every shape change needs defensive defaults plus a one-off backfill command. A TPM should treat "template field rename" as a migration-class change in the release checklist, because no tooling will remind anyone..* slug route above other routes eats /login, /blog, and API 404s, and "every URL returns 200 with an empty page" is both an SEO incident and, in practice, an incident-response discovery rather than a code-review one.deleting observer is the fix; if S3 cost or data-deletion obligations apply, add it to the acceptance criteria.Key questions
require block allow Nova 4 and 5, or drop 4? If dropped, is a Nova upgrade already on the roadmap, and does this package force its sequencing?Stack fit Requires Laravel with Nova. Full stop — without Nova this is not a candidate. Assuming Nova is in place, the fit is unusually clean because the package adds no new runtime surface: no second service, no external API, no separate auth, no parallel permission model. Content management stays inside the admin we already operate and audit. For a TPM, that is the headline: it removes a vendor relationship, an SSO integration, and a permissions reconciliation from the plan. Standard Laravel delivery machinery — Composer, migrations, config, Blade, feature tests — covers everything.
Migration path Adoption is greenfield-friendly but not migration-friendly, and the plan should say so. Existing hardcoded Blade pages and existing CMS content do not import themselves; someone must retype or script content into the JSON payload, per page, per locale. That is content-operations labor, not engineering labor, and it needs a named owner and a page-by-page inventory before the sprint starts. The realistic path:
PageResource on a branch.resources/views/pages/ and take ownership of them.Do not let step 5 start before step 3 is accepted. The failure mode is ten half-built templates and no agreed render contract.
Compatibility
Nova version is the compatibility question; PHP and Laravel constraints should be read off the same require block. Two ongoing compatibility obligations: Nova majors routinely change field registration and asset APIs, and template classes are precisely the surface that breaks — so Nova upgrades and this package's upgrade go on the same branch and the same ticket, never scheduled independently. And config:cache hides new templates, which presents as "the template doesn't exist" and burns support time; the runbook should say config:clear && nova:clear before debugging.
Sequencing Recommended order with rough shapes:
PageResource, one template, one view, sanitization and defaults in place, feature tests (published → 200, draft → 404, unknown slug → real 404, one test iterating every config template handle asserting class and view exist), seeder for fixed pages, HTML caching with saved/deleted invalidation.hreflang, page_redirects if adopted.The strategic value of this sequencing is that it converts "self-serve content" from a full engineering sprint into a template-design task, so marketing, campaign, legal, and about pages can ship as a fast-follow instead of competing with core product work.
Cross-team dependencies to schedule, not discover Legal/compliance sign-off on rich-text sanitization and on media deletion (GDPR); marketing sign-off on the page-type inventory and on the no-scheduling constraint; security review of the catch-all route and the XSS boundary; content-ops training on templates, publishing, and the slug-change runbook. Each is small; all are on the critical path if left implicit.
Maintenance
Recurring cost is low but real: template class and view changes are ordinary PRs; Nova upgrades are a coupled ticket; the fork contingency is a standing risk item to review quarterly, not a project. Two disciplines keep maintenance cheap and should be enforced from the first PR — subclass the shipped PageResource and override views rather than patching vendor files, and treat template handles as permanent database keys (adding a handle is a config change; renaming one requires Page::where('template','old')->update(['template'=>'new']) first; never repurpose a retired handle). The presenter/accessors layer for SEO fallbacks, image resolution, locale lookup, and per-field defaults is the single biggest day-to-day ergonomics win and should be built in Sprint 1, not retrofitted after twenty views have learned to poke raw JSON.
Support
Support load shifts in a specific, measurable, and politically useful direction: routine copy, headline, hero-image, and localized-copy changes move off the engineering backlog and onto content owners. Instrument it. Count page-change tickets and deploy frequency before and after adoption — that delta is the business case and it also sizes the threshold at which a fuller CMS becomes justified. Budget for a support runbook covering: template not appearing (config:clear && nova:clear), page rendering blank (missing translation / renamed JSON key / typo'd block type — all silent), 404-vs-200 confusion from the catch-all, and slug-change requests. Also budget for the fact that there is no workflow: no approvals, no scheduling, no versioning. For regulated pages the control is process discipline plus restricted publish permission, and that should be stated to stakeholders as a limitation rather than negotiated case by case later.
Scaling
Public pages are read-heavy, and the package adds nothing here — caching is ours to build. Cache rendered HTML keyed by slug + locale, invalidate on the model's saved/deleted events, and set Cache-Control in our own controller (another reason to own the route). At modest content volume with aggressive caching, scaling is a non-issue; traffic growth hits the standard Laravel/CDN path, not this package. The scaling limit that does bind is organizational, not technical: the number of page archetypes engineers are willing to maintain, and the volume of content changes that require a deploy because they touch structure rather than copy. When content owners start asking to invent layouts, the package has hit its ceiling — that is the CMS conversation, and it should be triggered by that signal rather than by a fixed date.
Failure modes Each needs an owner and a detection method:
/login, /api/*, /blog; it destroys SEO silently and is typically found by a third party.config:cache staleness; runbook fix, one-line cost, high support-frequency.deleting observer.Ramp-up
Engineering ramp-up is genuinely fast — an afternoon reading config/nova-page.php, the pages migration, the Template base class, the published PageResource, and the shipped views is the entire mental model, and the first template takes half a day. Content-owner ramp-up is the under-budgeted side: they need training on templates as fixed structures (you cannot add a section), on the draft/publish boolean as the only workflow, on the slug-change consequence, and on image handling. Plan a short enablement session and a one-page runbook, or the first month of "why can't I add a section" tickets will look like a product failure when it is actually a scope-boundary communication gap.
The one line to record in writing: this is a page editor, not a content platform. It assumes a known, developer-defined set of page types and blocks edited by a small team at modest volume. That assumption is the trigger condition for revisiting CMS investment when the roadmap adds editorial workflow, scheduling, versioning, approvals, or multichannel delivery — and writing it down now is what makes adopting a 239-star, single-maintainer MIT dependency a defensible decision rather than a deferred one.
How can I help you explore Laravel packages today?