Documentation Index
Fetch the complete documentation index at: https://docs.lunarphp.com/llms.txt
Use this file to discover all available pages before exploring further.
Attributes store custom, translatable data against Eloquent models using configurable field types.
Overview
Attributes allow custom data to be stored against Eloquent models. They are most commonly used with products, where different information needs to be stored and presented to visitors.
For example, a television might have the following attributes assigned:
- Screen Size
- Screen Technology
- Tuner
- Resolution
Attributes are organized into Attribute Groups for display purposes. A group like “SEO” might contain attributes for “Meta Title” and “Meta Description”.
Attribute Groups
Lunar\Models\AttributeGroup
Attribute groups form a logical collection of attributes. Each group belongs to a specific model type (e.g. products, collections, customers).
Fields
| Field | Type | Description |
|---|
id | id | Primary key |
attributable_type | string | The morph map name of the model type this group belongs to (e.g. product) |
name | json | Translated name, e.g. {"en": "SEO"} |
handle | string | Kebab-cased reference, e.g. seo. Must be unique |
position | integer | Sort order of the group |
created_at | timestamp | |
updated_at | timestamp | |
Relationships
| Relationship | Type | Related Model | Description |
|---|
attributes | HasMany | Lunar\Models\Attribute | All attributes in this group, ordered by position |
Attributes
Fields
| Field | Type | Description |
|---|
id | id | Primary key |
attribute_type | string | The morph map name of the model type that can use this attribute, e.g. product |
attribute_group_id | foreignId | The associated attribute group |
position | integer | Sort order within the attribute group |
name | json | Translated name, e.g. {"en": "Screen Size"} |
description | json nullable | Translated description |
handle | string | Kebab-cased reference, e.g. screen-size. Unique per attribute_type |
section | string nullable | An optional label to define where an attribute should be used in the UI |
type | string | The field type class, e.g. Lunar\FieldTypes\Number |
required | boolean | Whether a value must be provided |
default_value | string nullable | Default value for the attribute |
configuration | json | Field-type-specific configuration stored as a collection |
system | boolean | If true, the attribute should not be deleted |
validation_rules | string nullable | Laravel validation rules, e.g. required|max:255 |
filterable | boolean | Whether the attribute can be used for filtering (default false) |
searchable | boolean | Whether the attribute is included in search indexing (default true) |
created_at | timestamp | |
updated_at | timestamp | |
Relationships
| Relationship | Type | Related Model | Description |
|---|
attributeGroup | BelongsTo | Lunar\Models\AttributeGroup | The group this attribute belongs to |
Scopes
| Scope | Description |
|---|
system(string $type) | Filter to system attributes for a given model type |
Field Types
Field types determine how an attribute’s value is stored and retrieved. Each type implements the Lunar\Base\FieldType interface.
| Type | Description |
|---|
Lunar\FieldTypes\Text | Single-line, multi-line, or rich text |
Lunar\FieldTypes\TranslatedText | Translatable text with a Text value per locale |
Lunar\FieldTypes\Number | Integer or decimal value |
Lunar\FieldTypes\Toggle | Boolean on/off value |
Lunar\FieldTypes\Dropdown | Single selection from a list of predefined options |
Lunar\FieldTypes\ListField | A reorderable list of text values |
Lunar\FieldTypes\File | Single or multiple file references |
Lunar\FieldTypes\YouTube | A YouTube video ID or URL |
Lunar\FieldTypes\Vimeo | A Vimeo video ID or URL |
Custom Field Types
Custom field types can be created by implementing the Lunar\Base\FieldType interface. Once created, the field type should be registered with the FieldTypeManifest in a service provider:
use Lunar\Facades\FieldTypeManifest;
FieldTypeManifest::add(\App\FieldTypes\CustomField::class);
To make a custom field type editable in the admin panel, a corresponding Filament component and Livewire synthesizer are also needed. See Extending Attributes for a full walkthrough.
Models That Use Attributes
The following models support attributes out of the box:
Lunar\Models\Product
Lunar\Models\ProductVariant
Lunar\Models\Collection
Lunar\Models\Customer
Lunar\Models\Brand
Lunar\Models\CustomerGroup
Saving Attribute Data
Attribute values are stored in an attribute_data JSON column on the model. Each key is an attribute handle, and each value is a field type instance.
use Lunar\FieldTypes\Number;
use Lunar\FieldTypes\Text;
use Lunar\FieldTypes\TranslatedText;
$product->attribute_data = collect([
'meta_title' => new Text('The best screwdriver you will ever buy!'),
'pack_qty' => new Number(2),
'description' => new TranslatedText(collect([
'en' => new Text('Blue'),
'fr' => new Text('Bleu'),
])),
]);
$product->save();
Accessing Attribute Data
When the attribute_data property is accessed, it is cast to a collection of field type instances.
dump($product->attribute_data);
Illuminate\Support\Collection {#1522
#items: array:2 [
"name" => Lunar\FieldTypes\TranslatedText {#1533
#value: Illuminate\Support\Collection {#1505
#items: array:3 [
"de" => Lunar\FieldTypes\Text {#1506
#value: "Leren laarzen"
}
"en" => Lunar\FieldTypes\Text {#1514
#value: "Leather boots"
}
"fr" => Lunar\FieldTypes\Text {#1502
#value: "Bottes en cuir"
}
]
}
}
"description" => Lunar\FieldTypes\Text {#1537
#value: "<p>I'm a description!</p>"
}
]
}
Retrieving a Single Attribute Value
The translateAttribute method returns the resolved value for a single attribute. For TranslatedText fields, it resolves the correct locale automatically.
// Returns the value for the current app locale
$product->translateAttribute('name');
// Returns the French translation
$product->translateAttribute('name', 'fr');
// Falls back to the first available value
$product->translateAttribute('name', 'FOO');
The shorthand attr method does the same thing:
$product->attr('name');
$product->attr('name', 'fr');
For non-translatable fields, translateAttribute returns the raw value directly:
// Returns the integer value
$product->translateAttribute('pack_qty');
Adding Attributes to a Custom Model
To make a custom model support attributes:
- Add the
HasAttributes trait.
- Cast the
attribute_data column using AsAttributeData.
- Add an
attribute_data JSON column to the model’s database table.
use Lunar\Base\Casts\AsAttributeData;
use Lunar\Base\Traits\HasAttributes;
use Lunar\Base\Traits\HasTranslations;
class MyModel extends Model
{
use HasAttributes;
use HasTranslations;
protected $casts = [
'attribute_data' => AsAttributeData::class,
];
}
Then add the JSON column via a migration:
Schema::table('my_models', function (Blueprint $table) {
$table->json('attribute_data')->nullable();
});
Finally, register the model as an attributable type so that attribute groups and attributes can be created for it:
use Lunar\Facades\AttributeManifest;
// In a service provider's boot method
AttributeManifest::addType(\App\Models\MyModel::class);
Attribute Manifest
The AttributeManifest manages which model types support attributes and provides access to searchable attribute data.
use Lunar\Facades\AttributeManifest;
// Get all registered attributable types
$types = AttributeManifest::getTypes();
// Get a specific type by key (lowercase class basename)
$type = AttributeManifest::getType('product');
// Register a new attributable type
AttributeManifest::addType(\App\Models\MyModel::class);
// Get all searchable attributes for a model type
$searchable = AttributeManifest::getSearchableAttributes('product');