Skip to main content

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’s Search 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

The Search 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

This installs the 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.
Set the driver in the application’s .env file:

Indexing Products

After configuring the driver, import existing records into the search index using Lunar’s own indexing command:
This imports every model listed in the 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 the Search 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.
To search a different model, use model() to specify it:

Search Results

The SearchResults 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 the Pricing facade or access relationships), load the models from the hit IDs:

Sorting Results

Use the sort() 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

The lunarphp/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:
Each key under a model corresponds to a field in that model’s search index. Additional facets can be added for any indexed, filterable field.

Displaying Facets

After executing a search, the facets property on the results contains the available facet groups with value counts.
Each SearchFacet has: Each SearchFacetValue has:

Applying Facet Filters

Pass filters as an associative array to the filter() method. Multiple values for the same facet use OR logic.
Filters can also be added individually:

URL-Based Product Resolution

Lunar stores SEO-friendly slugs in the Lunar\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’s name, description, and short_description columns. This means customers can search by any attribute value, such as material, color, or specifications.
After changing which attributes are searchable, reimport the search index with php artisan lunar:search:index "Lunar\Core\Models\Product" --refresh.
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:index Artisan command.
  • Review the Product Listing Page guide for collection-based product browsing as an alternative to search.