Skip to content

Releases: Crumbls/layup

v1.3.1

31 May 19:12

Choose a tag to compare

Working on ADA, reducing redundancy. Lots going on, none breaking.

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.

01 May 14:00

Choose a tag to compare

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

  1. Run migrationsphp artisan migrate. The new migration adds parent_id and path columns to layup_pages, drops the unique-on-slug index, and backfills path from 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.
  2. Replace the $meta slot 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.
  3. (Optional) Configure SEO defaults. If you publish the config, the new layup.seo block lets you set title_suffix, site_name, default_og_image, and the breadcrumb home label.
  4. (Optional) Wire scheduled publishing. Make sure your app scheduler is running (schedule:work in dev, the standard cron in production). To wire layup:publish-scheduled yourself, set
    layup.scheduling.auto_publish to false.
  5. 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 from View to View|Htmlable|string. Existing Blade widgets still satisfy the wider type via covariance.
  • Internal type checks moved from instanceof BaseWidget to interface-based instanceof Widget in RegistersWidgets, 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() and assertWidgetRendersWithDefaults() accept any View|Htmlable|string from render() via a new renderToString() 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:doctor no 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 ...

Read more

v1.2.3

20 Apr 04:59
0e4fae0

Choose a tag to compare

Fix for missing stub

v1.2.2

05 Apr 16:30

Choose a tag to compare

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.php options
  • 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
  • .gitattributes to exclude docs, tests, and dev files from Composer dist installs
  • homepage and support URLs in composer.json for Packagist

Changed

  • README trimmed to concise overview with links to full documentation
  • Installation section updated with layup:install wizard and Filament prerequisite

Full Changelog: v1.2.1...v1.2.2

1.2.1

02 Apr 16:03

Choose a tag to compare

v1.2.1

Release v1.2.1 -- theme system, ColorPicker, mobile responsiveness

v1.2.0

28 Mar 07:32

Choose a tag to compare

Improved Installation & Diagnostics

Install Command (layup:install)

  • Pre-flight check ensures Filament is installed before proceeding
  • Automatically runs storage:link for uploaded image accessibility
  • Creates the frontend layout component from a stub if missing
  • Publishes Filament assets (filament:assets)
  • Detects if LayupPlugin is registered in any panel and warns if not
  • Warns when an existing layout is missing @layupScripts or Alpine.js
  • Runs layup:doctor at 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 LayupPlugin registration in Filament panels
  • Verifies storage symlink exists
  • Checks layout component file exists on disk
  • Scans layout for @layupScripts directive
  • Verifies safelist is referenced in app.css or tailwind.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.prefix to '' 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_paths config 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-columns widget 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, @layupScripts guidance, layup:doctor as post-install step

v1.1.2

22 Mar 21:30

Choose a tag to compare

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

19 Mar 14:20
02eb1b6

Choose a tag to compare

What's Changed

Full Changelog: 1.1.0...v1.1.1

1.1.0

16 Mar 06:58
77756c3

Choose a tag to compare

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

v1.0.6

10 Mar 23:50
3fc6b45

Choose a tag to compare

1.0.6 (2026-03-10)

Bug Fixes

  • correct class name typo (dLayupContent -> LayupContent) (b2a0ba1)