Overview
A Product Display Page (PDP) is the page where customers view a single product, select options like size or color, see pricing and images, and add items to their cart. This guide walks through building a PDP using Lunar’s models and facades. The examples below use standard Laravel controllers and Blade templates. The same concepts apply whether the storefront is built with Livewire, Inertia, or a headless API.Resolving a Product from a URL
Lunar’sUrl model provides slug-based lookups for products, removing the need to expose database IDs in URLs.
Define the Route
Resolve the Product
channel() and customerGroup() scopes ensure that a product not published to the current channel or customer group returns a 404 rather than rendering. See the Storefront Session reference for how to manage these values.
Displaying Product Information
Product Name and Description
Product names and descriptions are stored as attribute data. Use theattr() method to retrieve translated values.
Custom Attributes
Any custom attributes defined on the product type are accessible in the same way. For example, if the product type includes a “Material” attribute:Product Images
Lunar uses Spatie MediaLibrary for image management. Products store images in theimages media collection.
large, medium, zoom, etc.) depend on the media definitions configured in config/lunar/media.php. See the Media reference for details on customizing conversions.
Variant Selection
Most products have at least one variant. When a product offers multiple variants (different sizes, colors, etc.), the storefront needs to let customers select the variant they want.Understanding the Data Structure
Each variant is associated with one or moreProductOptionValue records. For example, a T-shirt might have:
- Product Options: Color, Size
- Product Option Values: Blue, Red (for Color); S, M, L (for Size)
- Variants: Blue/S, Blue/M, Blue/L, Red/S, Red/M, Red/L
Building an Option Selector
Mapping Option Values to Variants
To determine which variant corresponds to a given set of option selections, build a lookup map and pass it to the frontend.Single-Variant Products
When a product has only one variant, option selectors are unnecessary. Handle this in the template:Pricing
Pricing in Lunar is resolved through thePricing facade, which accounts for the current currency, customer group, and quantity.
Displaying the Price
ThePricing facade accepts an optional currency and customer group. Pass these from StorefrontSession so the returned price matches the browsing context.
get() method returns a PricingResponse with the following properties:
Formatting Prices in Blade
Tax-Inclusive and Tax-Exclusive Prices
If prices are stored inclusive of tax, use the helper methods on thePrice model to show both:
Price Breaks
If the product offers quantity-based pricing, display the available tiers:Stock and Availability
Each variant tracks its own inventory. Display stock status to help customers make purchasing decisions.purchasable field on a variant controls its availability:
Use
canBeFulfilledAtQuantity() to verify a specific quantity can be fulfilled before adding to cart:
Adding to Cart
Lunar provides aCartSession facade for managing the active cart. Use it to add variants to the cart from the PDP.
The Add-to-Cart Form
The Controller
The Route
Related Products
Lunar supports product associations for cross-sells, upsells, and alternate products. Display these on the PDP to encourage additional purchases.Variant-Specific Images
When variants have their own images (for example, showing a different image per color), swap the displayed image based on the selected variant.Putting It All Together
Here is a complete controller that prepares all the data a PDP needs:Next Steps
- Review the Products reference for the full list of model fields, relationships, and scopes.
- Review the Pricing reference for custom price formatters and additional formatting options.
- Review the Media reference for image conversion configuration.
- Review the Storefront Session reference to manage channel, currency, and customer group context.