Build an E-Commerce System in Seconds With TomatoPHP
- Published on
- Reading time
- 10 min read
Step by step, turn a fresh Laravel app into a full store with TomatoPHP: admin, roles, CRM, wallets, CMS, themes and a ready storefront.
Hi, community.
TomatoPHP is a cutting-edge, open-source set of Laravel packages built to streamline development in the VILT stack. The ecosystem uses Splade to generate modern, high-performance single-page applications (SPAs) from nothing but Blade files, and it makes the development experience both efficient and enjoyable.
We keep growing the ecosystem by adding features to our plugins, and we have now built a complete e-commerce system out of them. In this article I will walk you through the whole implementation, step by step, so you can drop a robust e-commerce system into your own Laravel application.
By the end you will have:
- An admin dashboard with role management
- A CRM for your customers, with its own authentication guard
- Customer wallets and payments
- A CMS and a theme system for the storefront
- Products, orders, offers and branches, with a ready-made e-commerce theme on top
Note: this guide was written in early 2024 for the Laravel 10 era of TomatoPHP. Newer Laravel versions changed some of the files mentioned below (for example RouteServiceProvider.php and the Authenticate middleware), so adapt those steps if you are on a newer release.
Install Tomato Admin
Everything starts from the tomato-admin plugin, installed on a fresh Laravel app.
- Create a new Laravel app:
composer create-project laravel/laravel tomato
If you don't have an environment for Laravel yet, you can use this doc to build one on your Ubuntu Linux.
cdinto your project folder, set your database credentials in.env, and make sure the app is running and the database is connected. The easiest way to check is to run the migrations:
php artisan migrate
- Install tomato-admin:
composer require tomatophp/tomato-admin
- When Composer is done, run the auto-installer:
php artisan tomato-admin:install
- If you are on macOS the installer can install the Yarn packages for you automatically. If not, just build your assets like this:
yarn && yarn build
Note: the original command read yarn & yarn build; a single & sends yarn to the background, so && is used here and throughout this guide.
Now tomato-admin is installed on your Laravel project.
Publish the Media Library migrations
Our packages use media, so we need to publish the Spatie Media Library migrations:
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations"
If that command does not work, run the interactive version instead:

php artisan vendor:publish
Then type media in the search and select the migrations entry. After that, migrate:
php artisan migrate
Check your browser now and you will see a homepage like this:

Finally, change the HOME const in RouteServiceProvider.php to /admin, so users are redirected to the admin panel after they authenticate.
Install Tomato Roles
No e-commerce system is complete without solid role management, so the next package is tomato-roles.
- Require the package:
composer require tomatophp/tomato-roles
- When Composer is done, run the installer:
php artisan tomato-roles:install
- Open
app\Models\User.phpand add this trait to it:
use \Spatie\Permission\Traits\HasRoles;
Your dashboard is now ready. Log in at /admin/login with [email protected] and password as the password.

