Skip to main content
Shopper supports multi-currency pricing for products and product variants. Each priceable model can have one price per currency, stored in a shared prices table through a polymorphic relationship. Prices are stored in cents following the Stripe/Shopify standard.

Money Storage Standard

All monetary values are stored as integers in cents. $29.99 is stored as 2999 cents. For zero-decimal currencies (XAF, JPY, KRW), the value is stored as-is since the currency has no subdivision (15000 FCFA is stored as 15000).

Display

Use shopper_money_format() to convert cents to a human-readable format. The helper divides by 100 for standard currencies and passes zero-decimal currencies through unchanged. It uses Laravel’s Number::currency() with the application locale.

Default Currency

The shopper_currency() helper returns the store’s default currency code. It reads the default_currency_id setting, looks up the currency code, caches it for one hour, and falls back to 'USD' if no default is configured.

Zero-Decimal Currencies

These helpers let you check whether a currency uses decimal subdivisions:

Price Model

The model used is Shopper\Core\Models\Price. It implements Shopper\Core\Models\Contracts\Price and is not configurable via config/shopper/models.php.

Database Schema

Price Fields

Each price record has three amount fields that serve distinct business purposes: For a product on sale, you would set all three: cost at 850, selling at 1999, and compare-at at 2999. The storefront shows “19.99  19.99 ~~29.99~~” and you know the margin is $11.49.

Relationships

The priceable relationship connects a price to its parent model (Product or ProductVariant):
The currency relationship returns the currency for this price:

Price Helper

The Price model provides three methods that return a Shopper\Core\Helpers\Price value object with both the raw amount and a pre-formatted string:
You can also create a Price helper directly:

HasPrices Trait

The HasPrices trait is used by Product and ProductVariant to provide pricing capabilities. Any model implementing the Shopper\Core\Contracts\Priceable interface can use this trait. To get the price for the store’s default currency:
To get the price for a specific currency:
The method checks if the prices relationship is already loaded to avoid extra queries. When eager-loaded, it filters the collection in memory instead of hitting the database. To access all prices:

Currency Model

The model used is Shopper\Core\Models\Currency. It implements Shopper\Core\Models\Contracts\Currency and has no timestamps.

Currency Schema

Enabled Scope

The Currency model has a global enabled scope that automatically filters out disabled currencies. All queries return only enabled currencies by default.

Zone Relationship

Each currency can be associated with a zone for region-specific pricing:

Creating Prices

To set a price on a product or variant, create a Price record through the prices() relationship:

Multi-Currency Pricing

To set prices in multiple currencies at once, use the SavePricingAction. It accepts an array keyed by currency ID and creates or updates prices in a single pass:
The action uses updateOrCreate on each entry, so existing prices for a currency are updated rather than duplicated.

Retrieving Prices

To get a product’s price for the default currency and format it for display:
To display a sale price with strikethrough:
To eager-load prices and avoid N+1 queries when listing products:

Admin Components

MoneyInput

For Filament forms, use the MoneyInput component instead of TextInput for monetary fields. It handles conversion between human values (form) and cents (database) automatically:
For zero-decimal currencies, the component adjusts the mask precision to 0 automatically. If no currency is specified, MoneyInput defaults to the store’s configured currency via shopper_currency().

Table Columns

Use the ->currency() macro on Filament TextColumn for displaying monetary values:
This macro uses shopper_money_format() internally.

Publishing Components

To customize the pricing Livewire components:
The pricing components are registered in config/shopper/components/product.php: