├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── resources ├── lang │ ├── ar │ │ └── translations.php │ ├── en │ │ └── translations.php │ └── nl │ │ └── translations.php └── views │ └── filament │ └── pages │ └── settings.blade.php └── src ├── Filament ├── Pages │ └── Settings.php └── Plugins │ └── FilamentSettingsPlugin.php ├── FilamentSettingsServiceProvider.php └── Helpers └── helpers.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.vscode 3 | /vendor 4 | /node_modules 5 | package-lock.json 6 | composer.phar 7 | composer.lock 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `filament-settings` will be documented in this file. 4 | 5 | ## 1.3.0 - 2025-02-27 6 | 7 | ### Added 8 | 9 | - Added support for Laravel 12. 10 | 11 | ## 1.2.0 - 2024-03-25 12 | 13 | ### Changed 14 | 15 | - Set the static string `$view` instead of overriding the `getView` method in the base Settings page. 16 | 17 | ## 1.1.1 - 2024-03-12 18 | 19 | ### Added 20 | 21 | - Added support for Laravel 11. 22 | 23 | ## 1.1.0 - 2024-02-21 24 | 25 | ### Fixed 26 | 27 | - Filament fields that return arrays will now correctly be saved as one Setting entry instead of multiple. This is done so that editing the field in the settings panel will correctly update the field value in the database. (EG: Select with multiple values will now be saved as a single JSON array instead of multiple rows in the database. So that when you remove one of the values, it will correctly update the database.) 28 | 29 | ## 1.0.0 - 2024-02-11 30 | 31 | - Initial release 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Outerweb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Filament Settings 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/outerweb/filament-settings.svg?style=flat-square)](https://packagist.org/packages/outerweb/filament-settings) 4 | [![Total Downloads](https://img.shields.io/packagist/dt/outerweb/filament-settings.svg?style=flat-square)](https://packagist.org/packages/outerweb/filament-settings) 5 | 6 | This package adds a way to interact with outerweb/settings in Filament. 7 | 8 | ## Installation 9 | 10 | You can install the package via composer: 11 | 12 | ```bash 13 | composer require outerweb/filament-settings 14 | ``` 15 | 16 | Configure the Outerweb/Settings package as described in the [Settings documentation](https://github.com/outer-web/settings). 17 | 18 | Add the plugin to your desired Filament panel: 19 | 20 | ```php 21 | use Outerweb\FilamentSettings\Filament\Plugins\FilamentSettingsPlugin; 22 | 23 | class FilamentPanelProvider extends PanelProvider 24 | { 25 | public function panel(Panel $panel): Panel 26 | { 27 | return $panel 28 | // ... 29 | ->plugins([ 30 | FilamentSettingsPlugin::make() 31 | ->pages([ 32 | // Add your own setting pages here 33 | ]) 34 | ]); 35 | } 36 | } 37 | ``` 38 | 39 | ## Usage 40 | 41 | Create a settings page at 'app/Filament/Pages/Settings/Settings.php': 42 | 43 | ```php 44 | namespace App\Filament\Pages\Settings; 45 | 46 | use Closure; 47 | use Filament\Forms\Components\Tabs; 48 | use Filament\Forms\Components\TextInput; 49 | use Outerweb\FilamentSettings\Filament\Pages\Settings as BaseSettings; 50 | 51 | class Settings extends BaseSettings 52 | { 53 | public function schema(): array|Closure 54 | { 55 | return [ 56 | Tabs::make('Settings') 57 | ->schema([ 58 | Tabs\Tab::make('General') 59 | ->schema([ 60 | TextInput::make('general.brand_name') 61 | ->required(), 62 | ]), 63 | Tabs\Tab::make('Seo') 64 | ->schema([ 65 | TextInput::make('seo.title') 66 | ->required(), 67 | TextInput::make('seo.description') 68 | ->required(), 69 | ]), 70 | ]), 71 | ]; 72 | } 73 | } 74 | ``` 75 | 76 | Register the setting page in the FilamentServiceProvider: 77 | 78 | ```php 79 | use Outerweb\FilamentSettings\Filament\Plugins\FilamentSettingsPlugin; 80 | 81 | class FilamentPanelProvider extends PanelProvider 82 | { 83 | public function panel(Panel $panel): Panel 84 | { 85 | return $panel 86 | // ... 87 | ->plugins([ 88 | FilamentSettingsPlugin::make() 89 | ->pages([ 90 | App\Filament\Pages\Settings\Settings::class, 91 | ]) 92 | ]); 93 | } 94 | } 95 | ``` 96 | 97 | You can add as many setting pages as you want. But when you do, make sure to override the `public static function getNavigationLabel() : string` method on your settings page. This is because multiple pages with the same navigation label will override each other in the Filament navigation. 98 | 99 | ### Changing the navigation label 100 | 101 | You can change the navigation label by overriding the `getNavigationLabel` method: 102 | 103 | ```php 104 | namespace App\Filament\Pages\Settings; 105 | 106 | use Outerweb\FilamentSettings\Filament\Pages\Settings as BaseSettings; 107 | 108 | class Settings extends BaseSettings 109 | { 110 | public static function getNavigationLabel(): string 111 | { 112 | return 'Custom label'; 113 | } 114 | } 115 | ``` 116 | 117 | ### Changing the page title 118 | 119 | You can change the page title by overriding the `getTitle` method: 120 | 121 | ```php 122 | namespace App\Filament\Pages\Settings; 123 | 124 | use Outerweb\FilamentSettings\Filament\Pages\Settings as BaseSettings; 125 | 126 | class Settings extends BaseSettings 127 | { 128 | public function getTitle(): string 129 | { 130 | return 'Custom title'; 131 | } 132 | } 133 | ``` 134 | 135 | ## Changelog 136 | 137 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 138 | 139 | ## Credits 140 | 141 | - [Simon Broekaert](https://github.com/SimonBroekaert) 142 | - [All Contributors](../../contributors) 143 | 144 | ## License 145 | 146 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 147 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "outerweb/filament-settings", 3 | "description": "This package adds a way to interact with outerweb/settings in Filament.", 4 | "homepage": "https://github.com/outer-web/filament-settings", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Outerweb", 9 | "email": "info@outerweb.be" 10 | } 11 | ], 12 | "require": { 13 | "php": "^8.0", 14 | "filament/filament": "^3.2", 15 | "laravel/framework": "^10.0|^11.0|^12.0", 16 | "outerweb/settings": "^1.0", 17 | "spatie/laravel-package-tools": "^1.16" 18 | }, 19 | "autoload": { 20 | "psr-4": { 21 | "Outerweb\\FilamentSettings\\": "src/" 22 | }, 23 | "files": [ 24 | "src\\Helpers\\helpers.php" 25 | ] 26 | }, 27 | "extra": { 28 | "laravel": { 29 | "providers": [ 30 | "Outerweb\\FilamentSettings\\FilamentSettingsServiceProvider" 31 | ] 32 | } 33 | }, 34 | "config": { 35 | "sort-packages": true 36 | }, 37 | "minimum-stability": "dev", 38 | "prefer-stable": true 39 | } 40 | -------------------------------------------------------------------------------- /resources/lang/ar/translations.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'actions' => [ 6 | 'save' => 'حفظ التعديلات', 7 | ], 8 | ], 9 | 'page' => [ 10 | 'title' => 'الإعدادات', 11 | 'navigation_label' => 'الإعدادات', 12 | ], 13 | 'notifications' => [ 14 | 'saved' => 'تم الحفظ', 15 | ], 16 | ]; 17 | -------------------------------------------------------------------------------- /resources/lang/en/translations.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'actions' => [ 6 | 'save' => 'Save changes', 7 | ], 8 | ], 9 | 'page' => [ 10 | 'title' => 'Settings', 11 | 'navigation_label' => 'Settings', 12 | ], 13 | 'notifications' => [ 14 | 'saved' => 'Saved', 15 | ], 16 | ]; 17 | -------------------------------------------------------------------------------- /resources/lang/nl/translations.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'actions' => [ 6 | 'save' => 'Wijzigingen opslaan', 7 | ], 8 | ], 9 | 'page' => [ 10 | 'title' => 'Instellingen', 11 | 'navigation_label' => 'Instellingen', 12 | ], 13 | 'notifications' => [ 14 | 'saved' => 'Opgeslagen', 15 | ], 16 | ]; 17 | -------------------------------------------------------------------------------- /resources/views/filament/pages/settings.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ $this->form }} 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Filament/Pages/Settings.php: -------------------------------------------------------------------------------- 1 | schema($this->schema()) 56 | ->statePath('data'); 57 | } 58 | 59 | public function getFormActions() : array 60 | { 61 | return [ 62 | Action::make('save') 63 | ->label(__('filament-settings::translations.form.actions.save')) 64 | ->submit('data') 65 | ->keyBindings(['mod+s']) 66 | ]; 67 | } 68 | 69 | public function mount() : void 70 | { 71 | $this->fillForm(); 72 | } 73 | 74 | protected function fillForm() : void 75 | { 76 | $data = Setting::get(); 77 | 78 | $this->callHook('beforeFill'); 79 | 80 | $this->form->fill($data); 81 | 82 | $this->callHook('afterFill'); 83 | } 84 | 85 | public function save() : void 86 | { 87 | try { 88 | $this->callHook('beforeValidate'); 89 | 90 | $fields = collect($this->form->getFlatFields(true)); 91 | $fieldsWithNestedFields = $fields->filter(fn (Field $field) => count($field->getChildComponents()) > 0); 92 | 93 | $fieldsWithNestedFields->each(function (Field $fieldWithNestedFields, string $fieldWithNestedFieldsKey) use (&$fields) { 94 | $fields = $fields->reject(function (Field $field, string $fieldKey) use ($fieldWithNestedFields, $fieldWithNestedFieldsKey) { 95 | return Str::startsWith($fieldKey, $fieldWithNestedFieldsKey . '.'); 96 | }); 97 | }); 98 | 99 | $data = $fields->mapWithKeys(function (Field $field, string $fieldKey) { 100 | return [$fieldKey => data_get($this->form->getState(), $fieldKey)]; 101 | })->toArray(); 102 | 103 | $this->callHook('afterValidate'); 104 | 105 | $this->callHook('beforeSave'); 106 | 107 | foreach ($data as $key => $value) { 108 | Setting::set($key, $value); 109 | } 110 | 111 | $this->callHook('afterSave'); 112 | } catch (Halt $exception) { 113 | return; 114 | } 115 | 116 | $this->getSavedNotification()?->send(); 117 | 118 | if ($redirectUrl = $this->getRedirectUrl()) { 119 | $this->redirect($redirectUrl, navigate: FilamentView::hasSpaMode() && is_app_url($redirectUrl)); 120 | } 121 | } 122 | 123 | protected function getSavedNotification() : ?Notification 124 | { 125 | $title = $this->getSavedNotificationTitle(); 126 | 127 | if (blank($title)) { 128 | return null; 129 | } 130 | 131 | return Notification::make() 132 | ->success() 133 | ->title($this->getSavedNotificationTitle()); 134 | } 135 | 136 | protected function getSavedNotificationTitle() : ?string 137 | { 138 | return __('filament-settings::translations.notifications.saved'); 139 | } 140 | 141 | protected function getRedirectUrl() : ?string 142 | { 143 | return null; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/Filament/Plugins/FilamentSettingsPlugin.php: -------------------------------------------------------------------------------- 1 | getId()); 20 | } 21 | 22 | public function getPages(): array 23 | { 24 | return $this->pages; 25 | } 26 | 27 | public function pages(array $pages): self 28 | { 29 | $this->pages = $pages; 30 | 31 | return $this; 32 | } 33 | 34 | public function getId(): string 35 | { 36 | return 'outerweb-filament-settings'; 37 | } 38 | 39 | public function register(Panel $panel): void 40 | { 41 | $panel 42 | ->pages($this->getPages()); 43 | } 44 | 45 | public function boot(Panel $panel): void 46 | { 47 | // 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/FilamentSettingsServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('filament-settings') 15 | ->hasTranslations() 16 | ->hasViews() 17 | ->hasInstallCommand(function (InstallCommand $command) { 18 | $composerFile = file_get_contents(__DIR__ . '/../composer.json'); 19 | 20 | if ($composerFile) { 21 | $githubRepo = json_decode($composerFile, true)['homepage'] ?? null; 22 | 23 | if ($githubRepo) { 24 | $command 25 | ->askToStarRepoOnGitHub($githubRepo); 26 | } 27 | } 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Helpers/helpers.php: -------------------------------------------------------------------------------- 1 |