Shopper dispatches events at key moments in the order, product, and cart lifecycle. These events allow you to hook into the system and add custom behavior like sending notifications, syncing with external services, updating analytics, or triggering workflows without modifying any Shopper code.
Events are organized by domain across two namespaces:
Shopper\Core\Events order and product events
Shopper\Cart\Events cart events
use Shopper\Core\Events\Orders\OrderCompleted;
use Shopper\Core\Events\Orders\OrderPaid;
use Shopper\Core\Events\Products\ProductCreated;
Listening to Events
Register listeners in your application’s EventServiceProvider or use Laravel’s event discovery:
use Shopper\Core\Events\Orders\OrderCompleted;
use Shopper\Core\Events\Orders\OrderPaid;
protected $listen = [
OrderPaid::class => [
GenerateInvoice::class,
SendPaymentConfirmation::class,
],
OrderCompleted::class => [
SendOrderCompletedEmail::class,
],
];
Every event carries the relevant model as a public property, accessible directly in your listener:
use Shopper\Core\Events\Orders\OrderPaid;
class GenerateInvoice
{
public function handle(OrderPaid $event): void
{
$order = $event->order;
$order->load('items', 'customer', 'billingAddress');
Invoice::generate($order);
}
}
Order Events
Order events cover the full lifecycle of a purchase — from creation to completion, cancellation, or archival.
Available Events
| Event | Payload | Trigger |
|---|
OrderCreated | Order $order | Order is inserted in the database |
OrderPaid | Order $order | Admin marks order as paid |
OrderCompleted | Order $order | Admin marks order as completed |
OrderShipped | Order $order | All items reach shipped status |
OrderCancelled | Order $order | Admin cancels the order |
OrderArchived | Order $order | Admin archives the order |
OrderDeleted | Order $order | Order is soft-deleted |
OrderNoteAdded | Order $order | Admin adds a note to the order |
All order events carry a single public Order $order property.
Lifecycle Flow
OrderCreated
│
├── OrderPaid
│ │
│ ├── OrderShipped ──→ OrderCompleted
│ │
│ └── OrderCancelled
│
├── OrderCancelled
│
├── OrderArchived
│
└── OrderDeleted
How They Are Dispatched
OrderCreated and OrderDeleted are dispatched automatically via the model observer. They fire on every insert and soft-delete, regardless of where the operation originates.
use Shopper\Core\Models\Order;
$order = Order::query()->create([...]);
Status-related events (OrderPaid, OrderCompleted, OrderCancelled, OrderArchived) are dispatched from the admin panel when an administrator changes the order status.
OrderShipped is dispatched by SyncOrderShippingStatusAction when the aggregated shipping status of all items transitions to Shipped. This happens automatically after shipment events are recorded — you don’t dispatch it manually.
Queueing
All order events implement ShouldDispatchAfterCommit, meaning listeners run on the queue after the database transaction commits.
| Event | Queued |
|---|
OrderCreated | Yes |
OrderPaid | Yes |
OrderCompleted | Yes |
OrderShipped | Yes |
OrderCancelled | Yes |
OrderArchived | Yes |
OrderDeleted | Yes |
OrderNoteAdded | Yes |
Shipment Events
Shipment events track the creation and delivery of individual packages within an order. A single order can have multiple shipments.
Available Events
| Event | Payload | Trigger |
|---|
OrderShipmentCreated | Order $order, OrderShipping $shipment | A new shipment is created with a shipping label |
OrderShipmentDelivered | Order $order, OrderShipping $shipment | A shipment is marked as delivered |
Both shipment events carry two properties — the order and the specific shipment. This is useful when an order has multiple packages and you need to know which one was created or delivered.
use Shopper\Core\Events\Orders\OrderShipmentDelivered;
class NotifyCustomerOfDelivery
{
public function handle(OrderShipmentDelivered $event): void
{
$order = $event->order;
$shipment = $event->shipment;
$trackingNumber = $shipment->tracking_number;
$deliveredItems = $shipment->items;
}
}
Shipment vs Order Events
Shipment events fire at the package level, order events fire at the order level:
| Scenario | Events fired |
|---|
| First package shipped (2 of 3 items) | OrderShipmentCreated |
| Second package shipped (last item) | OrderShipmentCreated, OrderShipped |
| First package delivered | OrderShipmentDelivered |
| Last package delivered | OrderShipmentDelivered, then OrderCompleted (if order is processing) |
Product Events
Product events are dispatched when products are created, updated, or deleted through the admin panel.
Available Events
| Event | Payload | Trigger |
|---|
ProductCreated | Product $product | Product is created via admin |
ProductUpdated | Product $product | Product is updated via admin |
ProductDeleted | Product $product | Product is deleted via admin |
use Shopper\Core\Events\Products\ProductCreated;
class SyncProductToCatalog
{
public function handle(ProductCreated $event): void
{
$product = $event->product;
ExternalCatalog::push($product);
}
}
All product events implement ShouldDispatchAfterCommit — listeners run on the queue after the database transaction commits.
Example: Order Notification System
Here’s how you might use Shopper events to build a notification flow for your store. Each listener handles a single responsibility.
Register your listeners:
use Shopper\Core\Events\Orders\OrderCreated;
use Shopper\Core\Events\Orders\OrderPaid;
use Shopper\Core\Events\Orders\OrderShipped;
use Shopper\Core\Events\Orders\OrderShipmentDelivered;
protected $listen = [
OrderCreated::class => [
SendOrderConfirmationToCustomer::class,
NotifyWarehouseTeam::class,
],
OrderPaid::class => [
GenerateInvoice::class,
SyncPaymentToAccounting::class,
],
OrderShipped::class => [
SendShippingConfirmation::class,
],
OrderShipmentDelivered::class => [
SendDeliveryConfirmation::class,
RequestProductReview::class,
],
];
A listener that sends a shipping confirmation:
use Shopper\Core\Events\Orders\OrderShipped;
class SendShippingConfirmation implements ShouldQueue
{
public function handle(OrderShipped $event): void
{
$order = $event->order;
$order->load('customer', 'shippings.carrier');
Mail::to($order->customer->email)
->send(new OrderShippedMail($order));
}
}
Cart Events
Cart events are dispatched when a cart reaches a key state during the checkout process.
Available Events
| Event | Payload | Trigger |
|---|
CartCompleted | Cart $cart | Cart is converted to an order |
CouponApplied | Cart $cart, string $code | A coupon code is successfully applied to the cart |
CouponRemoved | Cart $cart, string $code | A coupon code is removed from the cart |
Cart events are in the Shopper\Cart\Events namespace:
use Shopper\Cart\Events\CartCompleted;
use Shopper\Cart\Events\CouponApplied;
use Shopper\Cart\Events\CouponRemoved;
Example: Sending a Cart Recovery Email on Coupon Removal
use Shopper\Cart\Events\CouponRemoved;
class OfferAlternativeCoupon
{
public function handle(CouponRemoved $event): void
{
$cart = $event->cart;
$removedCode = $event->code;
$customer = $cart->customer;
if ($customer) {
Mail::to($customer->email)->send(new AlternativeDiscountMail($cart));
}
}
}
All Events Reference
| Namespace | Event | Payload | Queued |
|---|
Events\Orders | OrderCreated | Order $order | Yes |
Events\Orders | OrderPaid | Order $order | Yes |
Events\Orders | OrderCompleted | Order $order | Yes |
Events\Orders | OrderShipped | Order $order | Yes |
Events\Orders | OrderCancelled | Order $order | Yes |
Events\Orders | OrderArchived | Order $order | Yes |
Events\Orders | OrderDeleted | Order $order | Yes |
Events\Orders | OrderNoteAdded | Order $order | Yes |
Events\Orders | OrderShipmentCreated | Order $order, OrderShipping $shipment | Yes |
Events\Orders | OrderShipmentDelivered | Order $order, OrderShipping $shipment | Yes |
Events\Products | ProductCreated | Product $product | Yes |
Events\Products | ProductUpdated | Product $product | Yes |
Events\Products | ProductDeleted | Product $product | Yes |
Cart\Events | CartCompleted | Cart $cart | No |
Cart\Events | CouponApplied | Cart $cart, string $code | No |
Cart\Events | CouponRemoved | Cart $cart, string $code | No |