tomatophp/filament-ecommerce
Build a full ecommerce store inside FilamentPHP with Tomato CMS Builder. Manage products with variants, images, and multilingual content, plus orders, shipping, coupons, gift cards, referrals, and multi-company branches. Includes order logs, status actions, receipts, exports, and imports.
Install Dependencies Run the core installation command:
composer require tomatophp/filament-ecommerce
Then publish required migrations and configurations:
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations"
php artisan vendor:publish --provider="Spatie\LaravelSettings\LaravelSettingsServiceProvider" --tag="migrations"
php artisan filament-settings-hub:install
php artisan vendor:publish --tag="filament-accounts-model"
Initialize the Plugin Run the final setup command:
php artisan filament-ecommerce:install
Register the Plugin
Add the plugin to your Filament admin panel in app/Providers/Filament/AdminPanelProvider.php:
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
\TomatoPHP\FilamentEcommerce\Plugin::make(),
]);
}
Register an Order Policy (required since v1.1.3)
Order print links are now signed URLs gated by the view ability on TomatoPHP\FilamentEcommerce\Models\Order. Generate a policy (Filament Shield does this for you, or scaffold manually):
php artisan make:policy OrderPolicy --model="TomatoPHP\FilamentEcommerce\Models\Order"
Register it in app/Providers/AuthServiceProvider.php (or Gate::policy(...) in a service provider) and make sure view returns true for the users who should print orders. Without this, printing silently stops working after the upgrade. See the README section "Order Print Page".
First Use Case: Product Creation Navigate to the Products section in the Filament admin panel. Use the built-in CRUD interface to:
Product Management
hasMany relationship for product variants (e.g., size/color combinations) with shared inventory logic.Tomato\CMS\Traits\HasMeta trait.Order Processing
notes relationship, accessible in the Filament order detail view.Order model to include refund logic (e.g., handleRefund() method) and expose it as a Filament action.Order Printing (signed URLs)
Order policy’s view ability. Any custom "Print invoice" button you add should go through the same helper/URL generator rather than a raw route('...') call, otherwise the signature check will fail with a 403.config/filament-ecommerce.php → print:
'print' => [
'enabled' => env('FILAMENT_ECOMMERCE_PRINT_ENABLED', true),
'middleware' => ['web', 'auth'],
'expires' => 60, // minutes the signed URL stays valid
],
URL::temporarySignedRoute(...)) and keep the expiry aligned with the print.expires value so the two flows don’t drift.Customer Management
Inventory Sync
InventoryUpdated) to sync stock levels across platforms (e.g., ERP systems) via Filament’s Notifications.Payment Gateways:
Integrate with Stripe/PayPal by extending the Order model’s payment_method field and adding a custom Filament Resource for transaction logs.
// Example: Add a custom action for capturing payments
public static function getActions(Order $record): array
{
return [
Action::make('Capture Payment')
->action(fn (Order $order) => $order->capturePayment())
->requiresConfirmation(),
];
}
Shipping Providers:
Use Filament’s Forms to configure shipping rules (e.g., weight-based rates) via the ShippingMethod model. Publish a custom settings panel:
php artisan make:filament-settings ShippingSettings
Taxonomy Management:
Extend the built-in Category and Tag models to include custom fields (e.g., SEO slugs) by publishing the resource:
php artisan vendor:publish --tag="filament-ecommerce-resources"
API Extensions: Expose ecommerce data via Laravel Sanctum or Filament’s API Resources. Example:
// app/Http/Controllers/Filament/Ecommerce/ProductController.php
public function apiIndex()
{
return ProductResource::collection(Product::query()->paginate());
}
Reproducible Cart Totals:
Since v1.1.3 cart amounts are always recomputed from the product. Treat any stored cart line amount as a cache, not a source of truth — build reporting/exports off Cart recalculation or off the persisted order snapshot, not off previously written cart values.
Order Printing Breaks After Upgrade (v1.1.3)
view ability on TomatoPHP\FilamentEcommerce\Models\Order. If no policy is registered (or view denies), the print page 403s — this commonly bites right after composer update.OrderPolicy (Filament Shield can generate one) and confirm the ability:
public function view(User $user, Order $order): bool
{
return $user->can('view-order') || $user->id === $order->customer_id;
}
If print.enabled is false, links will not be generated at all — check the config before debugging policies.Expired / Mangled Print URLs
print.expires elapses, or when the app URL or proxy headers change between generation and click (e.g. behind a load balancer). APP_URL mismatches are the usual culprit.APP_URL canonical in every environment, set TrustProxies correctly, and regenerate links rather than storing them. Raise expires for slow back-office workflows; keep it short for customer-facing links.Cart Amounts No Longer Honour Overrides
Media Library Conflicts
Spatie\MediaLibrary migrations fail due to existing tables, manually drop the media table before republishing.--force flag or reset the database:
php artisan migrate:fresh --env=testing
Permission Denied Errors
updateOrderStatus might fail for non-admin users.OrderPolicy in app/Policies/OrderPolicy.php:
public function updateStatus(User $user, Order $order)
{
return $user->can('update-order-status') || $user->isAdmin();
}
Tax/Inventory Calculation Bugs
fresh() or with() clauses in Filament resources:
public static function getRelations(): array
{
return [
RelationManager::make('inventory', Inventory::class)
->query(function (Builder $query) {
return $query->with(['warehouse']);
}),
];
}
Plugin Registration Order
filament-ecommerce:install command may fail if run before filament-settings-hub:install.SettingsHub is registered in config/filament.php.Stale Config After Publishing Print Settings
filament-ecommerce.print appear ignored in production because the config is cached.php artisan config:clear (or config:cache after editing) and re-check the middleware stack — the configured print.middleware runs in addition to the panel’s, so a duplicate auth entry is harmless but a missing signed one is not.Log Filament Events: Enable debug logging for Filament’s plugin system:
// config/filament.php
'debug' => env('FILAMENT_DEBUG', true),
Check logs at storage/logs/laravel.log for plugin initialization errors.
Diagnose Print 403s:
Temporarily log the failure reason (InvalidSignatureException vs. AuthorizationException) — an invalid signature is a URL/APP_URL/expiry problem, an authorization exception is a missing policy or a denied view ability. They look identical in the browser but have completely different fixes.
Resource Overrides: To debug custom resource behavior, override the default Filament resources:
php artisan make:filament-resource Product --override
Then extend the published resource in app/Filament/Resources/ProductResource.php.
Database Seed Issues:
If seeding fails due to missing references (e.g., categories), use Laravel’s seed:run with --class:
php artisan db:seed --class=EcommerceSeeder
Order Policy / Authorization
The Order policy is now a first-class extension point — it governs printing as well as resource access. Implement view, update, and any custom abilities (print, refund) there rather than inside the resource, so signed URLs and Filament actions stay consistent.
Print Configuration Hooks
Control print behaviour per environment via filament-ecommerce.print (enabled, middleware, expires), or override at runtime:
config(['filament-ecommerce.print.expires' => 15]);
Useful for tests that need deterministic URL lifetimes.
Custom Fields
Add fields to models via Filament Forms. Example for Product:
// app/Filament/Resources/ProductResource/Pages/CreateProduct.php
public function form(Form $form): Form
{
return $form
->schema([
// ... existing fields
TextInput::make('custom_field')
->columnSpanFull(),
]);
}
Workflow Hooks Use Laravel Events to intercept actions. Example for order creation:
// app/Providers/EventServiceProvider.php
protected $listen = [
'order.created' => [
\App\Listeners\SendOrderConfirmation::class,
],
];
API Endpoints Extend the built-in API by creating a custom Filament API Resource:
// routes/api.php
Route::middleware('auth:sanctum')->get('/ecommerce/products', [ProductController::class, 'apiIndex']);
Theme Customization Override Filament’s Blade views for ecommerce-specific styling:
php artisan vendor:publish --tag=filament-views
Then modify resources/views/vendor/filament/... to match your store’s branding.
Multi-Warehouse Support
Extend the Inventory model to support multiple warehouses:
// app/Models/Inventory.php
public function warehouse()
{
return $this->belongsTo(Warehouse::class);
}
Update the Filament resource to include warehouse selection:
Select::make('warehouse_id')
->relationship('warehouse', 'name')
->required(),
How can I help you explore Laravel packages today?