Installation
composer require nickdekruijk/shopwire
php artisan vendor:publish --tag=config --provider="NickDeKruijk\Shopwire\ShopwireServiceProvider"
Configure Product Model
Add the ShopwireProduct trait to your Product model:
use NickDeKruijk\Shopwire\Traits\ShopwireProduct;
class Product extends Model { use ShopwireProduct; }
Run Migrations
php artisan migrate
Basic Livewire Integration Create a Livewire component for the cart:
php artisan make:livewire Cart
Use the Shopwire facade or inject the Cart service into your component:
use NickDeKruijk\Shopwire\Facades\Shopwire;
// or
public $cart;
public function mount() { $this->cart = Shopwire::cart(); }
First Use Case: Add to Cart In a Livewire component or controller, add a product to the cart:
Shopwire::cart()->add($product, $quantity = 1);
Cart Management
Shopwire::cart()->add($product, $quantity);
Shopwire::cart()->update($productId, $quantity);
Shopwire::cart()->remove($productId);
Shopwire::cart()->clear();
Checkout Flow
if (Shopwire::cart()->isValid()) {
// Proceed to checkout
}
$paymentIntent = Shopwire::checkout()->process($cartItems, $total);
Livewire Integration
updated() or render() to reflect cart changes in the UI:
public function updatedCart() {
$this->cart = Shopwire::cart()->get();
}
cart-updated):
Shopwire::cart()->add($product);
$this->emit('cart-updated');
Product-Specific Logic
getPrice() in your Product model to apply discounts:
public function getPriceAttribute() {
return $this->base_price - $this->discount;
}
checkStock() method to validate availability:
if (Shopwire::cart()->checkStock()) {
// Proceed
}
Session-Based Cart
By default, the cart persists in the session. For guest users, ensure session drivers (e.g., file, database) are configured in .env:
SESSION_DRIVER=database
Customizing Cart Storage
Extend the Cart class to use a different storage backend (e.g., Redis):
// app/Providers/AppServiceProvider.php
Shopwire::extend(function ($app) {
$app->singleton(\NickDeKruijk\Shopwire\Contracts\Cart::class, function () {
return new \App\Services\RedisCart();
});
});
Localization
Use the setLocale() method to support multi-language pricing/currency:
Shopwire::cart()->setLocale('en_US');
Testing
Mock the Cart service in tests:
$this->app->instance(\NickDeKruijk\Shopwire\Contracts\Cart::class, MockCart::class);
Model Configuration
Class 'App\Models\Product' does not use ShopwireProduct trait.
Fix: Ensure the trait is added to your Product model before running migrations. The package creates a shopwire_products table that expects the trait’s methods.Session Cart Persistence
SESSION_DRIVER is set to database or redis in .env. For API-based carts, use a cookie-based solution or database-backed storage.Livewire Event Conflicts
Shopwire::cart()->add($product);
$this->emit('cart-updated');
Ensure your Livewire component listens to this event:
protected $listeners = ['cart-updated' => 'render'];
Quantity Validation
public function addToCart($product, $quantity = 1) {
$maxQuantity = $product->stock;
$quantity = max(1, min($quantity, $maxQuantity));
Shopwire::cart()->add($product, $quantity);
}
Migration Conflicts
Table 'shopwire_products' already exists.
Fix: If you’ve modified the shopwire_products table manually, reset it:
php artisan migrate:fresh --env=testing
Or manually drop the table before re-running migrations.Log Cart State Dump the cart contents for debugging:
\Log::info('Cart contents:', ['items' => Shopwire::cart()->get()->items]);
Check Config Values
Validate the config/shopwire.php file for custom model/class names:
'model' => App\Models\Product::class,
'currency' => 'USD',
Livewire Wire:ignore
If cart items flicker during updates, add wire:ignore to the cart container in Blade:
<div wire:ignore>
@foreach (Shopwire::cart()->get()->items as $item)
{{ $item->name }} - {{ $item->quantity }}
@endforeach
</div>
Custom Cart Rules
Extend the Cart class to add business logic (e.g., bulk discounts):
// app/Services/CustomCart.php
namespace App\Services;
use NickDeKruijk\Shopwire\Cart as BaseCart;
class CustomCart extends BaseCart {
public function applyBulkDiscount() {
if ($this->total() > 1000) {
$this->setDiscount(100);
}
}
}
Bind it in AppServiceProvider:
Shopwire::extend(function ($app) {
$app->singleton(\NickDeKruijk\Shopwire\Contracts\Cart::class, function () {
return new \App\Services\CustomCart();
});
});
Override Checkout Logic Replace the default checkout handler:
Shopwire::extendCheckout(function ($app) {
return new \App\Services\CustomCheckout();
});
Add Custom Fields to Cart Items
Extend the ShopwireProduct trait to include additional attributes:
// app/Models/Product.php
use NickDeKruijk\Shopwire\Traits\ShopwireProduct;
class Product extends Model {
use ShopwireProduct;
public function getCustomAttribute() {
return $this->attributes['custom_field'];
}
}
Update the shopwire_products table migration to include custom_field.
Webhook Integration
Listen for cart events (e.g., cart.item.added) via Livewire or Laravel events:
// app/Providers/EventServiceProvider.php
protected $listen = [
\NickDeKruijk\Shopwire\Events\ItemAdded::class => [
\App\Listeners\LogCartActivity::class,
],
];
How can I help you explore Laravel packages today?