If you try to open any page and get redirected to
Two-factor Confirmation, and you don't need it for now, you can turn it off by removingimplements MustVerifyEmailfrom yourUser.phpmodel.
Install Tomato CRM
An e-commerce system has to manage customer interactions, customer authentication and other key actions. tomato-crm handles all of that.
- Require and install the package:
composer require tomatophp/tomato-crm
php artisan tomato-crm:install
- Publish the
Accounts.phpmodel into your app so you can customize it:
php artisan vendor:publish --tag="tomato-crm-model"
- Publish the tomato-crm config:
php artisan vendor:publish --tag="tomato-crm-config"
- In the
tomato-crm.phpconfig, point the model to your app's copy:
"model" => \App\Models\Account::class,
Add an accounts guard
Customers log in separately from admins, so we need a new guard. Add it to config/auth.php like this:
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'accounts' => [
'driver' => 'session',
'provider' => 'accounts',
]
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'accounts' => [
'driver' => 'eloquent',
'model' => App\Models\Account::class,
],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expiry time is the number of minutes that each reset token will be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
| The throttle setting is the number of seconds a user must wait before
| generating more password reset tokens. This prevents the user from
| quickly generating a very large amount of password reset tokens.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_reset_tokens',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];
Then clear the config cache and rebuild your assets:
php artisan config:clear
yarn && yarn build
Your CRM is ready. You can check it on your dashboard.
Install Tomato Wallet
To handle transactions between customers and vendors you need a solid payment handler. tomato-wallet manages customer wallets and handles payments too, and it ships with many integrated payment gateways.
- Require and install it:
composer require tomatophp/tomato-wallet
php artisan tomato-wallet:install
- Make your
Account.phpmodel implement theWalletinterface and use theHasWallettrait, so customer wallets work. Your Account model should look like this:
<?php
namespace App\Models;
use Bavix\Wallet\Interfaces\Wallet;
use Bavix\Wallet\Traits\HasWallet;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Macroable\Macroable;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\Permission\Traits\HasRoles;
use TomatoPHP\TomatoCrm\Models\Group;
/**
* @property integer $id
* @property string $name
* @property string $username
* @property string $loginBy
* @property string $address
* @property string $type
* @property string $password
* @property string $otp_code
* @property string $otp_activated_at
* @property string $last_login
* @property string $agent
* @property string $host
* @property integer $attempts
* @property boolean $login
* @property boolean $activated
* @property boolean $blocked
* @property string $deleted_at
* @property string $created_at
* @property string $updated_at
* @property AccountsMeta[] $accountsMetas
* @property Activity[] $activities
* @property Comment[] $comments
* @property Model meta($key, $value)
* @property Location[] $locations
*/
class Account extends Authenticatable implements HasMedia, Wallet
{
use InteractsWithMedia;
use HasApiTokens, HasFactory, Notifiable;
use HasWallet;
/**
* @var array
*/
protected $fillable = [
'email',
'phone',
'parent_id',
'type',
'name',
'username',
'loginBy',
'address',
'password',
'otp_code',
'otp_activated_at',
'last_login',
'agent',
'host',
'is_login',
'is_active',
'deleted_at',
'created_at',
'updated_at'
];
protected $casts = [
'is_login' => 'boolean',
'is_active' => 'boolean'
];
protected $dates = [
'deleted_at',
'created_at',
'updated_at',
'otp_activated_at',
'last_login',
];
protected $appends = [
'birthday',
'gender',
'more'
];
public function getMoreAttribute()
{
$metas = $this->accountsMetas()->get()->pluck('value', 'key')->toArray();
return $metas;
}
public function getBirthdayAttribute()
{
return $this->meta('birthday') ?: null;
}
public function getGenderAttribute()
{
return $this->meta('gender') ?: null;
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function accountsMetas()
{
return $this->hasMany('TomatoPHP\TomatoCrm\Models\AccountsMeta');
}
/**
* @param string $key
* @param string|null $value
* @return Model|string
*/
public function meta(string $key, string|null $value=null): Model|string|null
{
if($value){
return $this->accountsMetas()->updateOrCreate(['key' => $key], ['value' => $value]);
}
else {
return $this->accountsMetas()->where('key', $key)->first()?->value;
}
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function activities()
{
return $this->hasMany('TomatoPHP\TomatoCrm\Models\Activity');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function comments()
{
return $this->hasMany('TomatoPHP\TomatoCrm\Models\Comment');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function locations()
{
return $this->hasMany('TomatoPHP\TomatoCrm\Models\Location');
}
public function groups(){
return $this->belongsToMany(Group::class, 'account_groups', 'account_id', 'group_id');
}
}
Your wallet is now working. You can start any transaction and check the customer's balance.
Install Tomato CMS
Every working store needs a well-optimized front end. To improve SEO and add content such as posts and pages, we use tomato-cms:
composer require tomatophp/tomato-cms
php artisan tomato-cms:install
Install Tomato Themes
The storefront itself is built as a theme with tomato-themes. It makes multi-theme projects simple and uses a Hierarchical Model-View-Controller (HMVC) architecture.
- Require and install the package, then rebuild your assets:
composer require tomatophp/tomato-themes
php artisan tomato-themes:install
yarn && yarn build
- Make sure there is a
Themesfolder in your project root, and add theThemesnamespace to the autoload section of yourcomposer.json:
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/",
"Themes\\": "Themes/"
}
},
- Reload Composer's autoloader:
composer dump-autoload
- Add the theme views to the
contentarray in yourtailwind.config.js, so Tailwind picks up their classes:
content: [
...
"./Themes/**/*.blade.php",
"./Themes/**/**/*.blade.php",
],
Your theme system is ready: you can upload a theme or create a new one.
Install Tomato E-Commerce
With the foundations in place (CRM, role management and the supporting packages), it's time to bring them together with the e-commerce system itself.
- Require and install it:
composer require tomatophp/tomato-ecommerce
php artisan tomato-ecommerce:install
This package installs tomato-products, tomato-orders, tomato-offers and tomato-branches for you.
- To make everything work, install tomato-branches:
php artisan tomato-branches:install
-
Create at least one
Shipping Vendorfrom/admin/shipping-vendors. -
Go to
/admin/settings/seo, upload your logos and change the site name and SEO data.
Install the e-commerce theme
Now let's make the store and the CMS look good. Our theme has a simple, stylish design that is an ideal starting point for customization.
- Go into your
Themesfolder:
cd Themes
- Clone our theme:
git clone [email protected]:tomatophp/Ecommerce.git
- Open
/themesin your dashboard. The new theme is listed there, and you just activate it.
Please note that your main
routes/web.phpmust not define a/route, because it can override the theme routes.
- Rebuild your assets to fix the styles:
yarn && yarn build
Check your home page now and you will get something like this:

You can pick any section from the dropdown at the top and add it to your page.
Build the menus
Build your menus from /admin/menus using these endpoints:
- Home
/ - About
/about - Shop
/shop - Blog
/blog - Contact
/contact - Terms & Conditions
/terms - Privacy
/privacy
You can create two menus, main and footer. The main menu shows up in your header automatically, and the footer menu in your footer.
Redirect guests to the customer login
Change the Authenticate middleware so unauthenticated visitors are redirected to the accounts login route:
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*/
protected function redirectTo(Request $request): ?string
{
return $request->expectsJson() ? null : route('accounts.login');
}
}
Add the e-commerce traits to Account
Finally, add these traits to your Account.php model:
use \TomatoPHP\TomatoEcommerce\Services\Traits\InteractsWithEcommerce;
use \TomatoPHP\TomatoNotifications\Traits\InteractWithNotifications;
use \TomatoPHP\TomatoOrders\Services\Traits\InteractsWithOrders;
Wrapping up
With the full e-commerce system installed, you can start managing your catalog: add products, define categories to shape your offering, and create orders. The system is ready to handle transactions and run your online business.
Thanks for using Tomato Plugins and the TomatoPHP framework.
- Join the support server on Discord
- Read the docs
- If you like any repo, please give it a star on TomatoPHP GitHub
- Sponsor us on GitHub Sponsors