> ## Documentation Index
> Fetch the complete documentation index at: https://dokumentation.websale.de/llms.txt
> Use this file to discover all available pages before exploring further.

# $wsProducts - Product data

> Reference for $wsProducts: dynamically load and display product data such as details, prices and lists in the WEBSALE frontend templates.

With the `$wsProducts` module, you can dynamically load and display product data in the frontend.

***

## Module overview

**Example / excerpt of** `$wsProducts`

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{= $wsProducts | json }}
```

**JSON output**

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
  "load": "ƒ()",
  "loadByNumber": "ƒ()",
  "loadByCustomNumber": "ƒ()",
  "variantInfo": "ƒ()"
}
```

**Note:** `ƒ()` denotes a function.

**Methods overview**

| **Method**             | **Return type** | **Description**                                   |
| ---------------------- | --------------- | ------------------------------------------------- |
| `load()`               | map             | Returns a product based on the product ID.        |
| `loadByNumber()`       | map             | Returns a product based on the item number.       |
| `loadByCustomNumber()` | map             | Returns a product based on a user-defined number. |
| `variantInfo()`        | map             | Returns the variant data for a product.           |

***

## Templates

By default, products are displayed via the template `product.htm`. This is located in the `views` directory. The name `product.htm` and the storage location must not be changed, as the template is hard-wired in the software and is not configurable or customizable.

However, product data can be flexibly integrated on other pages as well, for example:

* Home page → display of top sellers, offers, or a product selection.
* Basket page → cross-selling products as purchase recommendations.
* Category pages & search results → custom product lists with filters.
* Checkout & order confirmation → display of complementary products or discount campaigns.

With `$wsProducts`, product information can be retrieved dynamically and integrated individually into various templates to enable targeted presentation of items.

***

## Variables

No variables are available for `$wsProducts`.

***

## Methods

### \$wsProducts.load()

Returns a product based on the product ID.

**Signature**\
`$wsProducts.load(productId)`

**Return value**\
`map` - Product map with all product data.

**Parameters**

| **Name**    | **Type** | **Required** | **Description**    |
| ----------- | -------- | ------------ | ------------------ |
| `productId` | string   | yes          | ID of the product. |

**Example** that loads a product and outputs the product name.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myProduct = $wsProducts.load("100-12345") }}
Name: {{= $myProduct.name }}
```

### \$wsProducts.loadByNumber()

Returns a product based on the item number.

**Signature**\
`$wsProducts.loadByNumber(itemNumber)`

**Return value**\
`map` - Product map with all product data.

**Parameters**

| **Parameter** | **Type** | **Required** | **Description**             |
| ------------- | -------- | ------------ | --------------------------- |
| `itemNumber`  | string   | yes          | Item number of the product. |

**Example** that loads a product by item number:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myProduct = $wsProducts.loadByNumber("ART-001") }}
Name: {{= $myProduct.name }}
```

### \$wsProducts.loadByCustomNumber()

Returns a product based on a user-defined number (e.g. EAN, GTIN).

**Signature**\
`$wsProducts.loadByCustomNumber(customNumber)`

**Return value**\
`map` - Product map with all product data.

**Parameters**

| **Parameter**  | **Type** | **Required** | **Description**      |
| -------------- | -------- | ------------ | -------------------- |
| `customNumber` | string   | yes          | User-defined number. |

**Example** that loads a product by GTIN.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myProduct = $wsProducts.loadByCustomNumber("4006381333931") }}
Name: {{= $myProduct.name }}
```

<Info>
  By using the `$wsProducts.load..()` functions, various variables are available to retrieve and output data about the product. Below is an overview of which variables are available.
</Info>

#### Product data (return value of \$wsProducts.load())

First, it is necessary to assign the map with the product data, as shown in the example above, to a local variable. This can then be used at various places in the template.

**JSON output of the variable**

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
  "id": "...",
  "active": "...",
  "name": "...",
  "descr": "...",
  "itemNumber": "...",
  "price": "...",
  "taxRateId": "...",
  "storeId": "...",
  "custom": { ... },
  "base": null,
  "variantSelection": { }
}
```

**Variables overview**

