secretwebmaster / laravel-optionable
Allow any Eloquent model to have own options such as user options, page options, etc.
Installs: 104
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/secretwebmaster/laravel-optionable
Requires
- php: ^8.2
- illuminate/database: ^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^10.0
- phpunit/phpunit: ^11.5
README
Laravel Optionable adds flexible, structured option storage to any Eloquent model. Options are stored in a dedicated table with support for:
- scope (e.g.
theme,template,seo) - group (e.g. section or nested context)
- repeatable items with
sort - nested JSON option values
- fallbacks
- translation support (via HasTranslations)
This package powers advanced option systems such as WNCMS theme options, page template options, and model metadata.
Installation
composer require secretwebmaster/laravel-optionable php artisan migrate
Usage
Add HasOptions to any Eloquent model:
use Illuminate\Database\Eloquent\Model; use Secretwebmaster\LaravelOptionable\Traits\HasOptions; class Page extends Model { use HasOptions; }
You may now store unlimited structured options on this model.
Getting Options
Get all rows (optional scope/group)
$rows = $page->getOptions(); $rows = $page->getOptions('theme'); $rows = $page->getOptions('theme', 'header');
Returns a sorted Collection of Option rows.
Get a single option value
$value = $page->getOption('title', 'theme');
Or with group:
$value = $page->getOption('button_text', 'theme', 'hero');
Fallback support:
$value = $page->getOption('color', 'theme', 'footer', 'default-color');
Allow null values:
$page->getOption('logo', 'theme', null, null, false);
Setting Options
Set a single option
$page->setOption('title', 'Hello World', 'theme');
With group and sort:
$page->setOption('image', '/a.jpg', 'theme', 'gallery', 0); $page->setOption('image', '/b.jpg', 'theme', 'gallery', 1);
Set multiple options for a scope/group
$page->setOptions('theme', 'hero', [ ['key' => 'title', 'value' => 'Welcome'], ['key' => 'subtitle', 'value' => 'Enjoy'], ['key' => 'button_text', 'value' => 'Click'], ]);
This clears existing options under that scope/group first.
Deleting Options
Delete a single option
$page->deleteOption('title', 'theme');
With group and sort:
$page->deleteOption('image', 'theme', 'gallery', 1);
Clear all options under a scope/group
$page->clearOptions('theme', 'hero');
Table Schema (v2)
The migration creates:
| Column | Type | Description |
|---|---|---|
| id | bigint | primary key |
| scope | string nullable | Option namespace (e.g. theme/template/seo) |
| group | string nullable | Optional subgroup |
| key | string | Option key |
| sort | integer nullable | Repeatable index |
| value | text/json | Value (translated or raw) |
| is_translatable | boolean | Whether value uses HasTranslations |
| optionable_type | string | Morph type |
| optionable_id | bigint | Morph id |
| timestamps | — | — |
Indexes:
scope + group + key + sort + optionable_type + optionable_id- polymorphic indexes
Legacy Support (v1)
Snake_case method names continue to work for all methods that still exist in v2, thanks to the __call() snake_case fallback.
Supported snake_case aliases:
- get_option()
- set_option()
- get_options()
- set_options()
- delete_option()
- clear_options()
The following v1 methods have been removed and no longer exist:
- deleteOptions()
- deleteAllOptions() Therefore their snake_case forms (delete_options(), delete_all_options()) are not available.