Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Pixelairport's avatar

Concept for filtering users or other models

I use filament and want to select a user group. I know there are table filters. But with this I will select users by Id and save them. I want to build groups, that can be dynamically.

For example:

  • All users who logged in in last 3 month
  • and who never bought a product
  • and are older than 18 years

This should be dynamic. I will build the scopes in the model, but I need a flexible system for filament to select these filters. Is there a package? At the moment I try to build it on my own. The fields are generated dynamically and I can create Filter-Files which will be used to generate the fields. Each filter has an own file. Hope someone can help. It is more difficult than I thought.

0 likes
6 replies
LaryAI's avatar
Level 58

To achieve dynamic filtering of users in your application using Filament, you can leverage Eloquent query scopes and custom filters. While there might not be a specific package that fits your exact needs, you can build a flexible system by combining Eloquent scopes with Filament's table filters. Here's a step-by-step approach:

  1. Define Eloquent Scopes:

    First, define scopes in your User model to encapsulate the filtering logic. This makes your queries reusable and clean.

    // In User.php model
    public function scopeLoggedInLastThreeMonths($query)
    {
        return $query->where('last_login_at', '>=', now()->subMonths(3));
    }
    
    public function scopeNeverBoughtProduct($query)
    {
        return $query->whereDoesntHave('orders');
    }
    
    public function scopeOlderThan($query, $age)
    {
        return $query->where('birthdate', '<=', now()->subYears($age));
    }
    
  2. Create Custom Filters in Filament:

    Use Filament's table filters to apply these scopes dynamically. You can create a custom filter class or define them directly in your Filament resource.

    // In your Filament resource
    use Filament\Tables\Filters\Filter;
    
    public static function table(Table $table): Table
    {
        return $table
            ->filters([
                Filter::make('Logged In Last 3 Months')
                    ->query(fn ($query) => $query->loggedInLastThreeMonths()),
    
                Filter::make('Never Bought Product')
                    ->query(fn ($query) => $query->neverBoughtProduct()),
    
                Filter::make('Older Than 18')
                    ->query(fn ($query) => $query->olderThan(18)),
            ]);
    }
    
  3. Dynamic Filter System:

    If you want to make this system more dynamic, consider creating a configuration file or database table where you define available filters and their corresponding scopes. You can then loop through these configurations to generate filters dynamically.

    // Example of dynamic filter configuration
    $filters = [
        'Logged In Last 3 Months' => 'loggedInLastThreeMonths',
        'Never Bought Product' => 'neverBoughtProduct',
        'Older Than 18' => fn($query) => $query->olderThan(18),
    ];
    
    // In your Filament resource
    public static function table(Table $table): Table
    {
        $filterDefinitions = [];
    
        foreach ($filters as $label => $scope) {
            $filterDefinitions[] = Filter::make($label)
                ->query(is_callable($scope) ? $scope : fn($query) => $query->$scope());
        }
    
        return $table->filters($filterDefinitions);
    }
    

This approach allows you to define and manage filters dynamically, making it easier to add or modify filters without changing the core logic of your application.

Pixelairport's avatar

That would be the best solution, but then I have to select specific models. Or is there a way to save the filters I select, combine them and save them into segments? Because these segments should be used later. I dont want to search for users at the table, I want to build segments.

For example: I create a transactional email which will be send every month. There are the newest blog articles in it. But I only want to send this mail to:

  • Users who were logged in in the last 12 month
  • And who also bought a product at our website

Im not sure what is the best way. I thougt with scopes. And if I could save the selected filters instead of seeing the results in the filmanet table to select the model items, that would be the best thing, I think.

Pixelairport's avatar

At the moment I think about that the easiest way would be, to use table (e.g. user table) with filters would be the easiest way. Is there a way, to have a button at the filters or the table with "Save Filters", remove the select boxes at the beginning (i dont want to select users, i just want to see who will be selected) and then get all filters to store them in the database to use them later?

Pixelairport's avatar

Filters are what I want in a form. But I want to show the table with the filters in the form and just save the selected filters not the selected model items (users). I could use relations, but I don't want to have a relation, because there is no.

I my package I create a email, which should be send to users at a later time. So the result of the filters will change from time to time. The filters should be saved and at the time the mail is send, the filters will get the correct users.

At the moment I have build an extra form with filters I can add manually. But I think it would be better to use the filter system of filament to avoid too much code.

Does anybody have an idea or did something like this already?

Pixelairport's avatar

I think best would be a repeater in my form, where I can choose filters, which i normally have in users table. On my user resource for example, I can choose useres who bought something the last X month. I want this filter also saved in my form. And when i send the email, the code will see the filters and select the users while sending not before when i select the filters.

Please or to participate in this conversation.