Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Cart Laravel Package

wearepixel/laravel-cart

A Laravel shopping cart package for managing cart items, quantities, prices, and totals with flexible storage options. It provides a simple API for adding, updating, and removing items, making it easy to integrate into ecommerce checkout flows.

View on GitHub
Deep Wiki
Context7

Getting Started

v3.0.0 is additive for most apps — if you already have a working cart, nothing breaks unless you instantiate Cart directly or reference CartSession (see Gotchas). New installs should start here:

  1. Install and scaffold — run php artisan cart:install. This publishes the config and creates the app/Cart/ directory structure for your first-class coupon/tax/shipping classes.
  2. Look at config/cart.php first — in particular the driver setting. The default SessionDriver behaves like the old package; DatabaseDriver/RedisDriver are the options to reach for when carts must survive session expiry or be shared across devices.
  3. First use case — the fastest path to something valuable is:
    • Add items as you always have.
    • Generate a coupon with php artisan cart:make:coupon FixedAmountOff, extend the stub, and apply it with Cart::coupon(new FixedAmountOff(...)).
    • Wrap your checkout controller in a feature test using Cart::fake() and assertTotal() — this is the single biggest day-to-day win of the release.

If you're upgrading, run php artisan cart:debug in a local environment to dump the current cart and confirm the driver/config wiring is intact before touching feature code.

Implementation Patterns

Choose your driver deliberately, not by default. Session is fine for guest carts, but the moment you need "cart survives logout" or "cart visible in an admin panel", switch to DatabaseDriver or RedisDriver. MultiDriver is the escape hatch for hybrid setups (e.g. read-through from Redis, fall back to session). Your app code should not care — resolve Cart from the container and inject CartDriver only in tests or health checks.

Wrap domain concepts in first-class objects. Coupon, TaxRule, and ShippingRate are abstract classes that convert to CartCondition. Do the conversion inside the subclass, keep the constructor taking plain scalars/IDs, and never let a subclass hold an Eloquent model you don't intend to serialise. This is the pattern to standardise on — a app/Cart/Coupons/ directory of small typed classes is far easier to test and audit than condition arrays scattered through controllers.

Use applies_to for capped discounts. This is easy to miss and immediately useful: a "20% off your first 3 units" promo is now a condition attribute instead of a manual quantity calculation in your controller. Prefer it over pre-computing totals.

Keep cart mutations in one service layer. Controllers, Livewire components, and Inertia share endpoints should all call the same CartService methods. The new HasCart trait and ShareCartWithInertia helper are presentation adapters — let them read state and call proxies, not own business rules. This keeps your Livewire and Inertia surfaces consistent and makes Cart::fake() tests cover the real path.

Testing pattern (adopt this everywhere).

Cart::fake()
    ->withItems($product, 2)
    ->withCoupon(new TenPercentOff())
    ->withCondition($shipping);

Cart::assertTotal(1980);

Cart::fake() swaps the active driver for an in-memory NullDriver and returns a CartFactory, so tests no longer need a session or database. Seed via the factory, assert via the assertion methods, and prefer assertTotal()/assertConditionApplied() over poking at the cart internals — those assertions are the contract that survives future releases.

Inertia sharing. Wire ShareCartWithInertia once in HandleInertiaRequests::share() so $page.props.cart is available to every page component. Don't duplicate the logic per-controller — otherwise you get drift between pages that show the cart badge and pages that don't.

Gotchas and Tips

  • CartSession is gone. Any type hint, new Cart(...) call, or container binding referencing it will fail. Constructor now takes a CartDriver; if you resolved from the container you're fine, if you hand-rolled new Cart you are not.
  • Config publish tag renamed from config to cart-config. Update deploy scripts and vendor:publish --tag=config invocations in your docs/CI, or the publish silently does nothing and you wonder why config changes aren't taking effect.
  • Redis TTL was wrong (minutes → seconds). If you previously compensated by passing huge TTL values to approximate hours, your carts are now expiring ~60× too fast. Audit any explicit TTL configuration.
  • Conditions are serialised to arrays before storage. This is the one to watch for custom work: a CartCondition (or your Coupon subclass) holding a model instance, closure, or resource will not round-trip cleanly. Keep condition state to scalars and IDs, and re-resolve models at display time.
  • Cart::fake() replaces the active driver for the duration of the test. It's in-memory, so nothing persists between tests — but if you assert on database rows or session contents in the same test you'll be looking at an empty store. Split those concerns.
  • cart:debug only runs outside production by design. Don't build internal support tooling on top of it; it's a local dev convenience.
  • cart:make:* commands validate class names and check write failures — good, but they generate stubs, not finished classes. Read the generated Coupon/TaxRule/ShippingRate before assuming the maths is right; the abstract class only handles condition conversion.
  • PHPStan level 5 with @mixin/@method restored means you can now rely on static analysis against the facade. Add the package to your own PHPStan runs (level 5 is a reasonable floor) rather than excluding it as you may have done previously.
  • Extension point if you need something custom: implement CartDriver and register it with CartManager — that's the supported seam. Avoid subclassing a built-in driver; the serialisation contract is the thing most likely to shift in future majors.
  • Livewire HasCart reactivity assumes the cart is mutated through the trait's proxies. Direct mutations elsewhere (e.g. a queued job, another component) won't trigger a re-render — call $this->refresh() (or your equivalent) after external changes instead of debugging phantom stale totals.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk