| Install | |
|---|---|
composer require muhammad-nawlo/filament-scout-manager |
|
| Latest Version: | v1.0.1 |
| PHP: | ^8.2 |
A Filament plugin to manage your Laravel Scout search setup from an admin panel.
Install the package:
composer require muhammad-nawlo/filament-scout-manager
Run the installer:
php artisan filament-scout-manager:install
Or manually publish package files:
php artisan vendor:publish --tag="filament-scout-manager-config"
php artisan vendor:publish --tag="filament-scout-manager-migrations"
php artisan migrate
If you use a custom Filament theme, add the package views as a Tailwind source:
@source '../../../../vendor/muhammad-nawlo/filament-scout-manager/resources/**/*.blade.php';
In your Filament panel provider, register the plugin:
use MuhammadNawlo\FilamentScoutManager\FilamentScoutManagerPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugins([
FilamentScoutManagerPlugin::make(),
]);
}
Published config: config/filament-scout-manager.php
return [
'log_searches' => true,
'log_retention_days' => 30,
'enable_synonyms' => true,
'models' => [
// 'App\\Other\\Model' => [],
],
];
Searchable trait.SCOUT_DRIVER) and engine credentials in .env.toSearchableArray().Stored model configuration (index name, searchable fields, engine) can be applied at runtime so that Scout uses the values you set in the Filament panel. This is opt-in and fully backward compatible.
searchableAs(), toSearchableArray(), and searchableUsing() use the stored values; otherwise defaults are unchanged.To enable runtime overrides on a model, use the SearchableWithScoutManagerConfig trait (it combines Scout’s Searchable with plugin config and avoids trait method collisions):
use Illuminate\Database\Eloquent\Model;
use MuhammadNawlo\FilamentScoutManager\Concerns\SearchableWithScoutManagerConfig;
class Product extends Model
{
use SearchableWithScoutManagerConfig;
}
If you prefer to use Searchable and UsesScoutManagerConfig separately, you must resolve the trait collision for searchableUsing, searchableAs, and toSearchableArray with insteadof; see the docblock on UsesScoutManagerConfig for the exact syntax.
Then configure the model in Filament (Search → Searchable Models → Configure). Stored values for index name, searchable fields, and engine will take effect when this trait is used. If no config exists for the model, behavior is identical to Scout’s defaults.
When you need to run many Eloquent operations (bulk updates, imports, etc.) without syncing each change to the search index, use Scout’s withoutSyncingToSearch() method. This avoids unnecessary index writes and improves performance.
Wrap your bulk logic in a closure:
use App\Models\Product;
Product::withoutSyncingToSearch(function () {
Product::where('status', 'draft')->update(['status' => 'published']);
// ... other bulk operations
});
After the batch is done, re-import the affected model so the index is up to date:
php artisan scout:import "App\Models\Product"
This pattern is controlled in your application code; the plugin does not add any global pause or toggle. See Laravel Scout: Pausing Indexing.
To index only some records (e.g. only published posts), implement shouldBeSearchable() on your model. Scout calls this when syncing via save/create or when using the searchable() method on a query; if it returns false, the record is not added or updated in the index.
public function shouldBeSearchable(): bool
{
return $this->is_published;
}
shouldBeSearchable() is not applied (all searchable data is in the database). For similar behavior, use where clauses in your search queries instead.Scout’s queue configuration is global, not per model.
SCOUT_QUEUE=true in .env (or the queue option in config/scout.php) to queue index operations instead of running them synchronously.config/scout.php and apply to all Scout indexing jobs.When using Scout’s database engine (SCOUT_DRIVER=database), you can control how each column is searched by adding PHP attributes to your model’s toSearchableArray() method:
SearchUsingFullText – use MySQL/PostgreSQL full-text search for the listed columns (faster and more relevant for text). Requires a full-text index on those columns in a migration.SearchUsingPrefix – use prefix-only matching (e.g. term%) for the listed columns instead of %term%. Helps performance on large tables.Columns not covered by these attributes keep Scout’s default “where like” behavior. The plugin does not set or change these attributes; you implement them in your model.
Example:
use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;
#[SearchUsingFullText(['title', 'description'])]
#[SearchUsingPrefix(['sku'])]
public function toSearchableArray(): array
{
return [
'title' => $this->title,
'description' => $this->description,
'sku' => $this->sku,
];
}
In a migration, add a full-text index for the columns you use with SearchUsingFullText:
$table->fullText(['title', 'description']);
These strategies apply only when the engine is database. See Laravel Scout: Customizing Database Searching Strategies.
Scout lets you customize how models are loaded during batch import and how the collection is prepared before indexing. Implement these methods on your model; the plugin does not override them.
Modify the import query (e.g. eager load relations to avoid N+1 during import):
use Illuminate\Database\Eloquent\Builder;
protected function makeAllSearchableUsing(Builder $query): Builder
{
return $query->with(['category', 'tags']);
}
Modify the collection before indexing (e.g. load relations on the chunk):
use Illuminate\Database\Eloquent\Collection;
public function makeSearchableUsing(Collection $models): Collection
{
return $models->load('author');
}
toSearchableArray() can use related data without extra queries.makeAllSearchableUsing is used when you run scout:import or Model::makeAllSearchable(); note that when the import is queued, relationships may not be restored in the job, so prefer makeSearchableUsing for per-chunk loading when using queues.When using the Algolia engine, you can associate search requests with authenticated users for analytics and personalization. Set in your .env:
SCOUT_IDENTIFY=true
This tells Scout to pass the authenticated user’s primary identifier and the request IP to Algolia with each search request. The plugin does not automatically send or capture user data; enabling identification and what is sent remain under your application and Laravel Scout. See Laravel Scout: Identifying Users.
By default, Scout uses the model’s primary key as the unique ID stored in the index. You can override this with getScoutKey() and getScoutKeyName() on your model (e.g. to use UUIDs, emails, or external IDs). Some engines (e.g. Typesense) expect string IDs or specific key names.
public function getScoutKey()
{
return $this->email;
}
public function getScoutKeyName()
{
return 'email';
}
The plugin does not override these methods; implement them in your model when needed. See Laravel Scout: Configuring the Model ID.
Some engines support passing extra parameters into the search request. For example, Typesense allows dynamic search parameters via options():
Post::search('laravel')
->options([
'query_by' => 'title, description',
'filter_by' => 'published:=true',
])
->get();
Algolia and other engines may support similar options depending on their API. The plugin does not restrict or modify options(); advanced search behavior stays in your application code. See your engine’s documentation (e.g. Typesense search parameters).
| Feature | Status |
|---|---|
| Index syncing (import, flush, refresh, sync settings) | ✅ |
| Runtime overrides (index name, fields, engine via trait) | ✅ |
| Typesense UI support & safe indexed count | ✅ |
| Custom engines (safe handling, no UI break) | ✅ |
| Indexing control docs (pause, conditional, queue) | ✅ |
| Database engine docs (search strategies, full-text) | ✅ |
| Import customization docs (makeAllSearchableUsing, makeSearchableUsing) | ✅ |
| Algolia user identification docs | ✅ |
| Scout key override docs (getScoutKey, getScoutKeyName) | ✅ |
| Dynamic search options docs (options()) | ✅ |
The plugin does not override Scout core behavior. All engine-specific logic (identify, key, options) remains application-controlled.
The package uses Pest for PHPUnit-style tests. Run the test suite:
composer test
isSearchable, Eloquent query), engine badges, SearchQueryLogResource, SynonymResource.Please see CHANGELOG for recent updates.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see LICENSE for details.