github shopperlabs/shopper v2.9.0

7 hours ago

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 the Setting model
  • shopper_currency() caches the code string via ->value('code')
  • RecentOrders caches order IDs, re-queries with eager loads
  • TopSellingProducts caches 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() now abort(403) for non-admins lacking access_setting (the Livewire endpoint bypasses page middleware)
  • ALLOWED_KEYS allow-list drops tampered payload keys before persisting
  • SetupGuide::complete() gated on access_setting
  • SaveSettings::saveSettings() is now protected, wraps writes in a transaction, batches the locked-check (3N to 1+N queries), and atomically invalidates the default_currency cache

Bug Fixes

  • fix(core): cache resolved value in shopper_setting() to prevent __PHP_Incomplete_Class by @mckenziearts in #520
  • fix(core): cache resolved code in shopper_currency() to prevent __PHP_Incomplete_Class by @mckenziearts in #521
  • fix(core): correct swapped instagram_link/twitter_link display labels by @mckenziearts in #519
  • fix(core): InventoryObserver now demotes rows with is_default = true (guard was a no-op) by @mckenziearts in #519
  • fix(dashboard): cache scalar IDs in RecentOrders/TopSellingProducts to prevent __PHP_Incomplete_Class on refresh by @mckenziearts in #525
  • fix(security): harden onboarding wizard and settings cache by @mckenziearts in #524
  • fix(types): correct Discount.min_required (to DiscountRequirement) and TaxRateRule.reference_id (to string | number) by @mckenziearts in #523

Improvements

  • refactor(onboarding): replace spatie/laravel-livewire-wizard with native Filament Wizard, four components into one by @mckenziearts in #517

New Features

Dependencies

  • stripe/stripe-php ^16.0 to ^19.0
  • filament/filament and media-library plugin ^4.9 to ^4.11
  • laravel/framework add ^13.0
  • blade-ui-kit/blade-heroicons ^2.6 to ^2.7
  • codeat3/blade-phosphor-icons ^2.3 to ^2.4
  • codewithdennis/filament-select-tree ^4.0 to ^4.1
  • bacon/bacon-qr-code ^3.0 to ^3.1
  • danharrin/livewire-rate-limiting ^1.0|^2.0 to ^1.3|^2.2
  • laravelcm/livewire-slide-overs ^2.0 to ^2.1
  • stevebauman/location ^7.2 to ^7.6
  • removed spatie/laravel-livewire-wizard
  • @shopperlabs/shopper-types migrated 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-wizard

The 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.1

No migrations. No config changes.

Full Changelog: v2.8.1...v2.9.0

Don't miss a new shopper release

NewReleases is sending notifications on new releases.