Shopper now runs on Laravel 13, and a class of __PHP_Incomplete_Class crashes on dashboard/settings refresh is gone. The store onboarding wizard was rebuilt on Filament's native Schema, dropping the Spatie wizard dependency.
Highlights
Laravel 13 support
Adds laravel/framework ^13.0 to the supported range (11, 12, 13). CI matrix now tests L11/L12/L13 on PHP 8.3 and 8.4. The only blocker, spatie/laravel-livewire-wizard (capped at Laravel 12), was removed via the onboarding rewrite.
Onboarding wizard rebuilt on Filament Schema
The store initialization flow moved from spatie/laravel-livewire-wizard (4 components) to a single Livewire component backed by Filament's native Wizard. New Shopper\Components\OnboardingWizard preserves the existing horizontal stepper. Smaller serialization payload, no inter-step state juggling, one fewer dependency.
Cache correctness: scalars only, never Eloquent objects
Same root fix across four spots, cache primitives and rehydrate on read:
shopper_setting()caches the resolved value, not theSettingmodelshopper_currency()caches thecodestring via->value('code')RecentOrderscaches order IDs, re-queries with eager loadsTopSellingProductscaches scalar stats, re-queries products with media
These crashed on refresh in Inertia starter projects where model classes were not autoloaded at unserialize() time.
Security: onboarding and settings hardened
InitializationWizard::mount()/save()nowabort(403)for non-admins lackingaccess_setting(the Livewire endpoint bypasses page middleware)ALLOWED_KEYSallow-list drops tampered payload keys before persistingSetupGuide::complete()gated onaccess_settingSaveSettings::saveSettings()is nowprotected, wraps writes in a transaction, batches the locked-check (3N to 1+N queries), and atomically invalidates thedefault_currencycache
Bug Fixes
- fix(core): cache resolved value in
shopper_setting()to prevent__PHP_Incomplete_Classby @mckenziearts in #520 - fix(core): cache resolved code in
shopper_currency()to prevent__PHP_Incomplete_Classby @mckenziearts in #521 - fix(core): correct swapped
instagram_link/twitter_linkdisplay labels by @mckenziearts in #519 - fix(core):
InventoryObservernow demotes rows withis_default = true(guard was a no-op) by @mckenziearts in #519 - fix(dashboard): cache scalar IDs in
RecentOrders/TopSellingProductsto prevent__PHP_Incomplete_Classon refresh by @mckenziearts in #525 - fix(security): harden onboarding wizard and settings cache by @mckenziearts in #524
- fix(types): correct
Discount.min_required(toDiscountRequirement) andTaxRateRule.reference_id(tostring | number) by @mckenziearts in #523
Improvements
- refactor(onboarding): replace
spatie/laravel-livewire-wizardwith native FilamentWizard, four components into one by @mckenziearts in #517
New Features
- feat(deps): add Laravel 13 support by @mckenziearts in #518
Dependencies
stripe/stripe-php^16.0to^19.0filament/filamentand media-library plugin^4.9to^4.11laravel/frameworkadd^13.0blade-ui-kit/blade-heroicons^2.6to^2.7codeat3/blade-phosphor-icons^2.3to^2.4codewithdennis/filament-select-tree^4.0to^4.1bacon/bacon-qr-code^3.0to^3.1danharrin/livewire-rate-limiting^1.0|^2.0to^1.3|^2.2laravelcm/livewire-slide-overs^2.0to^2.1stevebauman/location^7.2to^7.6- removed
spatie/laravel-livewire-wizard @shopperlabs/shopper-typesmigrated CommonJS to ESM, npm publish via OIDC Trusted Publisher (#523)
Breaking Changes
stripe/stripe-php 16 to 19. Three-major jump. Apps with custom Stripe SDK code must review the v17/v18/v19 changelogs. (StripeDriver itself only got PHPStan annotations.)
spatie/laravel-livewire-wizard removed. If you relied on it transitively, require it directly:
composer require spatie/laravel-livewire-wizardThe three onboarding step Livewire aliases are gone, remove direct usages:
<livewire:shopper::initialize-store-information />
<livewire:shopper::initialize-store-address />
<livewire:shopper::initialize-store-social-link />SaveSettings::saveSettings() is now protected (was public) and takes a second bool $locked = true argument. If you used the trait and called it externally, wrap it in a public action.
TextInputSelect::hydrateState() signature changed (Filament sync). If you extended this non-final class and overrode the method, update the signature.
TypeScript types (@shopperlabs/shopper-types): Discount.min_required narrowed from string to DiscountRequirement; the package is now ESM-only ("type": "module" + exports map).
Upgrading
composer update shopper/framework
php artisan cache:clear # flush stale Setting/dashboard cache from v2.8.1No migrations. No config changes.
Full Changelog: v2.8.1...v2.9.0