---
title: "Spec sheet (attributes) — Shops for Laravel | Roundly"
description: "Typed, validated, filterable product attributes via attributes-for-laravel — define them in config, then filter and sort the catalogue."
url: https://roundly-consulting.com/open-source/docs/shops-for-laravel/attributes
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Shops for Laravel](https://roundly-consulting.com/open-source/docs/shops-for-laravel.md)

# Spec sheet (attributes)

Products carry a typed, validated spec sheet via attributes-for-laravel — the descriptive data that complements variant options (which define SKUs). Define the schema under shops.attributes.definitions; each entry has a type (string, integer, float, boolean, array, datetime) plus optional rules, default, required, unique and encrypted. Definitions are registered at boot:

```php
// config/shops.php
'attributes' => ['definitions' => [
    'material' => ['type' => 'string'],
    'weight'   => ['type' => 'integer', 'rules' => ['min:0']],
]],
```

## Setting and reading values

```php
$product->attachAttribute('material', 'wool');
$product->attachAttribute('weight', 500);
$product->attachAttributes(['material' => 'wool', 'weight' => 320]);
$product->syncAttributes(['material' => 'cotton']);   // attach/replace, prune the rest
$product->detachAttribute('weight');

$product->attr('material')->string();   // 'wool'
$product->attr('weight')->int();        // 500
$product->attributeInt('weight');       // ?int
$product->validateAttributes();         // enforce the definitions' rules
$product->history('material');          // value-change history
```

## Filtering and sorting

Query scopes build faceted catalogue browsing — wool only, lightest first:

```php
Product::query()->whereAttribute('material', 'wool')->get();
Product::query()->whereAttributeIn('material', ['wool', 'cotton'])->get();
Product::query()->whereAttributeBetween('weight', 100, 500)->get();
Product::query()->whereHasAttribute('material')->get();
Product::query()->orderByAttribute('weight', 'desc')->get();
```

Definitions are read strictly at boot: an entry that is not an array, a type typo, a required flag that is not a boolean or rules that are not an array throw an InvalidConfigurationException naming the shops key (for example shops.attributes.definitions.colour.type) instead of being skipped.

Every write is checked against its definition before anything is stored: a value that fails the type or rules throws InvalidAttributeValueException, whose attributeName, messages() and errorBag() carry the details. Turn on the attributes package’s attributes.strict to also reject undefined attribute names with UnknownAttributeException.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/shops-for-laravel.md)
