---
title: Category
published: 2026-09-24
lastmod: 2026-09-24
url: https://larasell.dev/docs/category
---

## Table of contents
- [Creating a category](#creating-a-category)
- [Adding products](#adding-products)
- [Relationships and traversal](#relationships-and-traversal)
- [Removing products](#removing-products)
- [Translating the category](#translating-the-category)
- [Visibility](#visibility)

# Category

A `Category`{href="https://raw.githubusercontent.com/Larasell-dev/larasell/refs/heads/main/src/Models/Category.php"} allows
you to group and organize products. The main use case is to build up a navigation for your storefront,
but also to categorise products making it easier to search for them.

## Creating a category

Use the `create` method to create a new category:

```php
use Larasell\Larasell\Models\Category;

$category = Category::create([
    'name' => 'Clothing',
    'slug' => 'clothing',
]);
```

This creates a new _top-level_ category. For simple stores, this is enough. Most likely
you'll need nest categories. To do that you set a `parent_id` on the one you want
to nest.

```php
use Larasell\Larasell\Models\Category;

$clothing = Category::create([
    'name' => 'Clothing',
    'slug' => 'clothing',
]);

$shirts = Category::create([
    'name' => 'Shirts',
    'slug' => 'shirts',
    'parent_id' => $clothing->id,
]);
```

Or you can use Laravel's `children` method to create a nested category:

```php
use Larasell\Larasell\Models\Category;

$clothing = Category::create([
  'name' => 'Clothing',
  'slug' => 'clothing',
]);

$clothing->children()->create([
  'name' => 'Shirts',
  'slug' => 'shirts',
]);
```

Choose whatever fits your needs or style.

## Adding products

A category without products is not useful. Use the `attach` method to add one:

```php
use Larasell\Larasell\Models\Category;
use Larasell\Larasell\Models\Product;

$category = Category::create([
    'name' => 'Clothing',
    'slug' => 'clothing',
]);

$product = Product::create([
    'name' => 'T-Shirt',
    'price' => 1999,
]);

$product->categories()->attach($category->id);
```

In case you want to add multiple categories at once you can use the `sync` method:

```php{19-19}
use Larasell\Larasell\Models\Category;
use Larasell\Larasell\Models\Product;

$clothing = Category::create([
    'name' => 'Clothing',
    'slug' => 'clothing',
]);

$summer = Category::create([
    'name' => 'Summer sale',
    'slug' => 'summer-sale',
]);

$product = Product::create([
    'name' => 'T-Shirt',
    'price' => 1999,
]);

$product->categories()->sync([$clothing->id, $summer->id]);
```

## Relationships and traversal

You often need to get other categories that are related to
the one you currently got. Like getting the parent, descendants or sibling categories.

```php
use Larasell\Larasell\Models\Category;

// Get the parent category of a category
$shirts->parent->name->get(); // 'Clothing'

// Get the sibling categories that share the same parent
$shirts->siblings;

// Get the children of a category, useful for
// rendering the next level of your navigation
$clothing->children;

// Get all descendant categories, including children of children
$clothing->descendants;

// Get all top-level categories. This is a good
// starting point to build your storefront navigation
Category::root()->get();
```

## Removing products

To remove a product from a category, use the `detach` method:

```php
use Larasell\Larasell\Models\Category;
use Larasell\Larasell\Models\Product;

$product = Product::where('name->en', 'T-Shirt')->firstOrFail();
$category = Category::where('slug->en', 'summer-sale')->firstOrFail();

$product->categories()->detach($category->id);
```

Detaching multiple categories works the same way, pass an array of category ids:

```php
$product->categories()->detach([$clothing->id, $summer->id]);
```

If you call `detach` without any arguments, Larasell removes the product from all categories:

```php
$product->categories()->detach();
```

Detaching only removes the association between the product and the category. It doesn't delete the product or the category itself.

## Translating the category

It's possible to translate certain fields of a category, like the name and slug.

```php
use Larasell\Larasell\Models\Category;

Category::create([
  'name' => ['en' => 'Clothing', 'de' => 'Kleidung'],
  'slug' => ['en' => 'clothing', 'de' => 'kleidung'],
]);
```

To get the translated value, you call the `get` method on the category. It uses `App::currentLocale()`
to determine which translation to return to you.

```php
$category->name->get();
$category->slug->get();
```

In case you want to get the translation for a specific locale, you can pass an optional string parameter
to the method.

```php
$category->name->get('de');
```

If you try to get the value of a translation for a locale that does not exist, Larasell falls back
to the locale defined in `APP_FALLBACK_LOCALE` of your `.env` file.

Translating an existing category is easy too.

```php
use Larasell\Larasell\Models\Category;

$clothing = Category::where('slug->en', 'clothing')->first();

$clothing->update([
  'name' => ['nl' => 'Kleding']
]);
```

Note that calling `update` as above overwrites all previous translations. If you only want to add a translation,
you have to call the `with` method on the translatable value.

```php
$clothing->update(['name' => $clothing->name->with('fr', 'Vêtements')]);
```

In this case, we added a translation for French. If it already existed, we would overwrite the value rather than add it.

The same is true for removing a translation. Call the `without` method to remove a single translation without
removing all translations.

```php
$clothing->update(['name' => $clothing->name->without('de')]);
```

The `all` method helps you see all the translations the category has.

```php
$clothing->name->all(); // ['en' => 'Clothing', 'nl' => 'Kleding', 'de' => 'Kleidung']
```

There's a `has` method that you can call to check whether a category has a translation
for a specific locale.

```php
$clothing->name->has('pt');
```

## Visibility

It's possible to define the visibility of a `Category`{href="https://raw.githubusercontent.com/Larasell-dev/larasell/refs/heads/main/src/Models/Category.php"}.
Common use cases are preparing a new navigation structure or hiding seasonal
categories from your storefront.

```php
use Larasell\Larasell\Enums\Visibility;
use Larasell\Larasell\Models\Category;

$category = Category::create([
    'name' => 'Clothing',
    'slug' => 'clothing',
    'status' => Visibility::Hidden,
]);
```

Then at a later point you can make it visible, and it will show up on the storefront.

```php
use Larasell\Larasell\Enums\Visibility;
use Larasell\Larasell\Models\Category;

$category = Category::where('slug->en', 'clothing')->first();

$category->update([
  'status' => Visibility::Visible // or pass 'visible'
]);
```

A category can either be hidden or visible. If you want, you can just pass a string instead of passing the `Visibility`{href="https://raw.githubusercontent.com/Larasell-dev/larasell/refs/heads/main/src/Enums/Visibility.php"} enum.

> [!NOTE]
> Larasell automatically excludes hidden categories from the `children`, `descendants`, `siblings` and `root` relations and scopes. The `inCategory` and `inCategoryTree` product scopes also skip hidden categories, so their products won't show up in those queries either.
