Skip to main content
Products are the core catalog model in Lunar, representing items available for sale with variants, pricing, and options.

Overview

Products represent the items available for sale in a store. Every product belongs to a ProductType, which determines which attributes are available to it and its variants, and can optionally belong to a Brand. A product always has at least one variant. When a product has only a single variant, the editing experience appears as though the product itself is being edited directly, but behind the scenes the purchasable data (pricing, stock, tax, dimensions) lives on the variant.

Fields

Products do not use soft deletes. A product with order history cannot be hard-deleted; $product->hasOrderHistory() reports whether any of its variants appear on a historical order line, and such products should be archived instead of deleted.

Relationships

Scopes

Creating a Product

Name and description

Unlike custom attributes, name, description, and short_description are dedicated, translatable columns on the product, guaranteeing every product has a real, queryable name. They are stored as a locale-keyed map and read through the translate() helper:
attribute_data remains available for genuinely custom, per-product-type attributes. See the Attributes reference for details.

Filtering by status

Channels

Products support multi-channel availability through the HasChannels trait. When a product is created, all channels are automatically synced. Each channel can be independently enabled or disabled, with optional start and end dates for scheduled availability.

Scheduling a channel

Filtering by channel

Customer Groups

Products can be assigned to customer groups with optional scheduling. This controls whether the product is visible and purchasable for members of each group.

Scheduling a customer group

Filtering by customer group

The customerGroup scope accepts a single customer group (or ID), or a collection/array of customer groups or IDs.

Product Types

Product types categorize products and determine which attributes are available during editing (e.g. Television, T-Shirt, Book, Phone).

Fields

A product type cannot be deleted while products still reference it — reassign or remove them first, otherwise ProductTypeActionException is thrown.

Relationships

Scopes

Creating a product type

Product types have Attributes associated to them. These associated attributes determine which fields are available to products and variants when editing. For example, an attribute of Screen Type associated to a TVs product type would make that field available on any product with that type. Attributes can be associated using a standard polymorphic relationship:
Both Product and ProductVariant attributes can be associated to a product type, and each will display on the corresponding model when editing.
Deleting an attribute will drop the association and could result in data loss.

Retrieving the product type relationship

Product Options

Product options define the different variations available for a product. Each ProductOption has a set of ProductOptionValue models. For example, a ProductOption called “Color” could have values like “Blue”, “Red”, and “Green”.
Product options and product option values are defined at a system level and are translatable.

Fields

Relationships

Scopes

Creating a ProductOption

Values can then be created for the option:
This product option and its values are now ready to be used with product variants.

ProductOptionValue Fields

Product Option Meta

Both ProductOption and ProductOptionValue models include a meta field for storing custom information such as color hex values, image links, or other display data. Lunar makes no assumptions about the structure of the meta JSON field. Any values can be stored in whatever format the application requires.

Product Associations

Products can be associated with other products as cross-sells, up-sells, or alternates. See the Associations reference for full details on creating and managing product associations.

Variants

Variants represent the different purchasable permutations of a product, such as “Small Blue T-shirt” or “Size 9 Leather Boots”. The product acts as the parent, and variants hold the specific data including pricing, inventory, shipping information, and product identifiers. A product always has at least one variant.

Fields

Stock is a cached rollup derived from the variant’s per-location stock levels and an append-only movement ledger. See the Inventory reference for the full stock model, location tracking, and movement API.

Relationships

Scopes

Selling Policy

selling_policy decides whether a variant can be sold relative to its stock, cast to the Lunar\Core\Enums\SellingPolicy enum:

Product Identifiers

Each variant can store product identifiers for use in internal systems or external services. SKU (Stock Keeping Unit) — A code (usually eight alphanumeric digits) used to track stock levels internally. Each variant of a product typically has a unique SKU. GTIN (Global Trade Item Number) — An internationally recognized product identifier, often accompanying a barcode. Useful with services like Google Shopping to help classify products. MPN (Manufacturer Part Number) — An identifier from the manufacturer that differentiates a product among similar items from the same brand. EAN (European Article Number) — A series of characters that identifies specific products within an inventory system.

Creating Variants

A product variant requires a product and a tax class.
Create the product option and its values:
Create the variants and attach their option values:
Then create pricing for each variant. See the Pricing reference for full details on prices, price breaks, and fetching the correct price for a customer.

Shipping

By default, all product variants are marked as shippable. To mark a variant as non-shippable:

Dimensions

Products can store dimension data on each variant. The available dimensions are:
  • Length
  • Width
  • Height
  • Weight
  • Volume
For handling unit conversions, Lunar uses the Cartalyst Converter package, which supports a wide range of units of measure. Each dimension has a corresponding _value and _unit column in the database:

Configuring measurements

Available units of measure can be configured in the lunar/shipping.php config file. The defaults include: Length: m, mm, cm, ft, in Weight: kg, g, lbs Volume: l, ml, gal, floz

Getting and converting measurement values

The raw *_value and *_unit values can be accessed directly, but Lunar also provides an accessor for each dimension that supports conversion:

Volume calculation

Volume can be calculated automatically from the length, width, and height dimensions, or set manually:
Formatted values

Pricing

Pricing is defined at the variant level: each variant has its own price for each currency, plus optional customer group pricing and quantity breaks. See the Pricing reference for the full API, including the PricingManager facade used to fetch the correct price for a customer. To retrieve all prices across a product’s variants without loading the variants individually, use the prices relationship on the product:

Full Example

This example walks through creating a pair of Dr. Martens boots with multiple size and color variants. The steps involved are:
  • Create the product type
  • Create the initial product
  • Create product options and their values
  • Create the variants

Set up the product type

Create the initial product

Create product options

Based on the example above, two options are needed: Size and Color.

Create product option values

Create the variants

With the options and values defined, variants can be created for each combination. Each variant needs a product, tax class, SKU, and at least one price.
The resulting variants: SKUs, pricing, and other variant details can be adjusted as needed before publishing.