Releases: Crumbls/layup
v1.3.1
Dual-render widgets (Blade or Livewire per widget), drop-in SEO meta component, nested pages, scheduled publishing, and a panel toggle to use Layup as a pure rendering engine.
Headline features
Dual-render widgets — Livewire support
Widgets can now render through either a Blade view component (the default) or a Livewire component, opt-in via a new BaseLivewireWidget base class. Same Widget contract, same editor experience, same
registration — only the frontend render path differs. BaseWidget stays as a back-compat alias of the renamed BaseBladeWidget, so every existing widget, stub, and downstream package continues to work
without modification. livewire/livewire is a soft dependency — install it only when you actually use BaseLivewireWidget. New identity traits (HeadingIdentity, ButtonIdentity,
NumberCounterIdentity, NewsletterIdentity) let downstream packages ship Livewire flavours of built-ins without redeclaring schema, defaults, or preview. See docs/advanced/livewire-widgets.md.
Drop-in SEO meta component
New <x-layup-seo /> Blade component. Drop it once into your layout's <head> and Layup emits the full meta block (description, OG, Twitter, canonical, robots, article timestamps, JSON-LD) on every
layup-rendered request. On non-layup routes the component renders nothing, so it's safe in shared layouts. The Page Settings modal now exposes Meta Description and a "Hide from search engines" toggle. New
layup.seo config block adds title_suffix, site_name, default_og_image, and home_breadcrumb_label. BreadcrumbList JSON-LD now walks the parent chain with real page titles.
Nested pages
Pages can now form parent → child trees. A new path column stores the resolved URL (cached on save) and the unique constraint moves from slug to path — so two pages can share a slug under different
parents. Migration 2026_04_27_000001_add_nesting_to_layup_pages_table.php adds the columns and backfills path from slug for existing rows. layup.pages.max_depth (default 10) caps tree depth.
Scheduled publishing
Pages with status = 'scheduled' and a future published_at flip to published once their publish time arrives. The layup:publish-scheduled console command (with a --dry-run flag) does the work, and
the service provider auto-registers it on the app's scheduler to run every minute. Set layup.scheduling.auto_publish to false to wire it yourself (e.g. on a single dedicated worker).
Panel toggle: use Layup as a rendering engine
New layup.pages.enabled config option registers or hides the bundled PageResource in the Filament panel. Disable it when you're using Layup purely as a rendering engine — attaching HasLayupContent to
your own models and managing content through your own resources. Frontend rendering, the @layup directive, and existing pages are unaffected. Thanks @TheGodlyLuzer
(#20).
Bonus: PageTitleWidget
A new built-in widget that renders the current page's <h1> at render time, perfect for shared templates and layouts. Brings the built-in count to 96.
Upgrading from 1.2.x
- Run migrations —
php artisan migrate. The new migration addsparent_idandpathcolumns tolayup_pages, drops the unique-on-slug index, and backfillspathfrom existing slugs. Pages whose
slug already contains slashes continue to work; their breadcrumb falls back to path-derived segments until you split them into real parent/child rows. - Replace the
$metaslot with the SEO component. If your host layout used{{ $meta ?? '' }}in the<head>, swap it for<x-layup-seo />. The slot contract is removed entirely — the component is
the only supported integration point. Hosts on the bundled reference layout (resources/views/layouts/page.blade.php) get the swap automatically. - (Optional) Configure SEO defaults. If you publish the config, the new
layup.seoblock lets you settitle_suffix,site_name,default_og_image, and the breadcrumb home label. - (Optional) Wire scheduled publishing. Make sure your app scheduler is running (
schedule:workin dev, the standard cron in production). To wirelayup:publish-scheduledyourself, set
layup.scheduling.auto_publishtofalse. - Livewire is opt-in. No action needed unless you want to use
BaseLivewireWidget; existing widgets continue to render through Blade.
Notable internal changes
BaseView::render()return type widened fromViewtoView|Htmlable|string. Existing Blade widgets still satisfy the wider type via covariance.- Internal type checks moved from
instanceof BaseWidgetto interface-basedinstanceof WidgetinRegistersWidgets,LayupContent,LayupAssertions, and the default-completeness test. Downstream code
that introspects widgets at runtime should follow suit if it intends to recognise Livewire widgets. LayupAssertions::assertWidgetRenders()andassertWidgetRendersWithDefaults()accept anyView|Htmlable|stringfromrender()via a newrenderToString()helper.
Fixes
- Editor-set page descriptions and Open Graph data now reach rendered HTML on host layouts (root cause of the SEO component work).
- Backfilled missing top-level defaults across 12 widgets (22 fields) so freshly inserted widgets render with complete data.
layup:doctorno longer flags Repeater/Builder sub-fields as missing top-level defaults.- Revision restore produces a cleaner diff view and re-applies content without losing widget IDs.
Stats ...
v1.2.3
Fix for missing stub
v1.2.2
Documentation & Packaging
Added
- Full documentation site in
docs/following Spatie conventions (30 pages across 6 sections) - Getting Started guide: creating pages, adding widgets, saving and publishing
- Widget reference pages for all 5 categories (Content, Media, Interactive, Layout, Advanced)
- Configuration reference with all
config/layup.phpoptions - Grid system documentation (12-column grid, responsive spans, breakpoints, visibility)
- Advanced guides: custom widgets, extending widgets, Tailwind safelist, revision history, page templates, frontend rendering, theme system, testing helpers, rendering content
- API reference: Widget contract, models, service provider, support classes
.gitattributesto exclude docs, tests, and dev files from Composer dist installshomepageandsupportURLs incomposer.jsonfor Packagist
Changed
- README trimmed to concise overview with links to full documentation
- Installation section updated with
layup:installwizard and Filament prerequisite
Full Changelog: v1.2.1...v1.2.2
1.2.1
v1.2.1 Release v1.2.1 -- theme system, ColorPicker, mobile responsiveness
v1.2.0
Improved Installation & Diagnostics
Install Command (layup:install)
- Pre-flight check ensures Filament is installed before proceeding
- Automatically runs
storage:linkfor uploaded image accessibility - Creates the frontend layout component from a stub if missing
- Publishes Filament assets (
filament:assets) - Detects if
LayupPluginis registered in any panel and warns if not - Warns when an existing layout is missing
@layupScriptsor Alpine.js - Runs
layup:doctorat the end for a full health check - Next steps output now mentions bun/pnpm/yarn alongside npm
- Documents that pages default to draft status
Doctor Command (layup:doctor)
- Checks
LayupPluginregistration in Filament panels - Verifies storage symlink exists
- Checks layout component file exists on disk
- Scans layout for
@layupScriptsdirective - Verifies safelist is referenced in
app.cssortailwind.config.js - Warns when all pages are drafts with none published
- Widget view errors now include the expected file path
Route Exclusion for Root-Prefix Pages
- Setting
frontend.prefixto''no longer shadows/admin,/livewire, or other framework routes - Auto-detects Filament panel paths via
Filament::getPanels() - Excludes common framework paths (livewire, filament, storage, api, sanctum, telescope, horizon, pulse)
- New
frontend.excluded_pathsconfig for custom exclusions
Content Validator
- Field-level required checks only run in strict mode
- Fixes false "missing required field" warnings on widget save in the builder
Widget Edit Action
- Uses
->form()instead of->schema()to ensure Filament opens the slideover modal
Other
- Added missing
text-columnswidget Blade view - Moved page create/edit details into modals for cleaner builder UX
- Removed unused imports in EditPage
- Improved README: installation steps, Alpine.js requirement, root-prefix routing,
@layupScriptsguidance,layup:doctoras post-install step
v1.1.2
Minor changes to documentation and an installer command. Gearing up for some bigger stuff. Just needing the v to match the docs.
1.1.1
1.1.0
Summary
- Add 13 features for widget developers: FieldPacks, prepareForRender hook, render isolation (try/catch), widget validation rules, search tags, deprecation support, onDuplicate lifecycle hook, asset
declaration, WidgetData value object, widget test assertions, default data completeness audit in doctor, make-widget --with-test flag, debug-widget command - Add agents.md -- complete zero-ambiguity reference for AI agents and developers to create widgets without error
- Add developer tooling: layup:list-widgets, layup:search, layup:doctor, ContentWalker, HasLayupContent trait, LayupAssertions, PageFactory
Test plan
- All 1,086 existing tests pass (3,448 assertions)
- All new Widget contract methods have no-op defaults -- fully backward compatible
- 5 new files, 11 modified files, 0 removed files