Skip to main content
Search indexing in Lunar can be customized by making additional models searchable, changing what data is sent to the search index, and choosing which search engine each model uses.
This page covers customizing how models are indexed. For day-to-day search usage, configuration, and the search artisan commands, see the Search reference.

Overview

Every Lunar model that can be searched uses the Lunar\Core\Models\Concerns\Searchable trait, which wraps Laravel Scout’s own Laravel\Scout\Searchable trait. Instead of implementing Scout’s methods directly on the model, the trait delegates them to an indexer class, resolved from config('lunar.search.indexers'). This keeps indexing logic out of the model and makes it swappable per model. There are three things to consider when extending search:
  • Which models are searchable
  • What data is sent to the index (searchable, sortable, and filterable fields)
  • Which search engine a model’s index lives on

Making a custom model searchable

Any Eloquent model, not just Lunar’s own models, can be added to the search index. Add the Searchable trait to the model:
Then register the model in config/lunar/search.php under models:
Only models listed in models are picked up by the lunar:search:index artisan command. See the Search reference for indexing commands.

Default indexing behavior

If a model isn’t mapped in the indexers config, Lunar\Core\Search\ScoutIndexer is used by default. Its toSearchableArray() indexes:
  • The model’s id
  • Any attributes marked searchable on the model’s attribute data (via mapSearchableAttributes())
ScoutIndexer also exposes two protected helpers that a custom indexer can call when extending it:
Maps every custom attribute marked searchable for the model’s attribute type into the index. This means attributes marked searchable in the admin panel are automatically added to the index without further code changes. TranslatedText attribute values are exploded into locale-suffixed keys (for example, name_en, name_fr).
Takes a list of column names and explodes any translatable columns (such as a model’s own name or description) into locale-suffixed index keys, the same way translatable attributes are handled. A plain, non-translatable string column is indexed under its bare field name. Lunar’s own models are mapped to dedicated indexers that extend ScoutIndexer to add fields specific to that model. Lunar\Core\Search\ProductIndexer, for example, adds:
  • public_id and status
  • product_type (the product type’s name) and brand (the brand’s name, if set)
  • created_at as a Unix timestamp
  • Translatable name, description, and short_description fields, exploded per locale
  • Any searchable custom attributes
  • thumbnail (the small variant’s URL, if a thumbnail is set)
  • skus, an array of the product’s variant SKUs
Its sortable fields are created_at, updated_at, skus, and status; its filterable fields are __soft_deleted, skus, and status. Lunar ships similar dedicated indexers for BrandIndexer, CollectionIndexer, CustomerIndexer, OrderIndexer, and ProductOptionIndexer. See the Search reference for what each one indexes.

Mapping custom indexers

All indexers are mapped in config/lunar/search.php under indexers. To change how a model is indexed, map it to a custom class:

Creating a custom indexer

A custom indexer can extend Lunar\Core\Search\ScoutIndexer to reuse its helpers, or implement Lunar\Core\Search\Interfaces\ScoutIndexerInterface directly if none of the default behavior is needed:
Then map the model to this indexer in config/lunar/search.php:
Lunar\Core\Search\Interfaces\ScoutIndexerInterface::toSearchableArray() takes a single Model $model argument, and every indexer shipped with Lunar implements it with just that one argument. Implement it the same way in a custom indexer.

Custom search engines

Mapping a model to a different engine

By default, Scout indexes every searchable model using the driver set by the SCOUT_DRIVER environment variable. To send a specific model’s index to a different engine, for example keeping high-volume order data off a paid service used for products, map it under engine_map in config/lunar/search.php:
Any model not listed in engine_map falls back to the default Scout driver.

Registering a new engine

Adding an entirely new search engine (one that isn’t already a Scout driver) is not something Lunar reinvents: the Searchable trait resolves engines through Laravel Scout’s own Laravel\Scout\EngineManager, so a custom engine is registered the standard Scout way, using EngineManager::extend():
Once registered, map the desired model to the new driver name in engine_map:
The storefront search package (namespace Lunar\Search\...) is a separate package from the indexing pieces described on this page. It provides the storefront-facing query layer: faceted filtering, sorting, and instant search, built on top of the Scout search results that Lunar’s core indexers produce. Indexers control what gets indexed; Lunar\Search\... controls how the storefront queries it. See the Search reference for details.