Looking to hire Laravel developers? Try LaraJobs

laravel-cart maintained by centrex

Description
Shopping cart for Laravel with session, cookie, and database storage, Livewire components, and REST API
Author
Last update
2026/04/18 14:21 (dev-main)
License
Downloads
0

Comments
comments powered by Disqus

Laravel Cart

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

A full-featured shopping cart for Laravel. Supports session, cookie, and database storage drivers, multiple named cart instances (e.g. wishlist), Livewire components (CartIcon, CartDrawer), and a REST API — all swappable via a single config key.

Installation

composer require centrex/laravel-cart
php artisan vendor:publish --tag="laravel-cart-config"

For the database driver, run:

php artisan vendor:publish --tag="laravel-cart-migrations"
php artisan migrate

Configuration

php artisan vendor:publish --tag="laravel-cart-config"
// config/laravel-cart.php
'driver'          => env('CART_DRIVER', 'session'),   // session | cookie | database
'default_instance'=> 'default',
'tax'             => env('CART_TAX', 0),              // integer percent, e.g. 15
'cookie_lifetime' => env('CART_COOKIE_LIFETIME', 43200),  // minutes (default 30 days)
'database' => [
    'connection' => env('CART_DB_CONNECTION'),
    'table'      => 'carts',
],

Drivers

Driver Persists across requests Auth-aware Best for
session Until session expires No Default, server-rendered apps
cookie 30 days (configurable) No Guest carts, headless/SPA
database Permanently (until cleared) Yes — uses user ID for auth, session ID for guests Authenticated users, cart recovery

Usage

Facade

use Centrex\Cart\Facades\Cart;

// Add item (merges qty if same rowId already exists)
$item = Cart::add(
    id:      $product->id,
    name:    $product->name,
    qty:     2,
    price:   $product->price,
    options: ['color' => 'red', 'size' => 'M'],
);

echo $item->rowId;    // md5 hash of id + sorted options
echo $item->subtotal; // qty × price

// Update quantity
Cart::update($item->rowId, 5);

// Remove item
Cart::remove($item->rowId);

// Clear everything
Cart::clear();

Reading the cart

// All items — Collection<string, CartItem>
Cart::content();

// Single item (throws CartItemNotFoundException if missing)
Cart::get($rowId);

// Aggregates
Cart::count();      // total units (sum of all qty)
Cart::lines();      // number of distinct line items
Cart::subtotal();   // sum of all item subtotals
Cart::tax();        // subtotal × (tax% / 100)
Cart::total();      // subtotal + tax
Cart::isEmpty();

CartItem properties

$item->rowId;    // string — md5(id + sorted options)
$item->id;       // string|int — your product ID
$item->name;     // string
$item->qty;      // int
$item->price;    // float — unit price
$item->options;  // array — ['color' => 'red', 'size' => 'M']
$item->subtotal; // float — qty × price
$item->toArray();

Multiple cart instances

Use instance() to work with independent named carts. Returns a new Cart object — does not mutate the original singleton.

// Default cart
Cart::add(1, 'Widget', 1, 29.99);

// Wishlist cart
$wishlist = Cart::instance('wishlist');
$wishlist->add(2, 'Gadget', 1, 99.00);

Cart::count();              // 1 (default)
$wishlist->count();         // 1 (wishlist)

Events

Listen to cart events in your application's EventServiceProvider:

use Centrex\Cart\Events\CartItemAdded;
use Centrex\Cart\Events\CartItemUpdated;
use Centrex\Cart\Events\CartItemRemoved;
use Centrex\Cart\Events\CartCleared;

Event::listen(CartItemAdded::class, function (CartItemAdded $event) {
    // $event->item     — CartItem
    // $event->instance — 'default'
});

Cookie storage — guest carts

CART_DRIVER=cookie
CART_COOKIE_LIFETIME=43200  # 30 days in minutes

Note: Cookie writes are queued for the HTTP response. A get() call in the same request reads what the browser already sent, not what was queued. This is standard browser behaviour.

Database storage — persistent & auth-aware

CART_DRIVER=database
  • Guests are identified by session()->getId().
  • Authenticated users are identified by auth()->id().
  • Cart rows are keyed on (instance, identifier) — unique index.

To migrate a guest cart to a user after login:

// In your LoginController / AuthenticatedSessionController
use Centrex\Cart\Models\StoredCart;

StoredCart::where('identifier', session()->getId())
    ->update(['identifier' => (string) auth()->id()]);

Livewire Components

Requires livewire/livewire ^3.

CartIcon

Displays a shopping bag icon with an item count badge. Updates automatically when the cart changes.

{{-- In your navbar / header --}}
<livewire:cart-icon />

Clicking the icon dispatches the open-cart browser event, which opens CartDrawer.

CartDrawer

A slide-out panel showing the full cart with quantity controls, item removal, and totals.

{{-- Once, anywhere in your layout (e.g. before </body>) --}}
<livewire:cart-drawer />

Open the drawer from any element:

{{-- Alpine.js dispatch --}}
<button @click="$dispatch('open-cart')">View Cart</button>

{{-- Or from a Livewire component --}}
$this->dispatch('open-cart');

Triggering a cart update from your own Livewire components

After adding an item to the cart in a Livewire component, dispatch cart-updated so CartIcon and CartDrawer refresh automatically:

// In your ProductCard or similar Livewire component
public function addToCart(int $productId): void
{
    $product = Product::findOrFail($productId);

    Cart::add($product->id, $product->name, 1, $product->price);

    $this->dispatch('cart-updated');   // refreshes CartIcon badge + CartDrawer
    $this->dispatch('open-cart');      // optionally open the drawer
}

Publish views for customisation

php artisan vendor:publish --tag="laravel-cart-views"
# → resources/views/vendor/laravel-cart/livewire/cart-icon.blade.php
# → resources/views/vendor/laravel-cart/livewire/cart-drawer.blade.php

REST API

All endpoints are prefixed with api (configurable via api_prefix) and use the api middleware (configurable via api_middleware).

Method Endpoint Description
GET /api/cart Get full cart (items, count, subtotal, tax, total)
POST /api/cart/items Add item to cart
PUT /api/cart/items/{rowId} Update item quantity
DELETE /api/cart/items/{rowId} Remove item
DELETE /api/cart Clear cart

GET /api/cart

{
  "data": {
    "instance": "default",
    "items": [
      {
        "row_id": "b8b0b1b2...",
        "id": 1,
        "name": "Widget",
        "qty": 2,
        "price": 29.99,
        "subtotal": 59.98,
        "options": { "color": "red" }
      }
    ],
    "count": 2,
    "lines": 1,
    "subtotal": 59.98,
    "tax": 0.0,
    "total": 59.98
  }
}

POST /api/cart/items

{
  "id": 1,
  "name": "Widget",
  "qty": 2,
  "price": 29.99,
  "options": { "color": "red", "size": "M" }
}

PUT /api/cart/items/{rowId}

{ "qty": 5 }

DELETE /api/cart/items/{rowId}

Returns 204 No Content.

DELETE /api/cart

Returns 204 No Content.


Testing

composer test        # full suite
composer test:unit   # pest only
composer test:types  # phpstan
composer lint        # pint

Changelog

Please see CHANGELOG for more information on what has changed recently.

Credits

License

The MIT License (MIT). Please see License File for more information.