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

# Associations

> Relate products to each other as cross-sells, up-sells, alternates, or custom types.

Associations define relationships between products, such as cross-sells, up-sells, and alternates.

## Overview

Associations allow products to be related to each other. The type of association defines how the relationship should be presented on a storefront and how Lunar interprets it. Lunar ships with three built-in types (cross-sell, up-sell, and alternate), but custom types can also be created.

## Model

Associations are stored as `Lunar\Models\ProductAssociation` models.

### Fields

| Field               | Type            | Description                                                      |
| :------------------ | :-------------- | :--------------------------------------------------------------- |
| `id`                | `bigIncrements` | Primary key                                                      |
| `product_parent_id` | `foreignId`     | The owning product                                               |
| `product_target_id` | `foreignId`     | The associated product                                           |
| `type`              | `string`        | The association type (e.g. `cross-sell`, `up-sell`, `alternate`) |
| `created_at`        | `timestamp`     |                                                                  |
| `updated_at`        | `timestamp`     |                                                                  |

### Relationships

| Relationship | Type      | Related Model          | Description            |
| :----------- | :-------- | :--------------------- | :--------------------- |
| `parent`     | BelongsTo | `Lunar\Models\Product` | The owning product     |
| `target`     | BelongsTo | `Lunar\Models\Product` | The associated product |

### Scopes

| Scope                                                | Description                       |
| :--------------------------------------------------- | :-------------------------------- |
| `crossSell()`                                        | Filter to cross-sell associations |
| `upSell()`                                           | Filter to up-sell associations    |
| `alternate()`                                        | Filter to alternate associations  |
| `type(ProvidesProductAssociationType\|string $type)` | Filter by a specific type         |

### Association Types Enum

The built-in association types are defined using the `Lunar\Base\Enums\ProductAssociation` enum:

```php theme={null}
use Lunar\Base\Enums\ProductAssociation;

ProductAssociation::CROSS_SELL; // 'cross-sell'
ProductAssociation::UP_SELL;    // 'up-sell'
ProductAssociation::ALTERNATE;  // 'alternate'
```

<Warning>
  The `Lunar\Models\ProductAssociation` model also defines `CROSS_SELL`, `UP_SELL`, and `ALTERNATE` as class constants, but these are deprecated since v1.2.0. Use the `Lunar\Base\Enums\ProductAssociation` enum instead.
</Warning>

## Loading Associations

```php theme={null}
$product->associations;
```

This returns a collection of `Lunar\Models\ProductAssociation` models:

```php theme={null}
use Lunar\Models\ProductAssociation;

$association->parent; // The owning product
$association->target; // The associated product
$association->type;   // The association type string
```

### Inverse Associations

To find products that associate *to* a given product (i.e. where the product is the target), use the `inverseAssociations` relationship:

```php theme={null}
$product->inverseAssociations;
```

## Types of Association

### Cross-Sell

Cross-selling encourages customers to purchase complementary products in addition to the item they intended to buy.

For example, if a store sells a phone, cross-sell associations could include headphones or a case that works with that phone.

**Adding a cross-sell association**

```php theme={null}
use Lunar\Base\Enums\ProductAssociation;

$product->associate($crossSellProduct, ProductAssociation::CROSS_SELL);

// Or associate multiple products at once
$product->associate([$productA, $productB], ProductAssociation::CROSS_SELL);
```

**Fetching cross-sell associations**

```php theme={null}
use Lunar\Base\Enums\ProductAssociation;

// Using the convenience scope
$product->associations()->crossSell()->get();

// Using the type scope
$product->associations()->type(ProductAssociation::CROSS_SELL)->get();
```

### Up-Sell

Up-selling encourages customers to upgrade or include add-ons to the product they are buying, typically to a higher-value option.

For example, given two phones:

* Phone 16GB 5" Screen
* Phone 32GB 6" Screen

The 32GB version could be added as an up-sell association on the 16GB product, allowing it to be presented as an upgrade when a customer views the 16GB version.

**Adding an up-sell association**

```php theme={null}
use Lunar\Base\Enums\ProductAssociation;

$product->associate($upSellProduct, ProductAssociation::UP_SELL);

// Or associate multiple products at once
$product->associate([$productA, $productB], ProductAssociation::UP_SELL);
```

**Fetching up-sell associations**

```php theme={null}
use Lunar\Base\Enums\ProductAssociation;

// Using the convenience scope
$product->associations()->upSell()->get();

// Using the type scope
$product->associations()->type(ProductAssociation::UP_SELL)->get();
```

### Alternate

Alternate products are alternatives to the current product. This is useful when a product is out of stock or not quite the right fit, allowing the storefront to suggest similar options.

**Adding an alternate association**

```php theme={null}
use Lunar\Base\Enums\ProductAssociation;

$product->associate($alternateProduct, ProductAssociation::ALTERNATE);

// Or associate multiple products at once
$product->associate([$productA, $productB], ProductAssociation::ALTERNATE);
```

**Fetching alternate associations**

```php theme={null}
use Lunar\Base\Enums\ProductAssociation;

// Using the convenience scope
$product->associations()->alternate()->get();

// Using the type scope
$product->associations()->type(ProductAssociation::ALTERNATE)->get();
```

### Custom Types

In addition to the built-in types, custom association types can be defined by passing any string as the type. No registration or configuration is required since the `type` column is a plain string in the database.

```php theme={null}
$product->associate($relatedProduct, 'my-custom-type');
```

Custom types can be queried using the `type` scope:

```php theme={null}
$product->associations()->type('my-custom-type')->get();
```

<Tip>
  If using the admin panel, custom types can be added to the association type dropdown by replacing the default enum. See [Admin Panel Configuration](/1.x/admin/extending/configuration#product-association-types) for details.
</Tip>

## Removing Associations

The `dissociate` method removes associations between products. It accepts a single product, an array, or a collection. If no type is specified, all association types for the given product(s) are removed.

```php theme={null}
use Lunar\Base\Enums\ProductAssociation;

// Remove all associations with a product, regardless of type
$product->dissociate($associatedProduct);

// Also accepts an array or collection of products
$product->dissociate([$productA, $productB]);

// Remove only a specific association type
$product->dissociate($associatedProduct, ProductAssociation::CROSS_SELL);
```

## Queued Operations

<Info>
  Both `associate()` and `dissociate()` dispatch queued jobs (`Lunar\Jobs\Products\Associations\Associate` and `Lunar\Jobs\Products\Associations\Dissociate`). This means the changes may not be reflected immediately if using an asynchronous queue driver.
</Info>
