Changelog
All the changes made to Larasell open source products.
1.23.0 (2026-11-03)
⚠ BREAKING CHANGES
- upgrade Chronicle to 0.4
- require PHP 8.4
Features
- upgrade Chronicle to 0.4 (1aec70d)
Build System
- require PHP 8.4 (bc8bb56)
Upgrade guide
Larasell uses Chronicle 0.4
Larasell's structured exceptions,
LicenseExceptionandUnknownEntitlement, now implement Chronicle 0.4'sLarasell\Chronicle\Exceptions\StructuredExceptioninstead ofLarasell\Chronicle\StructuredError. Chronicle 0.4 bounds and redacts every event it logs and adds a fake for tests, and Larasell needs it so apps and the admin panel can upgrade too.Who is affected
- Apps that catch Larasell's exceptions as
Larasell\Chronicle\StructuredError. - Apps that use Chronicle themselves, e.g. its
LogRequestsmiddleware or structured exceptions. Composer now installs Chronicle 0.4, so follow Chronicle's upgrade guide.
Apps that catch
LicenseExceptionorUnknownEntitlementby name, or only readerrorCode(),errorWhy(),errorFix()anderrorLink(), are not affected.How to upgrade
Catch the new interface:
1// Before 2use Larasell\Chronicle\StructuredError; 3 4try { 5 $license->activate($key); 6} catch (StructuredError $exception) { 7 report($exception); 8} 9 10// After 11use Larasell\Chronicle\Exceptions\StructuredException; 12 13try { 14 $license->activate($key); 15} catch (StructuredException $exception) { 16 report($exception); 17}Larasell requires PHP 8.4
Larasell now needs PHP 8.4 or newer. Chronicle, the logging package Larasell is built on, requires PHP 8.4 from version 0.3.0, and Larasell's CI already runs on PHP 8.4 only, so PHP 8.3 was untested.
Who is affected
Apps that run on PHP 8.3. Composer won't install this version of Larasell there. Apps on PHP 8.4 or 8.5 are not affected.
How to upgrade
Upgrade PHP to 8.4 or newer on every server and in CI, then raise the PHP requirement in your app's
composer.json:1// Before 2"require": { 3 "php": "^8.3" 4} 5 6// After 7"require": { 8 "php": "^8.4" 9}1.22.0 (2026-11-02)
⚠ BREAKING CHANGES
- products no longer allow backorders unless allow_backorders is set to true.
Features
- add a position to categories to define their order (c51fe51)
- disable backorders by default (b0a7fc8)
Upgrade guide
Products no longer allow backorders by default
larasell_products.allow_backordersnow defaults tofalseinstead oftrue, so a product created withoutallow_backorderscan't be sold beyond its stock. Allowing overselling should be an explicit choice, not an accident.Who is affected
Apps that create products without setting
allow_backordersand rely on them accepting orders when stock runs out. Existing products keep their stored value; only products created after running the migration are affected. Apps that always setallow_backordersexplicitly are not affected.How to upgrade
Run the new migration:
1php artisan migrateThen pass
allow_backorderswherever products should still accept backorders:1use Larasell\Larasell\Models\Product; 2use Larasell\Larasell\Price; 3 4// Before 5Product::create([ 6 'slug' => 'gift-card', 7 'name' => 'Gift card', 8 'price' => Price::of(2500), 9]); 10 11// After 12Product::create([ 13 'slug' => 'gift-card', 14 'name' => 'Gift card', 15 'price' => Price::of(2500), 16 'allow_backorders' => true, 17]);1.21.0 (2026-11-02)
⚠ BREAKING CHANGES
- ProductAttribute::name and ProductAttributeValue::name are Translatable instead of string.
- Locale enum values use hyphens instead of underscores, and Translatable falls back to larasell.locale.default instead of app.fallback_locale. A migration renames stored translation keys.
Features
- make product attribute and value names translatable (#145) (d144986)
- use BCP 47 locale tags and configure supported locales (#144) (a1cf928)
Upgrade guide
Product attribute and value names are now
TranslatableProductAttribute::$nameandProductAttributeValue::$nameare nowLarasell\Larasell\Translatableinstances instead of strings, like product and category names. Variant options such as "Color" and "Red" can now be shown in the visitor's language.Who is affected
Code that reads
nameon aProductAttributeorProductAttributeValueand treats it as a string, for example by printing it, comparing it, or callingpluck('name').ProductVariant::options()andProductVariant::name()keep returning strings, now in the current locale. Code that only uses them is not affected. Writing plain strings keeps working: they are stored for the current locale.How to upgrade
Run the migrations. They turn every existing name into a translation for
larasell.locale.default.1php artisan migrateCall
get()where you need the text:1// Before 2$attribute->name; // 'Color' 3$attribute->values()->pluck('name'); 4 5// After 6$attribute->name->get(); // 'Color', or 'Farbe' when the locale is 'de' 7$attribute->values->map(fn ($value) => $value->name->get());Translate names the same way as product names:
1use Larasell\Larasell\Models\ProductAttribute; 2 3ProductAttribute::create(['slug' => 'color', 'name' => ['en' => 'Color', 'de' => 'Farbe']]);Localevalues are now BCP 47 tags (de-DEinstead ofde_DE)Every value of
Larasell\Larasell\Enums\Localethat has a region or script now uses a hyphen, as inde-DE,zh-Hansandes-419. Translation keys are stored the same way. This is the format HTTP headers, HTMLlangandhreflanguse, so no conversion is needed at the HTTP boundary. Script locales likezh-Hans, whichTranslatableused to reject, now work.Who is affected
- Code that stores, compares or hard-codes
Locale->value, or callsLocale::from()with an underscore value such as'de_DE'. - Code that reads translation JSON (
name,slug,description,product_name) directly from the database, or queries it with paths likeslug->de_DE.
Apps that only use base locales such as
enanddeare not affected: their values did not change.App::setLocale('de_DE')keeps working, andTranslatableaccepts underscore keys and stores them as hyphens.How to upgrade
Run the migration. It renames stored translation keys from
de_DEtode-DEand can be rolled back.1php artisan migrateReplace underscore values in your code, or canonicalize input first:
1use Larasell\Larasell\Enums\Locale; 2 3// Before 4Locale::from('de_DE'); 5$query->where('slug->de_DE', $slug); 6 7// After 8Locale::from('de-DE'); 9Locale::from(Locale::canonicalize('de_DE')); // for input in any case or style 10$query->where('slug->de-DE', $slug);Translations fall back to
larasell.locale.default, notapp.fallback_localeWhen a translation is missing in the requested locale,
Translatable::get()now falls back to the shop's default locale from the newconfig/larasell/locale.php. Plain string values read from the database are stored under that locale too. This gives a shop one setting for its default language, next to the list of locales it supports.Who is affected
Apps that set
app.fallback_localeto something other thanen. Apps whoseapp.fallback_localeisenare not affected, becauselarasell.locale.defaultalso defaults toen.How to upgrade
Publish the config and set the default to your previous
app.fallback_locale. The default must also be insupported.1php artisan vendor:publish --tag=larasell-config1// Before: config/app.php 2'fallback_locale' => 'de', 3 4// After: config/larasell/locale.php 5use Larasell\Larasell\Enums\Locale; 6 7return [ 8 'supported' => [Locale::GERMAN, Locale::ENGLISH], 9 'default' => Locale::GERMAN, 10];1.13.0 (2026-09-10)
Features
- add cart to starter kit (9f63ed5)
- add checkout to starter kit (dd7c46a)
- add compare at price (885fa5b)
- add customers (02b49b0)
- add explicit exceptions for promotions (e37cb57)
- add i18n to starter kit (#82) (58ad661)
- add method to fetch visible variants easily (1fc49e0)
- add optional billing address form (a30e093)
- add order history (8ae2e95)
- add order related mails (6cc37b2)
- add products to cart by id (#90) (f283f57)
- add promotion codes to the storefront (f140ab0)
- add styles to starter kit (#105) (e23acfc)
- add weight and dimension (958fe25)
- display variants on starter kit (69a9620)
- get discounted total for a CartItem (5273f1f)
- make starter kit multi lang (#84) (6bec9d1)
- prefill address when ordering with an account (e1ea5fb)
- show discount for each cart item in the starter kit (bb86a6d)
- show tax and shipping on starter kit (af83c69)
Bug Fixes
- display empty state on cart page (8d36bee)
- load option relations inside ProductVariant::options() (df8e205)
- remove all related stuff from the starter kit (#85) (3170dc7)
- remove multi locale stuff from starter kit (#89) (daea92a)
- rename optionSnapshots to options (00e0eff)
- rename snapshotName to name (807d49d)
1.12.0 (2026-09-03)
Features
- add cart exceptions (#81) (542d5e2)
- add footer to starter kit (#80) (3d08574)
- add menu to starter kit (#79) (9234ed3)
- add product listing page to starter kit (#78) (720e6b4)
- add public id to orders (93ec712)
- add starter kit (#76) (60cb6db)
Bug Fixes
- format prices on order confirmation page on the server (af604fc)
1.4.0 (2026-08-30)
Features
- add discount events (45a8435)
- add priority and exclusivity for promotions (9897892)
- add promotion api (#34) (55d1e7a)
- add promotion effects (#36) (2d16d25)
- add promotion limits (#46) (1c42670)
- add promotions (#33) (d486184)
- add user entered promotion codes (#39) (66f9c95)
- calculate promotions (#37) (7919935)
- snapshot discounts (#38) (f2036f4)
1.3.0 (2026-08-29)
Features
- add expired inventory cleanup command (76aa531)
- add inventory events (2587b56)
- add inventory reservation lifecycle events (3ee7648)
- add optional company details to addresses (#19) (2114346)
- add optional company details to addresses (#22) (18f87af)
- add optional order cancelation reason (1fa86da)
- configure inventory reservation expiration (#26) (0010f53)
- consume inventory reservations on payment (9f4db0b)
- release expired inventory reservations (fd94539)
- release inventory reservations on cancellation (d814741)
- reserve inventory during checkout (b8a2323)
Bug Fixes