| **Variable**       | **Type** | **Description**                                                                                                                                                                                                                 |
| ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`               | string   | Unique product ID assigned by the shop.                                                                                                                                                                                         |
| `active`           | string   | Returns whether the product is active in the shop.   <br />Return values:  <br />- `always` - the product is always active. <br />- `never` - the product is never active. <br />- `test` - the product is active in test mode. |
| `name`             | string   | Name of the product.                                                                                                                                                                                                            |
| `descr`            | string   | Description of the product.                                                                                                                                                                                                     |
| `itemNumber`       | string   | Item number of the product.                                                                                                                                                                                                     |
| `price`            | float    | Price of the product.                                                                                                                                                                                                           |
| `taxRateId`        | string   | Tax rate ID of the product.                                                                                                                                                                                                     |
| `storeId`          | string   | Stock item number of the product.                                                                                                                                                                                               |
| `custom`           | map      | Contains all configured free product fields of the product.                                                                                                                                                                     |
| `base`             | map      | Contains the data of the base product if it is a variant.                                                                                                                                                                       |
| `variantSelection` | map      | Contains the selected variant attributes (e.g. color, size).                                                                                                                                                                    |

### \$wsProducts.variantInfo()

Returns the variant data for a product.

**Signature**\
`$wsProducts.variantInfo(productId)`

**Return value**\
`map` - Map with variant data.

**Parameters**

| **Name**    | **Type** | **Required** | **Description**                                    |
| ----------- | -------- | ------------ | -------------------------------------------------- |
| `productId` | string   | yes          | ID of the product whose variants are to be loaded. |

**Example** that loads the variant info of a product.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myVariants = $wsProducts.variantInfo("100-12345") }}
Number of variants: {{= $myVariants.numVariants }}
```

<Info>
  By using the `$wsProducts.variantInfo()` function, various variables are available to retrieve and output data about the product. Below is an overview of which variables are available.
</Info>

#### Variant data (return value of \$wsProducts.variantInfo())

First, it is necessary to assign the map with the variant data, as shown in the example above, to a local variable. This can then be used at various places in the template.

**JSON output of the variable**

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
  "numVariants": 5,
  "variantAttributes": [
    {
      "name": "Color",
      "options": [
        { "name": "Red" },
        { "name": "Blue" }
      ]
    }
  ],
  "resolve": "ƒ()"
}
```

**Variables overview**

| **Variable**        | **Type** | **Description**                       |
| ------------------- | -------- | ------------------------------------- |
| `numVariants`       | int      | Number of variants.                   |
| `variantAttributes` | array    | List of variant attributes.           |
| `[$i].name`         | string   | Name of the attribute (e.g. "Color"). |
| `[$i].options`      | array    | List of options.                      |
| `[$i].name`         | string   | Name of the option (e.g. "Red").      |

#### \$wsProducts.variantInfo().resolve()

`resolve()` is a method of the return value of `$wsProducts.variantInfo()`. It takes a possibly incomplete or invalid attribute selection and returns the closest matching existing variant.

**Why** `resolve()` **is needed**\
Variant products only exist in certain attribute combinations.\
When a customer changes a single attribute (e.g. color), the previously selected overall combination may no longer be available. \
In this case, `resolve()` finds the next possible valid variant without you having to search through all available combinations yourself.\
\
**Example** \
A T-shirt is available in these combinations:

| Color | Size |
| ----- | ---- |
| Red   | S    |
| Blue  | S    |
| Red   | L    |

The customer currently sees "Red, L" and clicks on "Blue". However, the combination "Blue, L" does not exist, so `resolve()` returns "Blue, S" instead – the only valid variant in which the color Blue is preserved.\
The `fixate` parameter controls which attribute is considered immutable – in this case the color, since the user selected the color.

**Signature**\
`$variantInfo.resolve(selection, fixate)`

**Parameters**

| Name        | Type   | Required | Description                                                                                                                                                                                                   |
| ----------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `selection` | map    | yes      | The currently selected attribute values.<br />The map contains attribute names as keys and selected option values as values (e.g. `{"Color": "Blue", "Size": "L"}`). <br />Not all attributes need to be set. |
| `fixate`    | string | yes      | Name of the attribute that the user just changed.<br />This value is mandatorily preserved by `resolve()`. <br />All other attributes are adjusted as needed to produce a valid combination.                  |

\
**Return value**\
`map` - A product object that corresponds to the resolved variant. Its structure is identical to the return value of [\$wsProducts.load()](https://dokumentation.websale.de/frontend/referenz/module/wsproducts#\$wsproducts-load). In case of error (no variant with the fixated attribute value exists), `resolve()` returns `null`.\
\
**Example**\
The user had selected "Red, size L" and clicks on "Blue". Because "Blue, L" does not exist, `resolve()` returns the closest matching variant with the color Blue.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $varInfo  = $wsProducts.variantInfo("100-12345") }}
{{ var $resolved = $varInfo.resolve({"Color": "Blue", "Size": "L"}, "Color") }}

{{ if $resolved }}
  <a href="/produkt/{{= $resolved.id }}">Select variant</a>
{{ /if }}
```

***

## Actions

No actions are available for `$wsProducts`.

***

## Examples

In the following examples, the product is assigned to a variable `$myProduct`. This means that all product information can be retrieved and further processed via this variable.

### Name and description of the product

Name and description are standard product data fields that are predefined by the shop system. They belong to the essential fields used to record and display basic product information and are indispensable for order processing.

The technical field names are firmly defined and are addressed in the following form:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
$myProduct.<technical name>
```

The syntax for accessing the product name and the product description is:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<h1>{{= $myProduct.name }}</h1>
<p>{{= $myProduct.descr }}</p>
```

### Weight as an additional product data field

In contrast to standard product data fields, weight is one of the additional product data fields. These offer extended possibilities for recording and displaying product features that go beyond the basic information.

