Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Framework Laravel Package

vanilo/framework

Vanilo Framework is a modular e-commerce foundation for Laravel, providing products, pricing, carts, checkout, orders, payments, shipping, and promotions to help you build custom online stores quickly.

View on GitHub
Deep Wiki
Context7

Getting Started

Vanilo is not a shop-in-a-box — it's a set of ~20 composable e-commerce modules (products, cart, checkout, orders, payment, shipping, taxation, properties, channels) glued together by Concord, Konekt's module/contract system. vanilo/framework is the metapackage that pulls all of them in; you supply the storefront, the views, and the business rules.

Minimum path:

composer require vanilo/framework   # match the PHP/Laravel matrix for your Vanilo major
php artisan vendor:publish --tag=vanilo      # config + migrations (check the tags it lists)
php artisan vendor:publish --tag=concord
php artisan migrate

Then confirm what actually got registered:

php artisan concord:modules      # every module, its contracts and models
php artisan concord:models

Look here first, in this order:

  1. config/concord.php — the module registry. Commenting a module out is how you amputate features you don't want.
  2. config/vanilo/*.php (product, cart, checkout, order, payment, shipping, taxation) — every default table name, model class, and behaviour toggle lives here.
  3. vendor/vanilo/*/src/Contracts/ — this is the real API surface. Code against these interfaces, not the Eloquent models.
  4. vendor/vanilo/*/src/Providers/ModuleServiceProvider.php — shows what each module registers (routes, bindings, event listeners, migrations).
  5. vanilo.io/docs — genuinely good, and more reliable than reading the source for flow questions.

First use case — a working cart → order flow without any admin UI. Wire three controller actions against the facades:

use Vanilo\Cart\Facades\Cart;

public function add(Product $product)
{
    Cart::addItem($product, request('qty', 1));
    return redirect()->route('cart.show');
}

public function show()
{
    return view('cart.show', [
        'items' => Cart::getItems(),
        'total' => Cart::total(),
    ]);
}
use Vanilo\Checkout\Facades\Checkout;

public function begin()
{
    $checkout = Checkout::create(Cart::getFacadeRoot()->getCart());
    $checkout->begin();
    // ->update([...], 'billing'), ->update([...], 'shipping'), ->complete()
}

public function complete()
{
    $checkout->complete();
    $order = $checkout->getOrder();
}

That single flow touches cart, checkout, order, and (via the payment step) payment — it's the fastest way to see how the pieces fit before you customise anything.

Implementation Patterns

Code against contracts, resolve through proxies. Every entity has an interface (Vanilo\Product\Contracts\Product, Vanilo\Order\Contracts\Order, Vanilo\Payment\Contracts\Payment, …) bound to a concrete model via config. In your own code use the contract in type hints and constructor injection; when you need the concrete class (route model binding, ::query(), factories), use the Concord proxy:

use Vanilo\Order\Models\OrderProxy;
$orderClass = OrderProxy::modelClass();   // respects config/vanilo/order.php

To swap a model, extend the shipped one, point the config key at yours, and keep the contract. This is the supported extension mechanism — don't fork the package.

Cart is session-first. Cart::addItem() lazily creates a cart in the session. On login you generally want to adopt it (Cart::exists() / rebind to the user) and Cart::destroy() on logout, or you'll get ghost carts and duplicate line items after a re-login. For "buy now" or API flows, construct a cart explicitly instead of relying on the session facade.

Checkout is a state machine, not a form handler. Checkout::create($cart) → begin() → update($data, $step) per step (billing, shipping, payment, …) → complete(). Each update() validates the payload for that step and advances state. Keep the step order consistent with config; skipping steps out of order is where most checkout bugs come from. Persist the Checkout instance between requests (it's designed to be serialised into the session).

Orders: create from cart, then let events drive the rest. Order::createFromCart($cart) is the canonical path — it copies items, billpayer, shipping address, and totals. Afterwards, treat order status and payment status as two independent state machines; fire your own listeners on OrderCreated/payment-status changes rather than mutating statuses inline in controllers.

Payments are gateway-pluggable. Create a Payment against an order (or any Payable), attach a PaymentMethod (configured gateway), then hand off to the gateway. Gateways are registered per config/vanilo/payment.php and follow a request/response object contract — meaning you can add a custom driver without touching core. Keep a webhook/callback route per gateway and reconcile via payment events, not via the redirect.

Products, variants, properties, taxonomies. Price and stock may live on a variant rather than the product itself — check before assuming $product->price is authoritative. Arbitrary attributes go through Property/PropertyValue (typed: text, number, boolean, select), and categories go through Taxonomy/Taxon. Both are polymorphic-ish and worth seeding before you build catalogue screens.

Channels scope everything. In multi-store setups, Channel + the channel-aware traits determine which products, payment methods, and shipping methods are visible. If something "disappears" in a second store, it's almost always a missing channel association.

Grow by module, not by patch. For real customisation, generate a Concord module (php artisan list concord shows the generators) and put your domain logic there — it gets config, migrations, contracts, and model swapping for free, and it survives Vanilo upgrades cleanly.

Gotchas and Tips

  • The metapackage is heavy. vanilo/framework requires everything, including gateways and tax rules you may never use. In production, require the individual modules (vanilo/product, vanilo/cart, vanilo/order, …) and disable the rest in config/concord.php.
  • Version alignment is unforgiving. All vanilo/* packages must share the same major, and that major is pinned to a Laravel major. Composer conflicts after adding one gateway package are the single most common install failure — bump everything together.
  • Swap models before you migrate, and don't expect table renames. Changing the configured model class does not change the schema. If you need different tables, override the module's migration or set the table in config; otherwise your custom model just maps to the stock table.
  • Config cache vs. Concord. After adding/removing a module or changing a model binding, php artisan config:clear (and re-cache) — stale module registries produce baffling "class not found" or "contract not bound" errors. If it works in tinker but not in the app, this is why.
  • Money is a value object, not a float. Do all arithmetic through Vanilo's price/pricing layer and only format at the edge. Rounding and currency come from the channel; hand-rolled number_format() in Blade will eventually disagree with the order total by a cent.
  • No storefront, no auth, no admin. vanilo/framework ships zero front-end. The admin is a separate vanilo/admin package. Budget for building views, auth integration, and checkout templates.
  • Checkout sessions are brittle across deploys. Changing config keys, step order, or serialised class names invalidates in-flight checkouts. Drain or expire sessions around deploys that touch checkout config.
  • Don't mutate statuses manually. Order and payment statuses have their own transition rules and emit events; direct $order->status = ...; save() bypasses listeners and breaks reporting/inventory integrations.
  • Debugging playbook: php artisan concord:modules to confirm registration → OrderProxy::modelClass() in tinker to confirm which class is actually bound → check storage/logs for gateway request/response payloads → verify the channel association last.
  • Extension points, in order of preference: config model swap → event listeners → custom payment/shipping driver → custom Concord module → fork (last resort, and you'll regret it).

The framework rewards you for staying inside its contract-and-module seams and punishes shortcuts around them — nearly every "Vanilo bug" I've seen traced back to a swapped model without a cleared config cache, or business logic written directly against an Eloquent model instead of the contract.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect