Skip to main content
Attributes store custom 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”. An attribute is not tied to a single model. Instead, it declares which model types it can appear on (for example product and brand), and ProductType records separately declare which of those attributes each product type actually presents to its products and variants.

Attribute Groups

Attribute groups form a logical collection of attributes.

Fields

Relationships

Attributes

Fields

Relationships

Scopes

Methods

Which model types an attribute applies to

Lunar\Core\Models\Attribute does not carry a morph column for the model type it belongs to. Instead, each attribute has a models relationship to Lunar\Core\Models\AttributeModel, a simple table pairing an attribute_id with a model_type string (the morph alias, e.g. product, brand, collection). An attribute can apply to more than one model type.
The recommended way to create or update an attribute together with its model types is through the CreatesAttribute / UpdatesAttribute action contracts, which accept a model_types key and manage the AttributeModel rows for you.

Attributes on a Product Type

Lunar\Core\Models\ProductType declares which of the available attributes it exposes to its products and variants, through the product_type_attribute pivot table (the attributeMapping relationship). This is a separate concern from AttributeModel: AttributeModel says which model type an attribute is valid for; ProductType says which of those attributes a specific product type actually presents.

Field Types

Field types determine how an attribute’s value is stored and retrieved. Each type implements Lunar\Core\Contracts\FieldType and extends Lunar\Core\FieldTypes\AbstractFieldType. These type keys are backed by Lunar\Core\Enums\FieldTypeEnum, which is the source of the default entries in the FieldTypeManifest. Each field type can describe its own configuration through two methods on the FieldType contract:
  • getConfig() returns the validation rules for the attribute’s configuration array.
  • getConfigurationFields() returns a renderer-agnostic description of the configuration inputs (a key, an input type such as text, number, toggle, select, tags, or lookups, and a label), which an admin UI can use to build the attribute’s configuration form.

Custom Field Types

Custom field types can be created by extending Lunar\Core\FieldTypes\AbstractFieldType (or implementing Lunar\Core\Contracts\FieldType directly) and registering the type with the FieldTypeManifest in a service provider:
The first argument is the type key stored in attributes.type; the second is the field type class. To make a custom field type editable in the admin panel, a corresponding admin component is also needed.

Models That Use Attributes

The following models support attributes out of the box, via the Lunar\Core\Models\Concerns\HasAttributeData trait:
  • Lunar\Core\Models\Product
  • Lunar\Core\Models\ProductVariant
  • Lunar\Core\Models\ProductType
  • Lunar\Core\Models\Collection
  • Lunar\Core\Models\Customer
  • Lunar\Core\Models\Brand
  • Lunar\Core\Models\CustomerGroup

Saving Attribute Data

Attribute values are stored in an attribute_data JSON column on the model. On disk, values are stored keyed by the attribute’s numeric id, so renaming an attribute’s handle never disconnects stored data. When assigning or reading the column, use the attribute’s handle as the key: the Lunar\Core\Casts\AsAttributeData cast resolves handles to ids (and back) via an internal AttributeCache.

Accessing Attribute Data

When the attribute_data property is accessed, it is hydrated into a collection of field type instances keyed by handle.

Retrieving a Single Attribute Value

The translateAttribute method, from the HasAttributeData trait, returns the resolved value for a single attribute. For TranslatedText fields, it resolves the correct locale automatically, falling back to the first available value.
The shorthand attr method does the same thing:
For non-translatable fields, translateAttribute returns the raw value directly:

All attributes mapped to a model

The mappedAttributes() method (also exposed as the mappedAttributes accessor) returns every Attribute whose models relationship includes the calling model’s morph type, ordered by position.

Validation Rules

An attribute can carry its own Laravel validation rules in validation_rules, stored as a list of rule strings (for example ['min:1', 'max:10']). Core stores and exposes these rules; it does not enforce them automatically when attribute_data is written outside of an admin panel — enforcement is the responsibility of the editing surface (the Filament and Inertia admin panels apply them to their attribute forms). Lunar\Core\Rules\ValidRuleString is a Laravel validation rule that checks a rule string is well-formed (a recognized rule name with valid parameters), useful when building a form that lets staff author validation_rules entries.

Adding Attributes to a Custom Model

To make a custom model support attributes:
  1. Add the HasAttributeData trait.
  2. Add an attribute_data JSON column to the model’s database table.
  3. Register the model as an attributable type so that attributes can target it.
The HasAttributeData trait merges the attribute_data cast automatically, so no $casts entry is needed.
Finally, register the model as an attributable type so that attributes and the admin UI know it exists:

Attribute Manifest

Lunar\Core\Manifests\AttributeManifest, accessed through the Lunar\Core\Facades\AttributeManifest facade, manages which model types support attributes and caches searchable attribute lookups per type.
Product, ProductVariant, ProductType, Collection, Customer, Brand, and CustomerGroup are registered as attributable types out of the box.