Documentation Index
Fetch the complete documentation index at: https://docs.laravelshopper.dev/llms.txt
Use this file to discover all available pages before exploring further.
Customers are users who have the customer role and can place orders in your store. Shopper extends your Laravel User model with e-commerce specific fields and relationships.
User Model Integration
Shopper doesn’t create a separate Customer model. Instead, it extends your existing App\Models\User model with the InteractsWithShopper trait and ShopperUser contract.
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Shopper\Models\Contracts\ShopperUser;
use Shopper\Traits\InteractsWithShopper;
class User extends Authenticatable implements ShopperUser
{
use InteractsWithShopper;
}
The InteractsWithShopper trait provides:
HasRoles (Spatie Permission) for role-based access control
HasDiscounts for customer-specific discount eligibility
HasProfilePhoto for avatar management
Database Schema
User Table Modifications
Shopper modifies the standard Laravel users table:
| Column | Type | Nullable | Default | Description |
|---|
id | bigint | no | auto | Primary key |
first_name | string | yes | null | First name |
last_name | string | no | - | Last name |
email | string | no | - | Email address (unique) |
password | string | yes | null | Password (nullable for social auth) |
email_verified_at | timestamp | yes | null | Email verification date |
gender | string | yes | null | Gender enum value |
phone_number | string | yes | null | Phone number |
birth_date | date | yes | null | Birth date |
avatar_type | string | no | avatar_ui | Avatar source type |
avatar_location | string | yes | null | Avatar file path |
timezone | string | yes | null | User timezone |
opt_in | boolean | no | false | Marketing email consent |
last_login_at | timestamp | yes | null | Last login timestamp |
last_login_ip | string | yes | null | Last login IP address |
Address Table
| Column | Type | Nullable | Default | Description |
|---|
id | bigint | no | auto | Primary key |
first_name | string | no | - | First name |
last_name | string | no | - | Last name |
company_name | string | yes | null | Company name |
street_address | string | no | - | Street address |
street_address_plus | string | yes | null | Additional address line |
postal_code | string | no | - | Postal/ZIP code |
city | string | no | - | City |
state | string | yes | null | State/province/region |
phone_number | string | yes | null | Phone number |
shipping_default | boolean | no | false | Default shipping address |
billing_default | boolean | no | false | Default billing address |
type | string | yes | null | Address type enum |
country_id | bigint | yes | null | FK to countries |
user_id | bigint | no | - | FK to users |
Gender Type
The GenderType enum defines available gender options:
use Shopper\Core\Enum\GenderType;
GenderType::Male // male
GenderType::Female // female
Address Type
The AddressType enum defines address categories:
use Shopper\Core\Enum\AddressType;
AddressType::Billing // billing
AddressType::Shipping // shipping
Relationships
Orders
// Get all customer orders
$customer->orders; // Collection of Order models
// Get recent orders
$customer->orders()
->latest()
->take(5)
->get();
Addresses
// Get all customer addresses
$customer->addresses; // Collection of Address models
// Get default shipping address
$customer->addresses()
->where('shipping_default', true)
->first();
// Get default billing address
$customer->addresses()
->where('billing_default', true)
->first();
Query Scopes
use App\Models\User;
// Get only customers (users with 'user' role)
User::query()->customers()->get();
// Get administrators (admin or manager roles)
User::query()->administrators()->get();
Role Checking
// Check if user is an admin
$user->isAdmin();
// Check if user is a manager
$user->isManager();
// Check if email is verified
$user->isVerified();
Computed Attributes
// Get full name
$customer->full_name; // "John Doe"
// Get formatted birth date
$customer->birth_date_formatted; // "15, January 1990"
// Get roles as comma-separated string
$customer->roles_label; // "User, VIP"
// Get profile picture URL
$customer->picture; // Avatar URL (ui-avatars or uploaded)
Address Model
The model used is Shopper\Core\Models\Address. It implements Shopper\Core\Models\Contracts\Address and is configurable via config/shopper/models.php.
Extending the Address Model
namespace App\Models;
use Shopper\Core\Models\Address as BaseAddress;
class Address extends BaseAddress
{
// Add your customizations here
}
Update config/shopper/models.php:
return [
'address' => \App\Models\Address::class,
];
Address Relationships
Each address belongs to a user and optionally to a country:
$address->user; // The customer who owns this address
$address->country; // The Country model (nullable)
Address Methods
The Address model provides helpers for checking default status:
$address->isShippingDefault(); // true if this is the default shipping address
$address->isBillingDefault(); // true if this is the default billing address
$address->full_name; // "John Doe" (computed from first_name + last_name)
Creating Customers
Basic Customer
use App\Models\User;
use Shopper\Core\Enum\GenderType;
use Illuminate\Support\Facades\Hash;
$customer = User::query()->create([
'first_name' => 'John',
'last_name' => 'Doe',
'email' => 'john@example.com',
'password' => Hash::make('password'),
'gender' => GenderType::Male,
'email_verified_at' => now(),
]);
// Assign customer role
$customer->assignRole(config('shopper.admin.roles.user'));
Customer with Address
use Shopper\Core\Models\Address;
use Shopper\Core\Enum\AddressType;
$customer = User::query()->create([
'first_name' => 'Jane',
'last_name' => 'Doe',
'email' => 'jane@example.com',
'gender' => GenderType::Female,
'phone_number' => '+1234567890',
'opt_in' => true,
]);
$customer->assignRole(config('shopper.admin.roles.user'));
// Add shipping address
$customer->addresses()->create([
'first_name' => 'Jane',
'last_name' => 'Doe',
'street_address' => '123 Main Street',
'city' => 'New York',
'postal_code' => '10001',
'country_id' => $countryId,
'type' => AddressType::Shipping,
'shipping_default' => true,
]);
Retrieving Customers
use App\Models\User;
// Get all customers
$customers = User::query()
->customers()
->latest()
->get();
// Search customers
$customers = User::query()
->customers()
->where(function ($query) use ($search) {
$query->where('first_name', 'like', "%{$search}%")
->orWhere('last_name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%");
})
->get();
// Get customer with addresses and orders
$customer = User::query()
->with(['addresses', 'orders'])
->findOrFail($id);
// Get customers who opted in for marketing
$marketingList = User::query()
->customers()
->where('opt_in', true)
->get();
// Get verified customers only
$verified = User::query()
->customers()
->whereNotNull('email_verified_at')
->get();
Managing Addresses
use Shopper\Core\Models\Address;
// Create address for customer
$address = Address::query()->create([
'user_id' => $customer->id,
'first_name' => 'John',
'last_name' => 'Doe',
'street_address' => '456 Oak Avenue',
'city' => 'Los Angeles',
'postal_code' => '90001',
'country_id' => $countryId,
'type' => AddressType::Billing,
'billing_default' => true,
]);
// Update default address
Address::query()
->where('user_id', $customer->id)
->where('type', AddressType::Shipping)
->update(['shipping_default' => false]);
$newDefault = Address::query()->find($addressId);
$newDefault->update(['shipping_default' => true]);
Observer Behavior
When a user is deleted, the InteractsWithShopper trait automatically:
- Detaches all roles
- Deletes all addresses
// When deleting a user:
$customer->delete();
// Roles are detached and addresses are deleted automatically
Role Configuration
Roles are defined in config/shopper/admin.php:
return [
'roles' => [
'admin' => 'administrator',
'manager' => 'manager',
'user' => 'user',
],
];
Permissions
The admin panel generates five permissions for customer management:
| Permission | Description |
|---|
browse_customers | View the customers list |
read_customers | View a single customer profile |
add_customers | Create new customers |
edit_customers | Edit customer profiles |
delete_customers | Delete or anonymize customers |
Components
To customize the admin UI for customer management:
php artisan shopper:component:publish customer
Creates config/shopper/components/customer.php:
use Shopper\Livewire;
use Shopper\Livewire\Components;
return [
'pages' => [
'customer-index' => Livewire\Pages\Customers\Index::class,
'customer-create' => Livewire\Pages\Customers\Create::class,
'customer-show' => Livewire\Pages\Customers\Show::class,
],
'components' => [
'customers.addresses' => Components\Customers\Addresses::class,
'customers.orders' => Components\Customers\Orders::class,
'customers.profile' => Components\Customers\Profile::class,
],
];
Storefront Example
namespace App\Http\Controllers;
use App\Models\User;
use Shopper\Core\Models\Address;
use Shopper\Core\Enum\GenderType;
use Shopper\Core\Enum\AddressType;
use Illuminate\Support\Facades\Hash;
class AccountController extends Controller
{
public function show()
{
$customer = auth()->user();
return view('account.show', [
'customer' => $customer,
'orders' => $customer->orders()->latest()->paginate(10),
'addresses' => $customer->addresses,
]);
}
public function updateProfile(Request $request)
{
$validated = $request->validate([
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'phone_number' => 'nullable|string|max:20',
'birth_date' => 'nullable|date',
'opt_in' => 'boolean',
]);
auth()->user()->update($validated);
return back()->with('success', 'Profile updated successfully');
}
public function storeAddress(Request $request)
{
$validated = $request->validate([
'first_name' => 'required|string',
'last_name' => 'required|string',
'street_address' => 'required|string',
'city' => 'required|string',
'postal_code' => 'required|string',
'country_id' => 'required|exists:countries,id',
'type' => 'required|in:billing,shipping',
]);
auth()->user()->addresses()->create([
...$validated,
'type' => AddressType::from($validated['type']),
]);
return back()->with('success', 'Address added successfully');
}
}
Use Cases
| Scope | Description |
|---|
customers() | Users with ‘user’ role |
administrators() | Users with ‘admin’ or ‘manager’ role |
| Method | Description |
|---|
isAdmin() | Check if user has admin role |
isManager() | Check if user has manager role |
isVerified() | Check if email is verified |