> ## Documentation Index
> Fetch the complete documentation index at: https://docs.advancedtables.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced Filter Builder

> A powerful filtering system that auto-generates filters from table columns and supports grouped OR conditions for building custom queries.

![Advanced filter builder](https://user-images.githubusercontent.com/6097099/278955775-f124d155-8fd8-4af5-bf38-e13ec958df3c.png)

Advanced Filter Builder is a custom filtering system that gives your users a simple, yet powerful way to quickly build custom queries. Each filter inside the builder can be used multiple times and grouped into *or groups*, allowing your users to drill down and find the data they need. Advanced Filter Builder was designed to make filtering easy for your users with a simple UI and natural filtering language.

For developers, Advanced Filter Builder couldn't be easier to implement. Advanced Filter Builder can *automatically* generates `text`, `numeric`, `date`, `boolean`, and `select` filters from your table columns! You can also seamlessly integrate your existing filters or override the auto-generated ones allowing you to fully customize the filtering experience.

> Important: [Adding AdvancedTables](/v5/get-started/getting-started#adding-advanced-tables-to-your-table) to your table is required for Advanced Filter Builder to properly work.

## Using Advanced Filter Builder

To enable the Advanced Filter Builder, add `AdvancedFilterBuilder` to your table's `->filter()` method:

```php theme={null}
return $table
    ->columns([
        ...
    ])
    ->filters([
        AdvancedFilter::make(),
    ])
```

## Enabling Column Filters

<img src="https://user-images.githubusercontent.com/6097099/278954852-3a754833-d7a7-414c-a7fc-2dbe52e53b79.jpg" alt="Column Filters" width="600" />

To automatically generate Column Filters for each of your table columns, you may use the `->includeColumns()` method. This will [automatically map](/v5/features/advanced-filter-builder#automatic-column-mapping) your table's compatible columns to the appropriate [Column Filter](/v5/features/advanced-filter-builder#column-filter-types) and make them available in Advanced Filter Builder's picker:

```php theme={null}
AdvancedFilter::make()
    ->includeColumns()
```

> Tip: If you wish to only use some Column Filters, you may use either [include](/v5/features/advanced-filter-builder#including-columns) or [exclude](/v5/features/advanced-filter-builder#excluding-columns) columns.

## Column Filter types

Advanced Filter Builder includes multiple different custom Column Filters, each with it's own set of operators:

### Text Filter

The `TextFilter` allows you to filter text strings with operators like `is`, `is not`, `starts with`, `does not end with`, `contains`, etc.

<img src="https://user-images.githubusercontent.com/6097099/278954866-658a0990-335e-4fb8-b554-3de42e469592.jpg" alt="Text Filter" width="600" />

When appropriate, the `TextFilter` can also transform the `is` and `is not` operators into a multiple select dropdown:

<img src="https://user-images.githubusercontent.com/6097099/278954865-2539f10e-3ec9-4445-8484-c9bafeaa7952.jpg" alt="Text Filter with select" width="600" />

### Numeric Filter

The `NumericFilter` allows you to filter numbers with operators like `equal to`, `greater than`, `less than or equal to`, `between`, `positive`, etc.

<img src="https://user-images.githubusercontent.com/6097099/278954861-0740435e-244b-4355-9a31-b109fe9b4a41.jpg" alt="Numeric filter" width="600" />

### Date Filter

The `DateFilter` allows you to filter dates combining *operators* like `yesterday`, `in the next`, `before`, `between`, etc. with *units* like `day`, `week`, `months ago`, `years from now`, etc.

<img src="https://user-images.githubusercontent.com/6097099/278954859-f4486c21-6a30-429f-8d45-4f96a8ae2275.jpg" alt="Date filter" width="600" />

### Select Filter

Advanced Table's custom `SelectFilter` combines Filament's `SelectFilter` with operators `is`, `is not`, `is empty`, `is not empty`.

<img src="https://user-images.githubusercontent.com/6097099/278954856-68f48126-a400-4801-a2b7-459a4c59c391.jpg" alt="Select filter" width="600" />

## Automatic column mapping

Advanced Filter Builder will automatically map your table columns to the appropriate filter depending on the type of column:

1. `TextColumn::make()->date()` and `TextColumn::make()->dateTime()` columns will be mapped to the [DateFilter](/v5/features/advanced-filter-builder#date-filter).
2. `TextColumn::make()->numeric()` and `TextColumn::make()->money()` columns will be mapped to the [NumericFilter](/v5/features/advanced-filter-builder#numeric-filter).
3. [Aggregate Relationship](https://filamentphp.com/docs/3.x/tables/columns/relationships) columns `count`, `avg`, `min`, `max`, and `sum` will be mapped to an aggregate [NumericFilter](/v5/features/advanced-filter-builder#numeric-filter).
4. Any remaining `TextColumn` will be mapped to the [TextFilter](/v5/features/advanced-filter-builder#text-filter).
5. `SelectColumn` will be mapped to Advanced Filter's custom [SelectFilter](/v5/features/advanced-filter-builder#select-filter).
6. `CheckboxColumn`, `ToggleColumn`, `ImageColumn`, `IconColumn` will be mapped to Filament's `Ternary Filter`.

## Customizing filters

Advanced Filter Builder uses the methods on your columns to automatically determine the appropriate filter to use. However, sometimes your table column may not match the type of filter you need. For example, if you are using a `TextColumn` to display an numeric amount, but aren't using the `->numeric()` method, Advanced Filter Builder wouldn't know it's best to use a `NumericFilter`. In these cases, it's easy to customize the filter manually using the `->filters()` method.

### Customizing a Column Filter

You may manually define a Column Filter for a particular column by passing the desired [filter type](/v5/features/advanced-filter-builder#column-filter-types) to the `->filters()` method. The `name` of the filter should be the column you wish to override.

> Tip: Any filter you add to the `->filters()` array will be shown in the filters dropdown by default. To override this behavior you can use the `->defaultFilters()` method to [configure](/v5/features/advanced-filter-builder#setting-the-default-filters) which filters, if any, are shown by default.

> Note: When you are customizing a Column Filter the `name` of the filter *must* match the name of the column in your Filament table. If not, it will not appear in the Filter Picker.

```php theme={null}
AdvancedFilter::make()
    ->filters([
        NumericFilter::make('shipping_price') // Use the NumericFilter on the shipping_price column
    ])
```

To enable the `Select` field inside of the `TextFilter`, you may use a `TextFilter` and then pass in an array of options:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        TextFilter::make('country')
            ->options(fn () => Country::all()->pluck('name', 'id')),
    ])
```

You may also pass in a relationship to automatically load the available options:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        TextFilter::make('customer.name')
            ->relationship(name: 'customer', titleAttribute:'name')
            ->multiple()
            ->preload(),
    ])
```

Finally, if your table column only needs a dropdown of options to select from (ie, it doesn't need additional operators like `starts with`, `contains`, etc.), you may manually map your column to Advanced Filter Builder's custom `SelectFilter`:

```php theme={null}
use Archilex\AdvancedTables\Filters\SelectFilter;

AdvancedFilter::make()
    ->filters([
        SelectFilter::make('status')
            ->options([
                'processing' => 'Processing',
                'new' => 'New',
                'shipped' => 'Shipped',
                'delivered' => 'Delivered',
                'cancelled' => 'Cancelled',
            ])
            ->multiple(), 
    ])
```

> Important: Be sure to import `Archilex\AdvancedTables\Filters\SelectFilter` to see the `is`, `is not`, `is empty`, and `is not empty` operators.

#### Customizing a column filter's operators

You may customize a column filter's operators using either the `->includeOperators()` or `->excludeOperators()` methods:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        TextFilter::make('name')
            ->includeOperators([
                TextOperator::CONTAINS,
                TextOperator::DOES_NOT_CONTAIN
            ]), 
        SelectFilter::make('status')
            ->includeOperators([
                TextOperator::IS, // The SelectFilter uses the TextOperator
            ]), 
        DateFilter::make('created_at')
            ->excludeOperators([
                DateOperator::YESTERDAY,
                DateOperator::TODAY,
                DateOperator::TOMORROW
            ]), 
        NumericFilter::make('total_price')
            ->excludeOperators([
                NumericOperator::EQUAL_TO,
                NumericOperator::NOT_EQUAL_TO
            ]),
    ])
```

To customize a column filter's operators globally, you can call the static `configuringUsing()` method from the `boot()` method of a service provider:

```php theme={null}
public function boot()
{
    TextFilter::configureUsing(function (TextFilter $filter) {
        return $filter->includeOperators([
            TextOperator::CONTAINS,
            TextOperator::DOES_NOT_CONTAIN
        ]);
    });
}
```

`includeOperators()` and `excludeOperators()` can also take a closure meaning you can further customize which operators are available:

```php theme={null}
TextFilter::configureUsing(function (TextFilter $filter) {
    return $filter->includeOperators(function (TextFilter $filter) {
        return $filter->getName() === 'currency'
            ? [TextOperator::CONTAINS, TextOperator::DOES_NOT_CONTAIN]
            : [TextOperator::IS, TextOperator::IS_NOT];
    });
});
```

#### Customizing a column filter's default operator

To customize a column filter's default operator you may pass the name of the operator to the `->defaultOperator()` method:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        TextFilter::make('name')
            ->defaultOperator(TextOperator::CONTAINS),
    ])
```

To customize a column filter's default operator globally, you can call the static `configuringUsing()` method from the `boot()` method of a service provider:

```php theme={null}
public function boot()
{
    TextFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(TextOperator::CONTAINS));
    DateFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(DateOperator::TODAY));
    SelectFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(TextOperator::IS));
    NumericFilter::configureUsing(fn (TextFilter $filter) => $filter->defaultOperator(NumericOperator::GREATER_THAN));
}
```

`defaultOperator()` can also take a closure meaning you can further customize which operator is the default:

```php theme={null}
TextFilter::configureUsing(function (TextFilter $filter) {
    return $filter->defaultOperator(function (TextFilter $filter) {
        return $filter->getName() === 'currency' 
            ? TextOperator::CONTAINS 
            : TextOperator::IS;
    }); 
});
```

### Adding custom filters

Advanced Filter Builder can also seamlessly integrate any of Filament's [filters](https://filamentphp.com/docs/3.x/tables/filters), including [custom filters](https://filamentphp.com/docs/3.x/tables/filters#custom-filter-forms). This allows a filter to be used multiple times as well as in "or groups".

> Tip: Any filter you add to the `->filters()` array will be shown in the filters dropdown by default. To override this behavior you can use the `->defaultFilters()` method to [configure](/v5/features/advanced-filter-builder#setting-the-default-filters) which filters, if any, are shown by default.

To add a filter to Advanced Filter Builder, pass the filter into the `->filters()` method:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        Filter::make('is_active')
            ->query(fn (Builder $query): Builder => $query->where('is_active', true))
            ->toggle(),
    ])
```

> Note: Any filter that has the same `name` as your table column, will be override the automatically mapped column filter. If the filter name does not match any of the table columns it will be added as an additional filter.

> Important: If you are updating from a prior release and your users have already saved created User Views with filters, don't worry, Advanced Filter Builder will automatically map them to the first filter group.
>
> However, if you are using Preset Views with [default filters](/v5/features/preset-views#applying-filters), you will need to [adjust your filters](/v5/features/preset-views#applying-filters-with-filter-builder) to be compatible with Advanced Filter Builder.

## Using filters alongside Advanced Filter Builder

You may still use any of Filament's filters alongside Advanced Filter Builder by adding it as you normally would to your table's `->filters()` method:

```php theme={null}
return $table
    ->columns([
        ...
    ])
    ->filters([
        Filter::make('is_active')
            ->query(fn (Builder $query): Builder => $query->where('is_active', true))
            ->toggle(),
        AdvancedFilter::make(),
    ])
```

The above will add a *single* `Is active` toggle filter to the filter dropdown as well as display the Advanced Filter Builder below it.

## Including columns

To only filter some of your columns, you may pass an array of column `names` you wish to include to the `->includeColumns()` method:

```php theme={null}
AdvancedFilter::make()
    ->includeColumns([
        'is_active',
        'currency',
        'address.city',
    ]);
```

> Important: If you are [customizing a Column Filter](/v5/features/advanced-filter-builder#customizing-a-column-filter), that column must be included in the `->includesColumns()` method.

## Excluding columns

You may instead exclude columns by passing an array of columns `names` to the `->excludeColumns()` method:

```php theme={null}
AdvancedFilter::make()
    ->excludeColumns([
        'status',
        'customer.name',
        'created_at',
    ]);
```

> Important: If you are [customizing a Column Filter](/v5/features/advanced-filter-builder#customizing-a-column-filter), that column must *not* be excluded from the `->excludesColumns()` method.

## Setting the default filters

By default, every filter included in Advanced Filter Builder's `->filters()` method will be shown in the table's filter dropdown. Column Filters that haven't been overriden in the `->filters()` method will be available in the filter picker. To not display any column filters you can pass an empty array to the `->defaultFilters()` method:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        ...
    ])
    ->defaultFilters([])
```

To only display some filters by default, you may pass the name of your filter to the `->defaultFilters()` method inside a double array. You may also use this method to define Column Filters you wish to be displayed by default in the filter dropdown:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        ...
    ])
    ->defaultFilters([['status']])
```

> Important: Be sure to add your filters inside a double array.

You can also set up multiple default groups:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        ...
    ])
    ->defaultFilters([['status'], ['status']])
```

## Disabling Or Groups

By default, Advanced Filter Builder allows your filters to be used in "or groups". You may disable this feature by passing `false` to the `->orGroups()` method:

```php theme={null}
AdvancedFilter::make()
    ->orGroups(false)
```

## Layout options

Advanced Filter Builder responsively adapts to any of the available [FilterLayouts](https://filamentphp.com/docs/3.x/tables/filters#displaying-filters-in-a-modal) (`AboveContent`, `BelowContent`, `AboveContentCollapsible`, `Modal`, `SlideOver`, `Dropdown`). When the builder is used with the `Dropdown` layout (Filament's default layout), the user will also be presented with an "Expand View" button that will allow the dropdown to expand into a slideOver.

If you using the `Modal` layout, it's recommended you set the `->filtersFormWidth()` on the table to at least `3xl` so the form elements have space to flow:

```php theme={null}
use Archilex\AdvancedTables\Filters\AdvancedFilter;
use Filament\Tables\Actions\Action;
use Filament\Tables\Table;
use Filament\Tables\Enums\FiltersLayout;
 
public function table(Table $table): Table
{
    return $table
        ->filters([
            AdvancedFilter::make(),
        ])
        ->filtersLayout(FiltersLayout::Modal)
        ->filtersFormWidth('3xl')
}
```

## Customizing the Expand View Link Position

When using Filament's default `Dropdown` filter layout, the user will also be presented with an "Expand View" button that will allow the dropdown to expand into a slideOver. The expand view link in this view is `absolute` positioned (ugly...I know). If you are using translatable fields, this may cause the link to overlap. You may change the position of the expand view link by passing an array of styles to the `->filterBuilderExpandViewStyles()` method:

```php theme={null}
AdvancedTablesPlugin::make()
    ->filterBuilderExpandViewStyles(['right: 100px', 'top: 24px'])
```

This method also take a closure allowing you to set different positions based on a condition such as locale:

```php theme={null}
use Illuminate\Support\Facades\App;

AdvancedTablesPlugin::make()
    ->filterBuilderExpandViewStyles(fn () => App::isLocale('es') ? ['right: 100px', 'top: 24px'] : ['right: 80px', 'top: 24px'])
```

## Always opening the filter as a slideOver

If you would prefer Advanced Filter Builder to always open in a slideOver or modal, you may use [Filament's](https://filamentphp.com/docs/3.x/tables/filters#customizing-the-filters-dropdown-trigger-action) `filtersTriggerAction()` method:

```php theme={null}
use Archilex\AdvancedTables\Filters\AdvancedFilter;
use Filament\Tables\Actions\Action;
use Filament\Tables\Table;
 
public function table(Table $table): Table
{
    return $table
        ->filters([
            AdvancedFilter::make(),
        ])
        ->filtersFormWidth('md')
        ->filtersTriggerAction(
            fn (Action $action) => $action
                ->slideOver()
        );
}
```

## Adding icons to the Filter Picker

You can add icons to the Filter Picker by passing an array of icons to the `->icons()` method where the name of your filter is the `key` and the icon is the `value`:

```php theme={null}
AdvancedFilter::make()
    ->filters([
        ...
    ])
    ->icons([
        'status' => 'heroicon-o-clock',
        'currency' => 'heroicon-o-currency-euro',
        'customer' => 'heroicon-o-user',
        'created_at' => 'heroicon-o-calendar',
    ])
```

## Enabling search in the Filter Picker

If the Filter Picker has a lot of available filters you can enable a search field using the ->`filterPickerSearch()` method:

```php theme={null}
AdvancedFilter::make()
    ->filterPickerSearch()
```

## Configuring the number of Filter Picker columns

To change the number of columns the Filter Picker may occupy, you may use the `->filterPickerColumns()` method:

```php theme={null}
AdvancedFilter::make()
    ->filterPickerColumns(2)
```

Passing an `integer` will determine how many columns are displayed at the `lg` breakpoint. You may also pass an array:

```php theme={null}
AdvancedFilter::make()
    ->filterPickerColumns(['sm' => 2])
```

## Configuring the Filter Picker width

To customize the width of the Filter Picker, you may use the `->filterPickerWidth()` method, and specify a width - `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, etc.

```php theme={null}
AdvancedFilter::make()
    ->filterPickerWidth('md')
```

> Tip: Since the slideOver is confined to width `md`, it is recommended the Filter Picker not be set to a width larger than `md` as larger sizes will cause the slideOver to horizontally scroll.

## Configuring the maximum height of the Filter Picker

To add a maximum height to the Filter Picker, which, in turn, allows the picker to be scrolled, you may use the `->filterPickerMaxHeight()` method, passing a CSS length:

```php theme={null}
AdvancedFilter::make()
    ->filterPickerMaxHeight('240px')
```

## Hiding the filter indicator group labels

When adding multiple filter groups ("or" groups), an the Filter Group number (ie "Filter Group 1") will be prepended to the indicator to help differentiate between the different filter groups. You may disable this by passing `false` to the `->prependFilterGroupLabels()` method:

```php theme={null}
 AdvancedFilter::make()
    ->prependFilterGroupLabels(false)
```

You may also hide the filter group label when there is only one filter group:

```php theme={null}
 AdvancedFilter::make()
    ->prependFilterGroupLabels(prependFilterGroupLabelWhenSoleGroup: false)
```

And of course, this can be set globally in your service provider:

```php theme={null}
AdvancedFilter::configureUsing(function (AdvancedFilter $filter) {
    return $filter->prependFilterGroupLabels(prependFilterGroupLabelWhenSoleGroup: false); 
}); 
```

> Tip: The name/translation of the label can be modified in the language file.

## Customizing the sequence of filter indicator group colors

When adding multiple filter groups ("or" groups), the indicators will be displayed in different colors to help differentiate between the different filter groups. By default, the indicators will be colored in the following sequence: `primary`, `info`, `gray`,  `success`, `danger`, `warning`. You may choose a different sequence by passing an array of colors to the `->indicatorColors()` method:

```php theme={null}
AdvancedFilter::make()
    ->indicatorColors(['info', 'success'])
```

Any default color that is not defined in the array will be appended after the last defined color.

## Customizing the buttons and labels

You may customize Advanced Filter Builders buttons, labels, and filter operators in the [language file](/v5/configuration/additional-configurations#language-files).
