> ## 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 on Eloquent models using configurable field types.

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

```php theme={null}
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

```php theme={null}
Lunar\Models\Attribute
```

### 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:

```php theme={null}
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](/1.x/admin/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.

```php theme={null}
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.

```php theme={null}
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.

```php theme={null}
// 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:

```php theme={null}
$product->attr('name');
$product->attr('name', 'fr');
```

For non-translatable fields, `translateAttribute` returns the raw value directly:

```php theme={null}
// Returns the integer value
$product->translateAttribute('pack_qty');
```

## Adding Attributes to a Custom Model

To make a custom model support attributes:

1. Add the `HasAttributes` trait.
2. Cast the `attribute_data` column using `AsAttributeData`.
3. Add an `attribute_data` JSON column to the model's database table.

```php theme={null}
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:

```php theme={null}
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:

```php theme={null}
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.

```php theme={null}
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');
```
