ArtisanPack UI
DocsEcommerceUpgrade guide

Upgrade guide

Ecommerce v1.1.0

This guide lists every breaking change between releases of and what you need to do about each one. Minor and patch releases don't need any action; they're...

This guide lists every breaking change between releases of artisanpack-ui/ecommerce and what you need to do about each one. Minor and patch releases don't need any action; they're listed in CHANGELOG.md.

What counts as a breaking change: a change to a public contract signature (contracts.md), a hook name or its arguments (hooks.md), an event's properties (events.md), a REST/GraphQL request or response shape (api.md), a config key, or a migration that changes an existing column.

1.0.0

First stable release. A fresh install needs nothing from this section.

If you ran a pre-release build (a release/1.0 or dev-* checkout before the 1.0.0 tag), read on. Pre-release builds made no compatibility promise, and several changes landed just before the tag.

Estimated effort: medium for pre-release installs; none for new ones.

High-impact changes

Migrations were edited in place, and every table has the ecommerce_ prefix

Affects: anyone who ran the engine's migrations from a pre-release build.

What changed: The engine's migrations were edited rather than followed by new ones. Every engine table is now prefixed with ecommerce_ (products → ecommerce_products, orders → ecommerce_orders, and so on), and the migration files were renamed to match. The separate add_subject_columns_to_webhook_deliveries_table migration was folded into the create migration. No migration upgrades a pre-release schema.

What to do: Treat a pre-release database as disposable. On a development or staging database, drop the engine's old tables, remove their rows from the migrations table, and run php artisan migrate, or run php artisan migrate:fresh if the database holds nothing else. Re-seed with php artisan ecommerce:seed-demo --fresh if you need sample data. If you have pre-release data you must keep, export it first and import it into the new tables.

Update any raw queries, DB::table() calls, or reporting SQL in your app that used the old table names.

NotificationTemplate takes a locale

Affects: satellites and apps that implement Contracts\NotificationTemplate.

What changed: defaultSubject() and defaultBody() take an optional locale, so templates can ship their default text in more than one language.

What to do:

// before
public function defaultSubject(): ?string;
public function defaultBody(): string;

// after
public function defaultSubject( ?string $locale = null ): ?string;
public function defaultBody( ?string $locale = null ): string;

A null locale means the current app locale. See notifications.md and localization.md.

PaymentGateway gained a method and a parameter

Affects: payment gateway satellites.

What changed: Checkout now resumes the session the shopper confirmed instead of creating a new one, and refunds pass context through to the gateway.

What to do: Implement retrievePaymentSession( string $reference ): PaymentSession, and add the new parameter to refund():

// before
public function refund( Order $order, Money $amount, ?string $reason = null ): RefundResult;

// after
public function refund( Order $order, Money $amount, ?string $reason = null, array $context = [] ): RefundResult;

Gateways whose payment step runs in the browser should also implement RendersClientPayment (see checkout.md).

Medium-impact changes

New config keys

Affects: apps that published config/artisanpack/ecommerce.php before 1.0.0.

What changed: Laravel merges a package's config one level deep. New top-level sections (cart, promotions, store, inventory, schedule, retention) come from the package. A section you already published, such as checkout, replaces the package's whole section, so new keys inside it fall back to the defaults in code until you add them. A published list, such as webhooks.events, replaces the package's list.

What to do: Compare your published file with the package's and copy over what you need. The new keys are:

Key Default
currency.enabled, currency.cookie, currency.session_key ECOMMERCE_CURRENCIES (empty), ecommerce_currency, ecommerce.currency
cart.max_lines, cart.ttl_days, cart.cookie, cart.cookie_lifetime, cart.merge_on_login, cart.abandoned_after_minutes 100, 30, ecommerce_cart, 43,200, true, 60
promotions.verbose_coupon_errors false
checkout.guest_checkout, checkout.account_creation, checkout.reconcile_after_minutes allowed, true, 15
checkout.order_view_url, checkout.order_view_ttl_days unset, 90
checkout.guest_lookup.* 5 failures per order, 20 per IP, 15-minute lockout
fulfillment.allow_unpaid_shipments false
rate_limits.webhook.inbound.per_ip, rate_limits.lookup.attempt, rate_limits.notifications.unsubscribe 120, 30, 30
gateways.stripe.appearance []
fraud.fail_open false
store.country US
api.signature_cache_store, api.catalog_max_age default cache store, 60
webhooks.inbound_max_bytes 524,288
search.provider default
graphql.introspection null (follows the environment)
reviews.require_purchase, reviews.allow_multiple, reviews.max_media false, false, 5
notifications.preferences_url unset
localization.supported_locales en, es, fr, de
inventory.show_quantity false
schedule.enabled, schedule.tasks true, see operations.md
retention.* 90 / 90 / 365 / 365 days

api.middleware and graphql.middleware gained ecommerce.locale. The engine adds it even when your published list doesn't have it, so no change is needed.

Webhook events

Affects: apps with a published config that subscribe to outbound webhooks.

What changed: webhooks.events lists the event classes delivered as webhooks. A published list replaces the engine's, so an old file silently leaves out the new events.

What to do: Add these classes to webhooks.events:

ArtisanPackUI\Ecommerce\Events\CartAbandoned::class,
ArtisanPackUI\Ecommerce\Events\OrderPlaced::class,
ArtisanPackUI\Ecommerce\Events\CartCompleted::class,
ArtisanPackUI\Ecommerce\Events\CouponRedeemed::class,
ArtisanPackUI\Ecommerce\Events\PromotionApplied::class,
ArtisanPackUI\Ecommerce\Events\ShipmentCreated::class,
ArtisanPackUI\Ecommerce\Events\ShipmentDelivered::class,
ArtisanPackUI\Ecommerce\Events\OrderFulfilled::class,
ArtisanPackUI\Ecommerce\Events\CustomerRegistered::class,
ArtisanPackUI\Ecommerce\Events\CustomerUpdated::class,
ArtisanPackUI\Ecommerce\Events\ProductStockLow::class,
ArtisanPackUI\Ecommerce\Events\ProductOutOfStock::class,

See webhooks.md.

One review per customer by default

Affects: stores that accept product reviews.

What changed: A customer can now leave one live review per product. Rejected and spam reviews don't count. A second submission is refused with the reason already-reviewed, and GET products/{product}/reviews/eligibility reports it.

What to do: Nothing, if one review per customer is what you want. To allow more, set reviews.allow_multiple to true (ECOMMERCE_REVIEWS_ALLOW_MULTIPLE). See reviews.md.

Affects: stores with guest checkout.

What changed: Guest order confirmations now carry a signed link to the order (Order.view_url), served by the new GET order-views/{token} endpoint. Unless you set checkout.order_view_url, the link points at that REST endpoint, which returns JSON.

What to do: Set checkout.order_view_url to your storefront's order page, with a {token} placeholder (https://shop.test/order/{token}), and have that page load the order from order-views/{token}. See customers.md.

Database

  • Run php artisan migrate after upgrading, as after every release. When cms-framework is installed, this also syncs the engine's permissions.