Documentation Index
Fetch the complete documentation index at: https://docs.laravelshopper.dev/llms.txt
Use this file to discover all available pages before exploring further.
Attributes define product characteristics like Color, Size, or Material. They enable variable products, enhance filtering, and provide detailed product specifications.
Models
Shopper uses three models to manage attributes:
| Model | Purpose |
|---|
Shopper\Core\Models\Attribute | The attribute definition (Color, Size, Material) |
Shopper\Core\Models\AttributeValue | Possible values for an attribute (Red, Blue, Large) |
Shopper\Core\Models\AttributeProduct | Pivot linking attributes to products with a selected value |
The Attribute model implements Shopper\Core\Models\Contracts\Attribute and uses the HasSlug trait for automatic slug generation. Unlike products or brands, the Attribute model is not configurable via config/shopper/models.php and has no admin model wrapper.
Database Schema
Attribute Table
| Column | Type | Nullable | Default | Description |
|---|
id | bigint | no | auto | Primary key |
name | string | no | - | Attribute name |
slug | string | yes | auto | URL-friendly identifier (unique) |
description | string | yes | null | Attribute description |
type | string | no | - | Field type enum value |
icon | string | yes | null | Icon identifier |
is_enabled | boolean | no | false | Attribute visibility |
is_searchable | boolean | no | false | Include in search |
is_filterable | boolean | no | false | Show in filters |
created_at | timestamp | yes | null | Creation timestamp |
updated_at | timestamp | yes | null | Last update timestamp |
AttributeValue Table
| Column | Type | Nullable | Default | Description |
|---|
id | bigint | no | auto | Primary key |
value | string(50) | no | - | Display value |
key | string | no | - | Unique identifier key |
position | smallint | yes | 1 | Display order |
attribute_id | bigint | no | - | Foreign key to attribute |
AttributeProduct Table (Pivot)
| Column | Type | Nullable | Description |
|---|
id | bigint | no | Primary key |
attribute_id | bigint | no | Foreign key to attribute |
product_id | bigint | no | Foreign key to product |
attribute_value_id | bigint | yes | Foreign key to attribute value |
attribute_custom_value | longtext | yes | Custom value for text-based attributes |
Field Types
Attributes use the FieldType enum to determine input behavior:
use Shopper\Core\Enum\FieldType;
FieldType::Checkbox // Multiple selectable values
FieldType::ColorPicker // Color selection
FieldType::DatePicker // Date input
FieldType::RichText // Rich text editor
FieldType::Select // Single selection dropdown
FieldType::Text // Single-line text input
FieldType::Number // Numeric input
| Type | Database Value | Has Predefined Values | Description |
|---|
| Checkbox | checkbox | Yes | Multiple values can be selected |
| ColorPicker | colorpicker | Yes | Color values with picker |
| DatePicker | datepicker | No | Date input field |
| RichText | richtext | No | HTML content editor |
| Select | select | Yes | Single value selection |
| Text | text | No | Free text input |
| Number | number | No | Integer or decimal input |
Type Checking Methods
Each attribute type has helper methods to determine its behavior:
$attribute->hasMultipleValues();
$attribute->hasSingleValue();
$attribute->hasTextValue();
Attribute::fieldsWithValues();
hasMultipleValues() returns true for Checkbox and ColorPicker. hasSingleValue() returns true for Select. hasTextValue() returns true for Text, Number, RichText, and DatePicker. fieldsWithValues() returns the types that require predefined values.
Relationships
Values
To add values to an attribute:
$attribute->values()->create([
'value' => 'Red',
'key' => 'color-red',
'position' => 1,
]);
$attribute->values()->createMany([
['value' => 'Small', 'key' => 'size-s', 'position' => 1],
['value' => 'Medium', 'key' => 'size-m', 'position' => 2],
['value' => 'Large', 'key' => 'size-l', 'position' => 3],
]);
Products
Attach an attribute to a product with a predefined value:
$attribute->products()->attach($productId, [
'attribute_value_id' => $valueId,
]);
Or with a custom value:
$attribute->products()->attach($productId, [
'attribute_custom_value' => 'Custom specification',
]);
Variants (AttributeValue)
AttributeValue can be linked to product variants:
$attributeValue->variants;
$attributeValue->variants()->attach($variantId);
Slug & Lookup
The HasSlug trait generates unique slugs automatically and provides a findBySlug() static method:
use Shopper\Core\Models\Attribute;
$attribute = Attribute::findBySlug('color');
Query Scopes
Filter attributes by their visibility and behavior flags:
use Shopper\Core\Models\Attribute;
Attribute::query()->enabled()->get();
Attribute::query()->isFilterable()->get();
Attribute::query()->isSearchable()->get();
Scopes can be combined:
Attribute::query()
->enabled()
->isFilterable()
->with('values')
->get();
Status Management
$attribute->updateStatus(true);
$attribute->updateStatus(false);
Display Helpers
$attribute->type_formatted;
Attribute::typesFields();
type_formatted returns a translated label like “Checkbox”. typesFields() returns all available types with their labels.
Working with AttributeProduct
The AttributeProduct model provides a computed real_value accessor:
use Shopper\Core\Models\AttributeProduct;
$attributeProduct = AttributeProduct::query()->find($id);
// Get the actual value (custom or from value relationship)
$attributeProduct->real_value;
// Returns attribute_custom_value if set, otherwise value->value
Creating Attributes
Attribute with Predefined Values
use Shopper\Core\Models\Attribute;
use Shopper\Core\Enum\FieldType;
// Create a color attribute
$color = Attribute::query()->create([
'name' => 'Color',
'slug' => 'color',
'type' => FieldType::ColorPicker,
'is_enabled' => true,
'is_filterable' => true,
]);
// Add color values
$color->values()->createMany([
['value' => 'Red', 'key' => 'red', 'position' => 1],
['value' => 'Blue', 'key' => 'blue', 'position' => 2],
['value' => 'Green', 'key' => 'green', 'position' => 3],
]);
Attribute with Free Text
// Create a text attribute (no predefined values needed)
$material = Attribute::query()->create([
'name' => 'Material',
'slug' => 'material',
'type' => FieldType::Text,
'is_enabled' => true,
'is_searchable' => true,
]);
Assigning Attributes to Products
use Shopper\Models\Product;
$product = Product::query()->find($id);
// Assign attribute with predefined value (via options relationship)
$product->options()->attach($attributeId, [
'attribute_value_id' => $valueId,
]);
// Assign attribute with custom value
$product->options()->attach($attributeId, [
'attribute_custom_value' => '100% Cotton',
]);
// Get product attributes with values
foreach ($product->options as $attribute) {
$valueId = $attribute->pivot->attribute_value_id;
$customValue = $attribute->pivot->attribute_custom_value;
}
Retrieving Attributes
use Shopper\Core\Models\Attribute;
// Get all enabled attributes with values
$attributes = Attribute::query()
->enabled()
->with('values')
->get();
// Get filterable attributes for storefront
$filters = Attribute::query()
->enabled()
->isFilterable()
->with(['values' => fn ($q) => $q->orderBy('position')])
->get();
// Get attribute by slug
$size = Attribute::findBySlug('size');
$size->load('values');
Observer Behavior
The AttributeObserver handles cleanup when deleting:
// When an attribute is deleted:
// 1. All product associations are detached
// 2. All attribute values are deleted
$attribute->delete(); // Triggers observer cleanup
Disabling Attribute Feature
// config/shopper/features.php
use Shopper\Enum\FeatureState;
return [
'attribute' => FeatureState::Disabled,
];
Permissions
The admin panel generates five permissions for attribute management:
| Permission | Description |
|---|
browse_attributes | View the attributes list |
read_attributes | View a single attribute |
add_attributes | Create new attributes |
edit_attributes | Edit existing attributes |
delete_attributes | Delete attributes |
Components
Attribute components are part of the product configuration. To customize them:
php artisan shopper:component:publish product
Attribute-related components in config/shopper/components/product.php:
use Shopper\Livewire;
return [
'pages' => [
// ...
'attribute-index' => Livewire\Pages\Attribute\Browse::class,
],
'components' => [
// ...
'slide-overs.attribute-form' => Livewire\SlideOvers\AttributeForm::class,
'slide-overs.choose-product-attributes' => Livewire\SlideOvers\ChooseProductAttributes::class,
'slide-overs.attribute-values' => Livewire\SlideOvers\AttributeValues::class,
],
];
Storefront Example
namespace App\Http\Controllers;
use Shopper\Core\Models\Attribute;
use Shopper\Models\Product;
class ProductFilterController extends Controller
{
public function index()
{
// Get filterable attributes for sidebar
$filters = Attribute::query()
->enabled()
->isFilterable()
->with(['values' => fn ($q) => $q->orderBy('position')])
->get();
return view('products.index', compact('filters'));
}
public function filter(Request $request)
{
$query = Product::query()->publish();
foreach ($request->input('attributes', []) as $slug => $values) {
$query->whereHas('options', function ($q) use ($slug, $values) {
$q->where('slug', $slug)
->wherePivotIn('attribute_value_id', $values);
});
}
return $query->paginate(12);
}
}
Use Cases
| Attribute Type | Example | Use Case |
|---|
| Checkbox | Size | Multiple sizes available for clothing |
| ColorPicker | Color | Product color options |
| Select | Material | Single material selection |
| Text | SKU Suffix | Custom text per product |
| Number | Weight | Numeric specifications |
| DatePicker | Release Date | Product launch date |
| RichText | Care Instructions | Detailed HTML content |