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 as2999 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
Useshopper_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
Theshopper_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 isShopper\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 “29.99~~” and you know the margin is $11.49.
Relationships
Thepriceable relationship connects a price to its parent model (Product or ProductVariant):
currency relationship returns the currency for this price:
Price Helper
The Price model provides three methods that return aShopper\Core\Helpers\Price value object with both the raw amount and a pre-formatted string:
HasPrices Trait
TheHasPrices 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:
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 isShopper\Core\Models\Currency. It implements Shopper\Core\Models\Contracts\Currency and has no timestamps.
Currency Schema
Enabled Scope
The Currency model has a globalenabled 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 theprices() relationship:
Multi-Currency Pricing
To set prices in multiple currencies at once, use theSavePricingAction. It accepts an array keyed by currency ID and creates or updates prices in a single pass:
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:Admin Components
MoneyInput
For Filament forms, use theMoneyInput component instead of TextInput for monetary fields. It handles conversion between human values (form) and cents (database) automatically:
MoneyInput defaults to the store’s configured currency via shopper_currency().
Table Columns
Use the->currency() macro on Filament TextColumn for displaying monetary values:
shopper_money_format() internally.
Publishing Components
To customize the pricing Livewire components:config/shopper/components/product.php: