PHPackages                             toadfix/minishop - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. toadfix/minishop

ActiveLibrary[Admin Panels](/categories/admin)

toadfix/minishop
================

Drop-in ecommerce package for Laravel with Filament v5 admin panel and Sanctum API

v1.0.1(2mo ago)13MITPHP ^8.2

Since May 24Compare

[ Source](https://github.com/toadfix/minishop)[ Packagist](https://packagist.org/packages/toadfix/minishop)[ RSS](/packages/toadfix-minishop/feed)WikiDiscussions Synced 3w ago

READMEChangelogDependencies (11)Versions (27)Used By (0)

Minishop
========

[](#minishop)

A drop-in ecommerce package for Laravel 13 applications. Ships with a Filament v5 admin panel, a Livewire storefront, Stripe payments, a Sanctum REST API, and Canadian tax/shipping support.

---

Requirements
------------

[](#requirements)

- PHP 8.3+
- Laravel 13
- Filament 5

Installation
------------

[](#installation)

```
composer require toadfix/minishop
```

Then run the install command:

```
php artisan minishop:install
```

This will:

1. Publish the config file to `config/minishop.php`
2. Publish and run the migrations (re-running the installer is safe — already-published migrations are skipped)
3. Point `AUTH_MODEL` in your `.env` at `Minishop\Models\User` (the model carries the roles, Sanctum and Fortify traits the package needs)
4. Seed the required roles and permissions
5. Optionally create an initial admin user with the `super-admin` role (pass `--no-admin` to skip)

The admin panel is available at `/dashboard` and authenticates with Filament's built-in login.

### Local package development

[](#local-package-development)

If you are working on the package itself, `scripts/fresh-host.sh` scaffolds a throwaway Laravel host app as a sibling directory, wires the package in via a Composer path repository (symlinked, so edits are live) and runs the installer:

```
scripts/fresh-host.sh            # creates ../minishop-app
scripts/fresh-host.sh ../sandbox # or a directory of your choosing
```

### Livewire storefront (optional)

[](#livewire-storefront-optional)

The package ships a complete Livewire + Blade storefront (home, products, cart, checkout, and customer account). Publish it and enable the routes:

```
php artisan minishop:install --storefront
```

Add to your `.env`:

```
MINISHOP_STOREFRONT=true
```

The storefront is styled with Tailwind v4. Build the assets with your app's Vite setup:

```
npm install
npm run build
```

`minishop:install --storefront` publishes:

- `resources/views/storefront/` — the page views (override any of them freely).
- `resources/css/storefront.css` — the Tailwind entrypoint. Add it to your `vite.config.js` inputs (alongside your existing CSS) and reference it with `@vite(['resources/css/storefront.css'])` — the shipped layout already does.

Until the assets are built, the layout falls back to the Tailwind Play CDN so the storefront is usable out of the box.

**Email verification.** Customer accounts must confirm their email before reaching the `/account` area — registration sends a verification link (via Fortify's email-verification feature, enabled by default) and the package ships the storefront notice page, so make sure your app has a working mail driver. The admin user created by `minishop:install` is marked verified automatically.

> **Upgrading:** publishing copies the storefront views into your app, and your copies take precedence over the package's. After upgrading the package, the shipped views may have changed — re-publish to pick up the new versions:
>
> ```
> php artisan vendor:publish --tag=minishop-storefront --force
> ```
>
>
>
> `--force` overwrites the published views, so re-apply any local edits afterwards (or diff before publishing). If you haven't customised the views, deleting `resources/views/storefront/` and re-publishing is the cleanest path.

---

Configuration
-------------

[](#configuration)

The published config file is at `config/minishop.php`. Key options:

KeyEnv variableDefaultDescription`load_storefront_routes``MINISHOP_STOREFRONT``false`Enable the built-in storefront routes`renderer``MINISHOP_RENDERER``blade`Storefront renderer: `blade` (Livewire) or a custom FQCN`default_payment_gateway``MINISHOP_DEFAULT_GATEWAY``stripe`Default payment driver`panel_path``MINISHOP_PANEL_PATH``dashboard`URL path for the Filament admin panel`image_disk``MINISHOP_IMAGE_DISK``public`Filesystem disk for product images`low_stock_notification_email``MINISHOP_LOW_STOCK_EMAIL`—Email address for low-stock alerts`analytics.ga4_measurement_id``MINISHOP_GA4_ID`—Google Analytics 4 Measurement ID (e.g. `G-XXXXXXX`)### Analytics

[](#analytics)

Set `MINISHOP_GA4_ID` to your Google Analytics 4 Measurement ID and the storefront injects `gtag.js` on every page and fires a GA4 **`purchase`** event on the order-confirmation page (with `transaction_id`, `value`, `currency`, `shipping`, `tax`, and line `items`). Leave it unset to disable tracking entirely. The snippets live in publishable Blade partials (`resources/views/vendor/minishop/analytics/*`) if you need to customise them or add another provider.

### Product search

[](#product-search)

Product search (storefront, Livewire list, and the REST API) runs through [Laravel Scout](https://laravel.com/docs/scout). It defaults to Scout's portable **`database`** engine — no external service required, works on SQLite/MySQL/ Postgres, and matches across product name, description, and SKU. To scale up, set `SCOUT_DRIVER` (e.g. `meilisearch` or `algolia`) and configure that engine; `Minishop\Models\Product` is already `Searchable`. Facet filters (category, tag, price range, stock) are applied on top of the search results.

---

Environment Variables
---------------------

[](#environment-variables)

Add these to your `.env` as needed:

```
# Storefront
MINISHOP_STOREFRONT=true
MINISHOP_RENDERER=blade

# Stripe
STRIPE_KEY=pk_live_...
STRIPE_SECRET=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...

# Canada Post (optional)
CANADA_POST_USERNAME=
CANADA_POST_PASSWORD=
CANADA_POST_CUSTOMER_NUMBER=

# Notifications
MINISHOP_LOW_STOCK_EMAIL=store@example.com
```

---

Admin Panel
-----------

[](#admin-panel)

The Filament admin panel is available at `/dashboard` (or the path configured in `MINISHOP_PANEL_PATH`).

**Available panels:**

- Dashboard — analytics widgets: revenue (this month + 30-day chart, gated to admins), orders this month, new customers, a needs-attention counter, orders-by-status, latest orders, and low-stock products
- Products — full CRUD with options, variants, and images (managed inline as relation managers); bulk delete
- Categories &amp; Tags — full CRUD
- Orders — lifecycle management, bulk status updates, and downloadable invoice PDFs (also emailed to the customer on confirmation)
- Customers — profiles and order history
- Coupons — percentage and fixed discounts with expiry and usage limits
- Shipping Methods — flat-rate and carrier-calculated methods
- Tax Zones — zone-based tax rates
- Returns — approve/reject/receive/refund workflow
- Users — admin user management with roles
- Settings — currency &amp; locale, tax rate/mode, GST number, active payment gateway, inventory and promotion options
- Activity Log — admin action history

**Roles included:**

- `super-admin` — full access (bypasses all permission checks)
- `admin` — full management of every resource, including users
- `manager` — products and orders (no deletes), returns processing, and read access to categories/customers/tax zones/tags; no user, coupon, shipping, or settings management
- `customer` — assigned automatically on storefront registration; no admin access

---

Storefront Routes
-----------------

[](#storefront-routes)

When `MINISHOP_STOREFRONT=true`, the following routes are registered:

MethodURINameGET`/``storefront.home`GET`/products``storefront.products.index`GET`/products/{product}``storefront.products.show`GET`/cart``storefront.cart.show`GET`/checkout``storefront.checkout.create`POST`/checkout``storefront.checkout.store`GET`/order-confirmation/{order}``storefront.order.confirmation`GET`/checkout/pay/{order}``storefront.checkout.payment.show`POST`/checkout/pay/{order}/stripe``storefront.checkout.payment.stripe`POST`/webhooks/stripe``webhooks.stripe`POST`/webhooks/{gateway}``webhooks.gateway`The cart is also driven by JSON sub-routes (`storefront.cart.items.store`, `.items.update`, `.items.destroy`, `.clear`, `.sync`) used by the Livewire components.

Account routes (require authentication):

MethodURINameGET`/account``account.dashboard`GET`/account/orders``account.orders.index`GET`/account/orders/{order}``account.orders.show`GET`/account/address``account.address.edit`PUT`/account/address``account.address.update`GET`/account/payment``account.payment.index`---

REST API
--------

[](#rest-api)

The Sanctum API is available at `/api/v1/`. Catalog and cart endpoints are public; orders and the authenticated-user endpoint require a bearer token.

**Authentication:**

```
POST /api/v1/auth/register
POST /api/v1/auth/login
POST /api/v1/auth/logout
GET  /api/v1/user
```

**Catalog (public):**

```
GET /api/v1/products
GET /api/v1/products/{product}
GET /api/v1/categories
GET /api/v1/categories/{category}
POST /api/v1/coupons/validate
```

Product responses include each image's resolved `url` (and raw `path`).

**Cart:**

```
GET    /api/v1/cart
POST   /api/v1/cart/items
PATCH  /api/v1/cart/items/{cartItem}
DELETE /api/v1/cart/items/{cartItem}
```

**Orders (require a bearer token):**

```
GET /api/v1/orders
GET /api/v1/orders/{order}
```

**Example — register and fetch orders:**

```
# Register
curl -X POST http://your-app.test/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{"name":"Jane","email":"jane@example.com","password":"secret","password_confirmation":"secret"}'

# Fetch orders (use the token from the register response)
curl http://your-app.test/api/v1/orders \
  -H "Authorization: Bearer YOUR_TOKEN"
```

---

Payment Gateways
----------------

[](#payment-gateways)

Minishop uses a driver-based payment system. The built-in drivers are `stripe` and `cod` (cash on delivery / no payment step).

### Stripe setup

[](#stripe-setup)

1. Add your Stripe keys to `.env` (see Environment Variables above).
2. Set `MINISHOP_DEFAULT_GATEWAY=stripe` or select Stripe in the admin Settings panel.
3. Configure the webhook in the [Stripe Dashboard](https://dashboard.stripe.com/webhooks) to point at `https://your-app.test/webhooks/stripe` with the `payment_intent.succeeded` event.

### Adding a custom gateway

[](#adding-a-custom-gateway)

Implement `Minishop\Payments\Contracts\PaymentGatewayContract` and register the driver in a service provider:

```
use Minishop\Payments\Facades\Payment as MinishopPayment;

MinishopPayment::extend('paypal', function ($app) {
    return new PayPalGateway(config('services.paypal'));
});
```

The contract requires:

```
interface PaymentGatewayContract
{
    public function name(): string;
    public function initiate(Order $order, Request $request): JsonResponse|RedirectResponse;
    public function handleWebhook(Request $request): Response;
    public function requiresPaymentStep(): bool;
}
```

---

Queues &amp; background work
----------------------------

[](#queues--background-work)

Minishop pushes outbound work onto the queue rather than blocking the request:

- **Order confirmation emails** — sent after checkout (COD) and after the Stripe webhook confirms payment. These render the **invoice PDF** as an attachment, which is CPU work you don't want inline in a webhook.
- **Order status emails** — sent when an order moves to shipped/delivered/ cancelled/refunded.
- **Low-stock alerts** — a queued notification to `MINISHOP_LOW_STOCK_EMAIL`.

### Out of the box

[](#out-of-the-box)

With Laravel's default `QUEUE_CONNECTION=sync`, these run **inline** — everything works with no worker, but checkout and webhook responses pay the cost of sending mail and rendering PDFs. Fine for local/dev and low volume.

### In production

[](#in-production)

Use a real queue and run a worker:

```
QUEUE_CONNECTION=database   # or redis
```

```
php artisan migrate          # creates the jobs / failed_jobs tables
php artisan queue:work --tries=3 --max-time=3600
```

Run the worker under a process supervisor (Supervisor, systemd, or your platform's worker process) so it restarts on failure and after deploys (`php artisan queue:restart`). Inspect and replay failures with `php artisan queue:failed` and `php artisan queue:retry all`.

> **Gotcha:** on a non-`sync` connection, **emails only send when a worker is running.** If order confirmations aren't arriving in production, check that a `queue:work` process is up. Stripe webhook handling is idempotent (deduped on the Stripe event id), so retried deliveries never double-send.

---

Custom Storefront Renderer
--------------------------

[](#custom-storefront-renderer)

To use your own frontend (Inertia, a custom Blade theme, an SPA API bridge, etc.) instead of the built-in Livewire storefront, implement `Minishop\Rendering\StorefrontRendererContract` and set the FQCN in your config:

```
MINISHOP_RENDERER=App\Rendering\CustomRenderer
```

```
use Minishop\Rendering\StorefrontRendererContract;

class CustomRenderer implements StorefrontRendererContract
{
    public function render(string $view, array $data = []): mixed
    {
        // $view is a slash-separated path, e.g. 'storefront/Products/Index'.
        // Map it to your own templates, an Inertia page, an API payload, etc.
        return view('shop.'.str_replace('/', '.', strtolower($view)), $data);
    }
}
```

> The package no longer ships an Inertia renderer — the default (and only built-in) renderer is `blade`, which powers the Livewire storefront. A custom renderer is only needed if you are replacing that frontend entirely.

---

Seeders
-------

[](#seeders)

To seed demo data (roles, categories, products, shipping methods, Canadian tax zones, coupons, sample orders), run the package's aggregate seeder — `php artisan db:seed` alone runs your host app's `DatabaseSeeder`, not Minishop's:

```
php artisan db:seed --class="Minishop\Database\Seeders\MinishopSeeder"
```

To seed only roles and permissions (required for the app to function):

```
php artisan db:seed --class="Minishop\Database\Seeders\RoleAndPermissionSeeder"
```

---

Testing
-------

[](#testing)

The package ships with a full PHPUnit test suite. To run it from the package directory:

```
composer install
vendor/bin/phpunit
```

Or via the host app:

```
php artisan test --compact
```

---

License
-------

[](#license)

MIT

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance88

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

61d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/145857467?v=4)[toadfix.ca](/maintainers/toadfix)[@toadfix](https://github.com/toadfix)

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/toadfix-minishop/health.svg)

```
[![Health](https://phpackages.com/badges/toadfix-minishop/health.svg)](https://phpackages.com/packages/toadfix-minishop)
```

###  Alternatives

[unopim/unopim

UnoPim Laravel PIM

10.5k2.4k](/packages/unopim-unopim)[bagisto/bagisto

Bagisto Laravel E-Commerce

27.6k172.1k9](/packages/bagisto-bagisto)[leantime/leantime

Open source project management system for non-project managers. Simple like Trello, powerful like Jira. Built with neurodiversity in mind.

10.2k4.0k](/packages/leantime-leantime)[duncanmcclean/statamic-cargo

Comprehensive e-commerce addon for Statamic. Build bespoke e-commerce sites without the complexity.

3518.3k](/packages/duncanmcclean-statamic-cargo)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
