Overview
Product search lets customers find products by typing keywords, browsing faceted filters, and navigating directly to products via URLs. This guide walks through building search and discovery features using Lunar’sSearch facade and Url model.
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.
Lunar core already indexes its models through Laravel Scout out of the box — no add-on required. This guide covers the
lunarphp/search add-on, which adds a fluent query API, faceted filtering, and structured results on top of those indexes. For the underlying indexing setup (searchable models, indexers, engine mapping, the lunar:search:index command), see the Search reference.Search Setup
TheSearch facade and its faceted query API are provided by the lunarphp/search add-on package. It is built on top of Laravel Scout with a driver-based architecture that supports Meilisearch, Typesense, and a database fallback. The Search facade provides a consistent API regardless of which driver is active.
Installing the Search Package
Search facade and the search engine drivers used throughout this guide.
Installing a Search Driver
For production storefronts, install either Meilisearch or Typesense. The database driver works out of the box but lacks faceting and advanced relevance features..env file:
Indexing Products
After configuring the driver, import existing records into the search index using Lunar’s own indexing command:models configuration key (see the Search reference for the full list of options, including per-model refresh and flush flags). Lunar automatically keeps the index in sync as records are created, updated, or deleted.
Searchable Models
Lunar core registers the following models as searchable by default:Searching Products
Use theSearch facade to query products. The query() method accepts a search string, and get() returns a Lunar\Search\Data\SearchResults object. Products are the default model, so no additional configuration is needed.
model() to specify it:
Search Results
TheSearchResults object contains everything needed to render a results page:
Each
SearchHit contains:
Building a Search Controller
Displaying Search Results
Search hits contain the indexed document data, not Eloquent models. The default product indexer indexes fields like
id, public_id, status, product_type, brand, thumbnail, skus, translatable name/description/short_description columns (exploded per locale), and any custom attributes marked as searchable — see the Search reference for the full field list. To load full Eloquent models from search results, collect the IDs and query the database.Loading Eloquent Models from Results
When full model data is needed (for example, to use thePricing facade or access relationships), load the models from the hit IDs:
Sorting Results
Use thesort() method with a field:direction string to control result ordering. The default product indexer’s sortable fields are created_at, updated_at, skus, and status; additional sortable fields can be configured in a custom indexer.
Letting Customers Choose a Sort Order
Faceted Filtering
Facets allow customers to narrow results by attributes like brand, size, or color. Facets are configured per model and are only available when using Meilisearch or Typesense.Configuring Facets
Thelunarphp/search add-on merges its own facets key into the same config/lunar/search.php file that Lunar core uses for indexing configuration. Publish the config file (if not already published) and add a facets entry for the Product model:
Displaying Facets
After executing a search, thefacets property on the results contains the available facet groups with value counts.
SearchFacet has:
Each
SearchFacetValue has:
Applying Facet Filters
Pass filters as an associative array to thefilter() method. Multiple values for the same facet use OR logic.
URL-Based Product Resolution
Lunar stores SEO-friendly slugs in theLunar\Core\Models\Url model. Products, collections, and brands all support URL resolution through the HasUrls trait.
Defining a Catch-All Route
A common pattern is to define a catch-all route that resolves the URL to the correct model type:Resolving the URL
Working with URLs on Models
Searchable Attributes
Custom product attributes marked as searchable in the admin panel are automatically included in the search index alongside the product’sname, description, and short_description columns. This means customers can search by any attribute value, such as material, color, or specifications.
See the Search reference for the complete list of fields the default product indexer sends to the search engine.
Routes
Putting It All Together
Here is a complete search controller with faceted filtering and sorting:Next Steps
- Review the Search reference for the full list of searchable models, indexers, and the
lunar:search:indexArtisan command. - Review the Product Listing Page guide for collection-based product browsing as an alternative to search.