Additional product data fields are:

* Not mandatorily required for order processing, but helpful for product presentation.
* Individually customizable and can be added as required.
* Created via the admin interface or supplied via the product data interface.

The technical names of these fields are addressed in the form:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
$myProduct.custom.<technical name>
```

If a field `weight` was created in the admin area, the weight of a product can be output like this:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<p>Weight: {{= $myProduct.custom.weight }} kg</p>
```

### Product images

The data fields for product images are not standard fields but additional product data fields. To output product images flexibly and in different sizes, these fields must be created as the MultiFormatImage data type. This field type enables storing an image in multiple formats and at the same time provides automatic conversion, so the images are available in the desired sizes. The number of additional product data fields with this type is not limited, so any number of images can be stored for a product.

The configuration of the image sizes is done in the admin interface in the image converter service. There you can define the desired formats needed for various areas of use. Typically, four image sizes are used:

* mini (thumbnail)
* small
* normal and
* large

In the admin interface image converter service, you also define the storage directory for the images on the server. The path to the image is then output directly via the corresponding variable.

Product images are accessed according to the following scheme

* `$myProduct.custom.<technical field name>.<defined format>`

If, for example, the field `image01` was created for the main image of the product, the images can be output in the various sizes as follows:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<img src="{{= $myProduct.custom.image01.mini}}" alt="{{= $myProduct.name }}">
<img src="{{= $myProduct.custom.image01.small}}" alt="{{= $myProduct.name }}">
<img src="{{= $myProduct.custom.image01.normal}}" alt="{{= $myProduct.name }}">
<img src="{{= $myProduct.custom.image01.large}}" alt="{{= $myProduct.name }}">
```

### Variants of a product

Products that are available in different versions such as size, color, or material are created as variant products. Variants are not standalone items, but subordinate versions of a main product that differ in certain features. So that variants can be correctly managed and displayed in the shop, special product data fields are used, which are referred to as type-specific product data fields.

These fields are specifically designed to support the requirements of variant products, set products, and other complex product structures. They are deeply anchored in the shop software, firmly predefined, and cannot be changed technically. This means that both the designation and the specifications of these fields – such as allowed values, field types, or inheritance mechanisms – cannot be adjusted.

The actual product information of a variant, such as name, description, price, or images, is maintained via the standard and additional product data fields defined for the variants. This data can either be set individually per variant or – if no specific values are stored – automatically inherited from the main product.

The following syntax is used to access variants of a product:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myProductVariant = $wsProducts.variantInfo($myProduct.id) }}
{{ foreach $myVariant in $myProductVariant.variantAttributes }}
   <p>Variant name: {{= $myVariant.name }}</p>
{{ /foreach }}
```

### Price of a product

Each product has a sales price displayed in the shop. In addition to the regular price, additional prices and discounts can also be taken into account, displayed either as a fixed amount or as a percentage discount.

The following data fields are available for the price calculation, for example:

* `price` → The current sales price of the product.
* `setDiscount` → The discount in percent, i.e. "You save X%".
* `setDiscountPrice` → The reduced price after deduction of the discount, i.e. "You save X euros".
* `setOrgPrice` → The original price before the discount, i.e. the strikethrough price.

So that the prices are output with the correct currency, the currency formatting is automatically taken from the shop settings in the admin interface. This means that the currency is displayed either as an ISO code (`EUR`) or as a symbol (`€`), depending on the configuration of the shop.

Whether the prices in the shop are treated net (excl. VAT) or gross (incl. VAT) is also a setting that can be configured in the admin interface.

The syntax for accessing the prices and discounts is:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<p>Price: {{= $myProduct.price | currency }}</p>
<p>Discount in percent: {{= $myProduct.setDiscount }} %</p>
<p>Discount in numbers: {{= $myProduct.setDiscountPrice | currency }}</p>
<p>Original price: {{= $myProduct.setOrgPrice | currency }}</p>
```

### Availability of a product

In addition to all other product information, the availability of a product is one of the most important pieces of information for the buyer. Each product can be given a stock level that determines whether and in what quantity an item can be ordered. Additionally, the current stock and the corresponding delivery status can be displayed in the shop.

Access to the stock is not made directly via `$wsProducts`, but via the separate module `$wsInventory`.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myProductInventoryInfo = $wsInventory.load($myProduct.id) }}
{{ if $myProductInventoryInfo.active }}
      Current quantity: {{= $myProductInventoryInfo.amount }}
{{ /if }}
```

You can find detailed information about data access of the stock module [here](/en/frontend/referenz/module/wsinventory).

You can find more practical examples for implementing products and product variants here:

→ [Practical examples: products](/en/frontend/praxisbeispiele/produkte/anzeige-von-produkten)

***

## Related links

* [actions - Products](/en/konfiguration/actions-fehlertexte-e-mails/actions-produkte)
* [\$wsInventory - Stock & availability](/en/frontend/referenz/module/wsinventory)
