PHPackages                             jackardios/elastic-query-wizard - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. jackardios/elastic-query-wizard

ActiveLibrary[API Development](/categories/api)

jackardios/elastic-query-wizard
===============================

Laravel Elastic Query Wizard

v2.2.0(1y ago)0462MITPHPPHP ^8.1CI passing

Since Jun 28Pushed 3mo ago2 watchersCompare

[ Source](https://github.com/Jackardios/elastic-query-wizard)[ Packagist](https://packagist.org/packages/jackardios/elastic-query-wizard)[ Docs](https://github.com/jackardios/elastic-query-wizard)[ RSS](/packages/jackardios-elastic-query-wizard/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (10)Versions (15)Used By (0)

Elastic Query Wizard
====================

[](#elastic-query-wizard)

[![Latest Version on Packagist](https://camo.githubusercontent.com/c6ac60370aaeae01c8c903f70cb58384553e4c2adedf4da239ad1361e9a59258/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a61636b617264696f732f656c61737469632d71756572792d77697a6172642e737667)](https://packagist.org/packages/jackardios/elastic-query-wizard)[![License](https://camo.githubusercontent.com/890b0b62c8a10a9650c423c01423f0baf0f376e24b4694a814c1178571f24bbc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6a61636b617264696f732f656c61737469632d71756572792d77697a6172642e737667)](https://packagist.org/packages/jackardios/elastic-query-wizard)
[![CI](https://github.com/jackardios/elastic-query-wizard/actions/workflows/ci.yml/badge.svg)](https://github.com/jackardios/elastic-query-wizard/actions)

A powerful Laravel package for building Elasticsearch queries with JSON:API style filtering, sorting, and relation loading. Built on top of [laravel-query-wizard](https://github.com/Jackardios/laravel-query-wizard) and [es-scout-driver](https://github.com/Jackardios/es-scout-driver).

Table of Contents
-----------------

[](#table-of-contents)

- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Documentation](#documentation)
- [Resource Schemas](#resource-schemas)
- [Usage Examples](#usage-examples)
- [Elasticsearch Version Compatibility](#elasticsearch-version-compatibility)
- [License](#license)

Features
--------

[](#features)

- **Declarative API** — define allowed filters, sorts, and includes in one place
- **Resource Schemas** — centralize query configuration in reusable, context-aware schema classes
- **Security** — only explicitly allowed parameters are applied to queries
- **Full-text Search** — match, multi\_match, fuzzy and other Elasticsearch query types
- **Geo Queries** — filter and sort by geographic coordinates
- **Flexible Configuration** — pass additional parameters to any query
- **SearchBuilder DSL Integration** — configure `query`, bool clauses, aggregations, highlight, suggest, KNN, and more directly on the wizard
- **Consistent DSL Facades** — use `ElasticQuery` and `ElasticAggregation` as package-local proxies for full `es-scout-driver` capabilities
- **Eloquent Integration** — load relations and accessors after Elasticsearch query execution
- **JSON:API Compatible** — standardized query parameter format

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 10, 11, or 12
- Elasticsearch 8.x or 9.x
- [es-scout-driver](https://github.com/Jackardios/es-scout-driver)
- [laravel-query-wizard](https://github.com/Jackardios/laravel-query-wizard)

Installation
------------

[](#installation)

```
composer require jackardios/elastic-query-wizard
```

Make sure your model uses the `Searchable` trait from `es-scout-driver`:

```
use Jackardios\EsScoutDriver\Searchable;

class Post extends Model
{
    use Searchable;

    // ...
}
```

Quick Start
-----------

[](#quick-start)

### Basic Example

[](#basic-example)

```
use Jackardios\ElasticQueryWizard\ElasticQueryWizard;
use Jackardios\ElasticQueryWizard\ElasticFilter;
use Jackardios\ElasticQueryWizard\ElasticSort;

// GET /posts?filter[status]=published&filter[title]=laravel&sort=-created_at&include=author

$posts = ElasticQueryWizard::for(Post::class)
    ->allowedFilters([
        ElasticFilter::term('status'),
        ElasticFilter::match('title'),
        ElasticFilter::range('created_at'),
    ])
    ->allowedSorts([
        ElasticSort::field('created_at'),
        ElasticSort::field('title'),
    ])
    ->allowedIncludes(['author', 'comments'])
    ->build()
    ->execute()
    ->models();
```

Documentation
-------------

[](#documentation)

Detailed documentation for each section:

SectionDescription[Filters](docs/filters.md)All filter types: term, match, range, geo, fuzzy, and more[Sorts](docs/sorts.md)Sorting by fields, geography, and scripts[Includes](docs/includes.md)Loading Eloquent relations after Elasticsearch query[Advanced Usage](docs/advanced.md)Resource schemas, custom filters, aggregations, working with SearchBuilder[ES Compatibility](docs/elasticsearch-compatibility.md)Elasticsearch 8.x/9.x differences and migration guideResource Schemas
----------------

[](#resource-schemas)

For larger applications, use Resource Schemas to centralize query configuration in reusable classes:

```
use Jackardios\QueryWizard\Schema\ResourceSchema;
use Jackardios\QueryWizard\Contracts\QueryWizardInterface;

class PostSchema extends ResourceSchema
{
    public function model(): string
    {
        return Post::class;
    }

    public function filters(QueryWizardInterface $wizard): array
    {
        return [
            'status',
            ElasticFilter::match('title'),
            ElasticFilter::multiMatch(['title^2', 'body'], 'search'),
        ];
    }

    public function sorts(QueryWizardInterface $wizard): array
    {
        return ['created_at', 'title'];
    }

    public function includes(QueryWizardInterface $wizard): array
    {
        return ['author', 'comments', 'commentsCount'];
    }

    public function defaultSorts(QueryWizardInterface $wizard): array
    {
        return ['-created_at'];
    }
}
```

### Using Schemas

[](#using-schemas)

```
// Create wizard from schema
$posts = ElasticQueryWizard::forSchema(PostSchema::class)
    ->build()
    ->execute()
    ->models();

// Override schema settings for specific endpoints
ElasticQueryWizard::forSchema(PostSchema::class)
    ->disallowedFilters('status')        // Remove filter
    ->disallowedIncludes('comments')     // Remove include
    ->build()
    ->execute();
```

See [Advanced Usage](docs/advanced.md#resource-schemas) for full schema documentation including context-aware schemas, wildcard support, and all available methods.

Usage Examples
--------------

[](#usage-examples)

### Advanced SearchBuilder DSL

[](#advanced-searchbuilder-dsl)

```
use Jackardios\ElasticQueryWizard\ElasticQueryWizard;
use Jackardios\ElasticQueryWizard\ElasticQuery;
use Jackardios\ElasticQueryWizard\ElasticAggregation;

$results = ElasticQueryWizard::for(Article::class)
    ->allowedFilters([
        ElasticFilter::term('status'),
        ElasticFilter::multiMatch(['title^3', 'body'], 'search'),
    ])
    ->query(ElasticQuery::match('language', 'en'))
    ->must(ElasticQuery::range('published_at')->gte('2024-01-01'))
    ->highlight('title')
    ->aggregate('by_author', ElasticAggregation::terms('author')->size(10))
    ->trackTotalHits(true)
    ->build()
    ->execute();
```

### Geo Filtering

[](#geo-filtering)

```
// GET /places?filter[nearby][lat]=55.75&filter[nearby][lon]=37.62&filter[nearby][distance]=10km

$places = ElasticQueryWizard::for(Place::class)
    ->allowedFilters([
        ElasticFilter::geoDistance('location', 'nearby'),
        ElasticFilter::term('category'),
    ])
    ->allowedSorts([
        ElasticSort::geoDistance('location', 55.75, 37.62, 'distance'),
    ])
    ->build()
    ->execute()
    ->models();
```

### Full-text Search

[](#full-text-search)

```
// GET /articles?filter[search]=elasticsearch tutorial&filter[category]=tech

$articles = ElasticQueryWizard::for(Article::class)
    ->allowedFilters([
        ElasticFilter::multiMatch(['title^2', 'body', 'tags'], 'search')
            ->withParameters([
                'type' => 'best_fields',
                'fuzziness' => 'AUTO',
            ]),
        ElasticFilter::term('category'),
    ])
    ->defaultSorts('-created_at')
    ->build()
    ->execute()
    ->models();
```

### Date Range Filtering

[](#date-range-filtering)

```
// GET /orders?filter[created_at][gte]=2024-01-01&filter[created_at][lte]=2024-12-31

ElasticQueryWizard::for(Order::class)
    ->allowedFilters([
        ElasticFilter::range('created_at'),
        ElasticFilter::term('status'),
    ])
    ->build()
    ->execute()
    ->models();
```

### Autocomplete Search (Prefix)

[](#autocomplete-search-prefix)

```
// GET /users?filter[username]=joh

ElasticQueryWizard::for(User::class)
    ->allowedFilters([
        ElasticFilter::prefix('username'),
    ])
    ->build()
    ->execute()
    ->models();
```

### Typo-tolerant Search (Fuzzy)

[](#typo-tolerant-search-fuzzy)

```
// GET /products?filter[name]=iphon (will find "iphone")

ElasticQueryWizard::for(Product::class)
    ->allowedFilters([
        ElasticFilter::fuzzy('name')->withParameters([
            'fuzziness' => 'AUTO',
        ]),
    ])
    ->build()
    ->execute()
    ->models();
```

### Field Selection

[](#field-selection)

```
// GET /posts?fields[post]=id,title,status

ElasticQueryWizard::for(Post::class)
    ->allowedFields(['id', 'title', 'status', 'body', 'created_at'])
    ->build()
    ->execute()
    ->models();
```

> By default, `resource` is the model class basename in camelCase (for `Post` it is `post`). If you use `forSchema()`, it uses schema `type()`.

### Using Aliases

[](#using-aliases)

Aliases allow you to use different parameter names in your API:

```
// GET /products?filter[tag]=electronics&sort=-date

ElasticQueryWizard::for(Product::class)
    ->allowedFilters([
        // Internal field: category, API parameter: tag
        ElasticFilter::term('category', 'tag'),
    ])
    ->allowedSorts([
        // Internal field: created_at, API parameter: date
        ElasticSort::field('created_at', 'date'),
    ])
    ->build()
    ->execute()
    ->models();
```

### Default Sorting

[](#default-sorting)

```
ElasticQueryWizard::for(Post::class)
    ->allowedSorts(['created_at', 'title', 'views'])
    ->defaultSorts('-created_at') // Default: newest first
    ->build()
    ->execute()
    ->models();
```

### Working with Soft Deletes

[](#working-with-soft-deletes)

```
// GET /posts?filter[trashed]=with (include trashed)
// GET /posts?filter[trashed]=only (only trashed)
// GET /posts?filter[trashed]=without (exclude trashed)
// GET /posts?filter[trashed]=true|false (aliases)

ElasticQueryWizard::for(Post::class)
    ->allowedFilters([
        ElasticFilter::trashed(),
    ])
    ->build()
    ->execute()
    ->models();
```

### Filter Groups

[](#filter-groups)

Filter groups allow you to create complex query structures with OR/AND logic or query nested documents.

#### Bool Group (OR Logic)

[](#bool-group-or-logic)

```
use Jackardios\ElasticQueryWizard\ElasticGroup;

// GET /posts?filter[status]=published&filter[priority]=high
// Matches posts where status=published OR priority=high

ElasticQueryWizard::for(Post::class)
    ->allowedFilters([
        ElasticFilter::term('category'),

        // OR condition: match at least one
        ElasticGroup::bool('status_or_priority')
            ->minimumShouldMatch(1)
            ->children([
                ElasticFilter::term('status', 'status')->inShould(),
                ElasticFilter::term('priority', 'priority')->inShould(),
            ]),
    ])
    ->build()
    ->execute()
    ->models();
```

#### Nested Group (Nested Documents)

[](#nested-group-nested-documents)

```
// GET /posts?filter[comment_author]=john&filter[comment_text]=great
// Matches posts with comments where author=john AND body contains "great"

ElasticQueryWizard::for(Post::class)
    ->allowedFilters([
        ElasticFilter::term('status'),

        // Query nested "comments" documents
        ElasticGroup::nested('comments')
            ->scoreMode('avg')
            ->children([
                ElasticFilter::term('comments.author', 'comment_author'),
                ElasticFilter::match('comments.body', 'comment_text'),
            ]),
    ])
    ->build()
    ->execute()
    ->models();
```

See [Filter Groups](docs/filters.md#filter-groups) for more options including `innerHits`, nested groups, and complex boolean logic.

Query Parameter Format
----------------------

[](#query-parameter-format)

The package uses a standardized JSON:API style parameter format:

ParameterFormatExampleFilters`filter[field]=value``?filter[status]=active`Sorting`sort=field` or `sort=-field``?sort=-created_at`Includes`include=relation1,relation2``?include=author,comments`Fields`fields[resource]=field1,field2``?fields[post]=id,title`Appends`append=accessor1,accessor2``?append=full_name`Elasticsearch Version Compatibility
-----------------------------------

[](#elasticsearch-version-compatibility)

This package supports both Elasticsearch 8.x and 9.x. The package handles most version differences internally, but there are some ES 9.x breaking changes to be aware of:

FeatureES 9.x Status`force_source` highlightingRemovedBoolean histogram aggregationRemoved (use `terms`)`random_score` default fieldChanged to `_seq_no`For full details, migration guide, and safe usage examples, see [Elasticsearch Compatibility](docs/elasticsearch-compatibility.md).

Testing
-------

[](#testing)

```
make test
```

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) file for details.

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance67

Regular maintenance activity

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity64

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~79 days

Recently: every ~16 days

Total

14

Last Release

389d ago

Major Versions

v0.1.4 → v1.0.02024-01-30

v1.x-dev → v2.0.22025-02-17

PHP version history (2 changes)v0.1.0PHP ^8.0

v1.0.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/d502bd9c7502e3464a661326548cb3698cf0a5dfc25b45fc4b93ee22fd1a23d2?d=identicon)[jackardios](/maintainers/jackardios)

---

Top Contributors

[![Jackardios](https://avatars.githubusercontent.com/u/24757335?v=4)](https://github.com/Jackardios "Jackardios (86 commits)")

---

Tags

jsonapilaravellaravel-query-builderquerybuilderelasticquery builderJSON-APIwizardscoutjackardiosscout-query-wizardlaravel-elastic-query-wizardelastic-query-builder

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jackardios-elastic-query-wizard/health.svg)

```
[![Health](https://phpackages.com/badges/jackardios-elastic-query-wizard/health.svg)](https://phpackages.com/packages/jackardios-elastic-query-wizard)
```

###  Alternatives

[cloudcreativity/laravel-json-api

JSON API (jsonapi.org) support for Laravel applications.

7881.1M5](/packages/cloudcreativity-laravel-json-api)[aimeos/aimeos-laravel

Cloud native, API first Laravel eCommerce package with integrated AI for ultra-fast online shops, marketplaces and complex B2B projects

8.6k214.7k3](/packages/aimeos-aimeos-laravel)[joskolenberg/laravel-jory

Create a flexible API for your Laravel application using json based queries.

4513.5k](/packages/joskolenberg-laravel-jory)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
