Skip to main content

Create a Simple Settings Page with Filament

· 6 min read
Luis Güette

Recently, I had to create a simple settings page to manage general settings for a website with Filament. Filament is a Laravel-based admin panel that provides an intuitive interface for managing your application's data.

In this blog post, I'll walk you through the steps I took to create the settings page, including how to use migrations to store the data, how to update the settings from the Filament admin panel, and how to dynamically build the edit form depending on the setting type.

Creating the Settings Table

First, we need to create a settings table to store the data. We'll use migrations to create the table with the necessary columns. Instead of using an id column, we'll use key as a primary column, which will make it easier to identify the settings. We'll also include columns for the label, value, type, and attributes. We'll also create multiple settings to be able to test. Here's the content of the migration file:

<?php

use App\Models\Setting;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('settings', function (Blueprint $table) {
$table->string('key')->primary();
$table->string('label');
$table->text('value')->nullable();
$table->json('attributes')->nullable();
$table->string('type');

$table->timestamps();
});

Setting::create([
'key' => 'site_name',
'label' => 'Site Name',
'value' => null,
'type' => 'text',
]);

Setting::create([
'key' => 'basic_plan_price',
'label' => 'Basic Plan Price',
'value' => 1000,
'type' => 'number',
]);

Setting::create([
'key' => 'pro_plan_price',
'label' => 'Pro Plan Price',
'value' => 2000,
'type' => 'number',
]);

Setting::create([
'key' => 'environment',
'label' => 'Environment',
'value' => 'production',
'type' => 'select',
'attributes' => [
'options' => [
'production' => 'Production',
'staging' => 'Staging',
'local' => 'Local',
],
],
]);
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('settings');
}
};

Creating the Setting Model

Next, we need to create a Setting model to interact with the settings table. As we are using a non-standard column as the primary key, we need to customize the model a little bit. We set the $primaryKey attribute to key which is the name of our primary column, and we also set $incrementing attribute to false so Laravel doesn't automatically set our primary key with an incrementing integer. We also cast the attributes column as an array as this is a json column.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Setting extends Model
{
protected $primaryKey = 'key';

public $incrementing = false;

protected $fillable = [
'key',
'label',
'value',
'type',
'attributes',
];

protected $casts = [
'attributes' => 'array',
];
}

Creating the Filament Resource

With the settings table and Setting model in place, we can now create a Filament resource to manage our settings. We can use the make:filament-resource command to create the resource:

php artisan make:filament-resource Settings --simple

We use the --simple option to manage our settings on one page using modals. This command will create two files, ManageSettings.php and SettingsResource.php.

In ManageSettings.php, we remove the getActions() method because we don't need it in our case.

<?php

namespace App\Filament\Resources\SettingsResource\Pages;

use App\Filament\Resources\SettingsResource;
use Filament\Resources\Pages\ManageRecords;

class ManageSettings extends ManageRecords
{
protected static string $resource = SettingsResource::class;
}

In SettingsResource.php, we update the $model attribute with the Setting model class and namespace.

<?php

namespace App\Filament\Resources;

use App\Models\Setting;
use Filament\Resources\Resource;

class SettingsResource extends Resource
{
protected static ?string $model = Setting::class;

protected static ?string $navigationIcon = 'heroicon-o-collection';

//...
}

We also override the canCreate() method to set it to false because we don't want to create settings from the control panel.

<?php

namespace App\Filament\Resources;

use App\Models\Setting;
use Filament\Resources\Resource;

class SettingsResource extends Resource
{
//...

public static function canCreate(): bool
{
return false;
}

//...
}

In the table() method, we define the columns we want to display in the settings table. We make the label and value columns sortable and searchable, and we use the formatStateUsing() method to show Empty when the value is null. We also customize the EditAction with a custom form by adding the form() method. Depending on the setting type, we return the correct input.

<?php

namespace App\Filament\Resources;

use App\Filament\Resources\SettingsResource\Pages;
use App\Models\Setting;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;

class SettingsResource extends Resource
{
//...

public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('label')
->sortable()
->searchable(),

Tables\Columns\TextColumn::make('value')
->formatStateUsing(fn ($state) => $state === null ? 'Empty' : $state)
->sortable()
->searchable(),
])
->actions([
Tables\Actions\EditAction::make()
->form(function (Setting $record) {
return match ($record->type) {
'select' => [
Select::make('value')
->label($record->label)
->options($record->attributes['options'])
],
'number' => [
TextInput::make('value')
->label($record->label)
->type('number')
],
default => [
TextInput::make('value')
->label($record->label)
]
};
}),
]);
}

//...
}

The final result

Go to the settings page in the control panel and you should see something like this:

Settings page

Editing a setting

Conclusion

And that's it! With Filament, creating a simple settings page is a breeze. By using migrations to create the settings table, the Setting model to interact with the table, and Filament to create the resource to manage the settings, we can easily update the settings from the admin panel. And with the ability to dynamically build the edit form depending on the setting type, we can ensure that the user interface is intuitive and easy to use.

I hope this post was helpful in showing you how to create a simple settings page with Filament. If you have any questions or comments, feel free to leave them below!

Krater: Debugging Laravel

Before you go, have you heard about our latest product, Krater?

Krater is a cross-platform desktop application designed as a solution for Laravel developers looking to improve and enhance their debugging experience. If your daily job consists of working with Laravel, you should definitely check this out. You can download Krater here.

We've also released an article about Krater that you might find interesting.

MoonGuard: The Software Creator's Journey

Discover the secrets behind our successful software with our book "MoonGuard: The Software Creator’s Journey" to learn how to create successful Laravel package from scratch! In addition to our website, we also maintain an active presence on Twitter (@moonguard_dev). By following us on Twitter, you'll be the first to know about any breaking news or important announcements regarding MoonGuard. So be sure to check us out and stay connected!