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

# Insert codes

> Insert codes assign order items to an advertising medium such as a catalog, an advertisement, or a mailing.

export const confWerbecode = "Einstellungen -> Shop-Konfiguration -> Gruppe „Werbemittelkennzeichen\"";

Insert codes are short codes that let you trace which advertising medium an order came from. Examples are a specific catalog, an advertisement, or a mailing. The code is appended to the product number, for example `123456-09`. Here `123456` is the product number and `09` is the insert code.

In the areas of configuration, templates, and interfaces, this concept has the technical name `Insert`. The related fields are named, for example, `content.inserts` (configuration), `validInsertCodes` (valid codes per product), and `insert` (code of an individual item). The table in the section [Terms and technical names](#terms-and-technical-names-at-a-glance) maps all the names to each other.

The full technical details per layer (template module, configuration, REST and Storefront API) can be found on the detail pages linked under [Related links](#related-links).

<Info>
  The function is switched off by default. As long as it is not activated **and** set up (see [Prerequisites](#prerequisites)), the shop behaves as before: no additional input fields, no additional displays, nothing is stored.
</Info>

## Prerequisites

For an insert code to take effect, three things must be in place. If even one of them is missing, the function has no effect for the affected product — no error message appears in that case either.

1. **The function is activated.** In the configuration, `content.inserts.enabled` must be set to `true`. As long as it is off, no code is captured, resolved, or displayed.
2. **The field assignment is set up** (once per shop). The shop must know which product field contains the valid codes. This assignment is stored in `content.usedFields.products.validInsertCodes`. If it is missing, the shop cannot find the codes maintained on the product and treats every product as if it had no valid codes.
3. **Valid codes are maintained on the product.** Only when a product has specific codes in the `validInsertCodes` field can a code be applied to that product. If the list is empty, the [default code](#configuration) (`defaultInsertCode`) is used, provided one is configured.

The concrete steps for this are described further below in the [Setup](#setup) section.

<Warning>
  Without the field assignment (item 2), the product-specific codes have no effect. It is not enough to just create the product field and enter codes. If the assignment in `usedFields.products` is missing, each item silently gets the default code (or no code at all), even if codes are maintained on the products.
</Warning>

## Terms and technical names at a glance

Depending on the layer (admin interface, configuration, template, or interface), the concept of insert codes has different names. This table maps the various designations to each other.

| Concept                       | Admin Interface                                                     | Configuration                          | Template                              | Interface                               |
| ----------------------------- | ------------------------------------------------------------------- | -------------------------------------- | ------------------------------------- | --------------------------------------- |
| Function active               | `Settings -> Shop configuration -> Group "Insert code"`             | `$wsConfig.inserts.enabled`            | `enabled` in `GET config/inserts`     |                                         |
| Default code                  | `Settings -> Shop configuration -> Group "Insert code"`             | `content.inserts.defaultInsertCode`    | `$wsConfig.inserts.defaultInsertCode` | `defaultInsertCode` in `config/inserts` |
| Separator                     | `Settings -> Shop configuration -> Group "Insert code"`             | `content.inserts.separator`            | `$wsConfig.inserts.separator`         | `separator` in `config/inserts`         |
| Position (before/after)       | `Settings -> Shop configuration -> Group "Insert code"`             | `content.inserts.position`             | `$wsConfig.inserts.position`          | `position` in `config/inserts`          |
| Valid codes per product       | Field "Valid insert codes" ([details](#valid-codes-on-the-product)) | `validInsertCodes` (product field)     | —                                     | `custom.validInsertCodes` (Admin API)   |
| Field assignment (once)       | —                                                                   | `usedFields.products.validInsertCodes` | —                                     | —                                       |
| Code per basket item          | —                                                                   | —                                      | `$item.insert`                        | `insert` (add / update)                 |
| Product number including code | —                                                                   | —                                      | `$item.itemNumberWithInsert`          | `itemNumberWithInsert` (response)       |
| Pass code via URL             | —                                                                   | —                                      | —                                     | URL parameter `insert`                  |

<Note>
  In the stored order data, the code carries the name `insertCode` (not `insert`). When reading a completed order, this name is therefore authoritative. The exact field names per interface can be found on the respective detail pages (see [Related links](#related-links)).
</Note>

## How the shop determines an insert code

If the [prerequisites](#prerequisites) are met, when a product is added to the basket the shop determines the insert code for that item in the following order:

1. **A valid code has been provided** → The code is applied to the product.
2. **No code has been provided** → The shop tries to apply the code most recently used in this session (the [session-wide insert code](#session-wide-insert-code)), provided it is valid for this product.
3. **Otherwise** → The default code (`defaultInsertCode`) stored in the [configuration](#configuration) is used. If none is stored, the item remains without a code.

The three cases build on each other. Case 3 only applies if no code was provided and there is no matching session code. So "no code → default code" is not an absolute rule but the last step in the chain.

### Session-wide insert code

As soon as a valid code has been detected, the shop remembers it for the current session. This is the code described in case 2 above, which is used for subsequent products that do not have a code specified themselves. The code is retained even if an item is removed from the basket in the meantime.

If the visitor later provides another valid code via one of the [entry paths](#where-a-code-can-be-entered), it replaces the previous one. From then on, the new code applies as the session-wide insert code. An empty or invalid code, on the other hand, does not overwrite the remembered code. When the order is completed, the remembered code is deleted.

### What does "valid code" mean

Which codes are allowed for a product is determined by [product maintenance](#valid-codes-on-the-product). The check is character-exact and case-sensitive. For example, `DA` and `da` are not the same.

### Storage in the order

The determined insert code is stored with the order and is therefore available in the order evaluation as a dedicated piece of information.

## Where a code can be entered

There are three independent ways in which an insert code can reach the shop.

* **Via the URL**: An insert code can be appended to a product call via the `insert` URL parameter — ideal for links from catalogs, advertisements, or mailings. This is possible in two independent ways:
  * on a technical view URL using the product ID: `?view=Product&productId=<productId>&insert=<code>`
  * on a SEO URL of the product: `/colorful-t-shirt?insert=<code>`
* **Direct order**: On the direct order page, a field for the insert code can be added per input row. This is a template extension. The implementation is described under [Examples](#enter-insert-codes-in-the-direct-order).
* **Basket (interface)**: When adding or updating an item, the code can be passed directly — see [Storefront API basket](/en/schnittstellen/storefront-api/storefront-api-warenkorb).

A view URL here is a technical shop URL generated via the template function `$wsViews.url(...)` or `$wsViews.viewUrl(...)` (in contrast to the human-readable SEO URL) — for details see [Module \$wsViews](/en/frontend/referenz/module/wsviews). Both URL types accept the `insert` parameter equally.

<Note>
  If a product is called **without** the `insert` parameter, a session-wide insert code that has already been set is retained — "no parameter" is therefore not treated the same as "no code". The session code is only applied when the product is added to the basket and is checked there against the valid codes.
</Note>

## Practical example: from advertisement to order

The following scenario illustrates how the rules interact:

A customer receives a mailing with a product link to which the insert code `09` is appended (for example `/colorful-t-shirt?insert=09`). With one click, they land on the product page. The code `09` is stored as the session-wide insert code.

Then they add the T-shirt to the basket. Since `09` is a valid code for this product, the item carries the code and the item number appears as `123456-09`.

They then keep browsing and add a pair of trousers to the basket without opening a code link. The shop uses the remembered session code `09`. If `09` is also valid for the trousers, that item is likewise marked with `09`. Otherwise, the default code applies or the item remains without a code.

When switching to checkout and completing the order, the determined code of each item is stored together with the order. Afterwards, the session ends and the remembered code `09` is discarded.

<Note>
  In the order history, the stored code is present in the order data (as `insertCode`), but the fully assembled display `itemNumberWithInsert` is not available there. How to display the code in the order history is described under [Examples → Order history](#order-history).
</Note>

## Special cases

**Set items:** The code is resolved both for the main item and for the contained sub-items. Each sub-item checks the code against its own valid codes (otherwise the default code applies). This works just like a separately added item.

**Variants:** The valid codes are maintained at the main product level and apply equally to its variants. When a variant is added, the session-wide code is checked against the valid codes of the main product.

## Setup

This section describes the concrete steps for the conditions listed under [Prerequisites](#prerequisites).

### Configuration

The settings are located in the configuration area under {confWerbecode} (`content.inserts`):

| **Setting**         | **Meaning**                                                                                               | **Default** |
| ------------------- | --------------------------------------------------------------------------------------------------------- | ----------- |
| `enabled`           | Switches the entire function on or off.                                                                   | off         |
| `defaultInsertCode` | Used when no code or an invalid code has been entered. Leave empty if no code should be set in that case. | empty       |
| `separator`         | Character between the product number and the code, for example `-`.                                       | `-`         |
| `position`          | Whether the code appears after the product number (`123456-09`) or before it (`09-123456`).               | after       |

As long as `enabled` is switched off, the function has no effect anywhere in the shop — regardless of how individual products are maintained.

<Info>
  Note on `defaultInsertCode`: The default code applies across all products for every entry that cannot be resolved to a valid code. If you set the code to a fixed value, keep in mind that this value can then also be used for items that are actually not intended to have an insert code. When in doubt, leave the value empty.
</Info>

### Create the product field

If the `validInsertCodes` field does not yet exist in the shop, it is created once as a custom product field. In the admin interface, this is done in the Catalog → Products area via the product field settings (select Settings / gear icon at the top right). The table there shows all existing product fields with name, type, and maximum length. Using the **New** button, the field is created with the following settings:

| **Setting**    | **Value**               |
| -------------- | ----------------------- |
| Name           | `validInsertCodes`      |
| Label          | Valid insert codes      |
| Type           | List (text entries)     |
| Maximum length | 16 characters per entry |

Alternatively, the field can be created via the [REST API configuration](/en/schnittstellen/admin-interface-api/api-referenz-konfiguration) in the `content.customProductField` node.

### Set up the field assignment

After creating the product field, it must be assigned to the function once. Only through this assignment does the shop know in which product field the valid insert codes are stored.

The assignment is maintained in the configuration node [content.usedFields](/en/konfiguration/content-katalog-kategorien-produkte#content-usedfields-zuordnung-benutzerdefinierter-felder). In the `products` area, the `validInsertCodes` entry points to the created product field:

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
  "products": {
    "validInsertCodes": "content.customProductField.validInsertCodes"
  }
}
```

The example shows only the relevant entry. The node also contains the assignments of all other functional areas (for example `weight`, `crossSelling`, `metaTitle`). These existing entries are retained unchanged; only the value of `validInsertCodes` is set.

<Warning>
  Without this assignment, the codes maintained on the product have no effect. The shop cannot then determine the valid codes of a product, and each item silently receives the default code or remains without a code, even if codes are maintained on the products. So it is not enough to just create the product field — it must also be assigned.
</Warning>

### Valid codes on the product

The field "**Valid insert codes**" (`validInsertCodes`) is a custom product field and is maintained in the admin interface on the detail page of the respective product. Like every custom field, it appears in the field group it has been assigned to — otherwise in the catch-all group "Other". This field determines per product which codes are allowed for that product.

It is a list field. Each valid code is entered as a separate entry. A separator is not needed and the codes are not maintained as a single continuous string. The following requirements apply when adding a code:

* Each entry may be a maximum of 16 characters long.
* Each code is its own list entry. Codes are not strung together in one field using commas or other separators.
* Codes are case-sensitive (for example, `DA` is not the same as `da`).
* The field is maintained at the main product level and also applies to its variants.
* If the list is empty, no code can be applied for that product (at most the [default code](#configuration) applies, if set).

In the template, the field is available as a list, for example via `$cProduct.custom.validInsertCodes` on the product page or `$item.product.custom.validInsertCodes` on the basket item. Output is done via a loop or with `join` and a freely chosen separator:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{= $cProduct.custom.validInsertCodes | join(", ") }}
```

**Result** <br />The valid codes of the product are displayed comma-separated, for example `DA, 09`.

## Display in the shop

The insert code can be displayed as part of the item number in the basket, in the order overview, in the confirmation email, in the order PDF, and in the order history (for example `123456-09`) — in the configured order and with the configured separator. The prerequisite is that the output is embedded in the respective template (see [Examples](#examples)).

The display is composed of the item number (`itemNumber`) maintained on the product and the code. If no item number is maintained on the product, only the code appears.

If an unknown code is entered, the shop discards it and, if configured, falls back to the default value. As a result, the order is never blocked.

## Modules

The following modules are used for outputting the insert code in the template:

* [\$wsConfig](/en/frontend/referenz/module/wsconfig) — provides the current settings via `$wsConfig.inserts` (active, separator, position, default code) and is needed to show output only when the function is active.
* [\$wsBasket](/en/frontend/referenz/module/wsbasket) — provides, per basket item, the code via `$item.insert` and the ready-made display via `$item.itemNumberWithInsert`.

Capturing a code (URL, direct order, basket interface) does not require its own module; this happens via URL parameters, the direct order form, or the [Storefront API](/en/schnittstellen/storefront-api/storefront-api-warenkorb).

## Examples

### Output the item number with insert code

In the basket (and analogously in the order overview, the email, and the PDF), it is sufficient to output `itemNumberWithInsert` as the item number. The order and the separator are already taken into account. If no code is set, the field contains the plain product number.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ foreach $item in $wsBasket.items }}
  <p>Item no.: {{= $item.itemNumberWithInsert }}</p>
  <p>Product name: {{= $item.product.name }}</p>
{{ /foreach }}
```

**Result** <br />Each item shows its item number including the insert code, if one has been captured. Otherwise, the plain product number is displayed.

### Output the insert code as a separate field

If the plain code should also appear as its own field, first check whether the function is active. Otherwise nothing will appear when the function is switched off.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ if $wsConfig.inserts.enabled }}
  {{ foreach $item in $wsBasket.items }}
    {{ if $item.insert }}
      <p>Insert code: {{= $item.insert }}</p>
    {{ /if }}
  {{ /foreach }}
{{ /if }}
```

**Result** <br />The insert code appears only when the function is active and only for items that carry a code.

### Enter insert codes in the direct order

On the direct order page (template `modules/directOrder.htm`, module [\$wsDirectOrder](/en/frontend/referenz/module/wsdirectorder)), customers enter product numbers row by row. By default, there is no input field for the insert code there; it must be added per input row.

Add the following field to each input row of the form, next to the existing `name="id"` field. The decisive part is the field name `insert`: The shop reads the code via this name and, when the item is added to the basket, resolves it against the codes valid for that product (see [How the shop determines an insert code](#how-the-shop-determines-an-insert-code)). Using `{{ if $wsConfig.inserts.enabled }}`, the field only appears when the function is active.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ if $wsConfig.inserts.enabled }}
<div class="col col-sm-auto">
  <div class="form-floating">
    <input type="text"
           name="insert"
           value="{{= $wsDirectOrder.items[$cDirectOrderProduct].insert | ifNull('') }}"
           class="form-control"
           id="directorder.insert.{{= $cDirectOrderProduct }}"
           placeholder="Insert code"
           aria-label="Insert code">
    <label aria-hidden="true" tabindex="-1" for="directorder.insert.{{= $cDirectOrderProduct }}">Insert code</label>
  </div>
</div>
{{ /if }}
```

**Result** <br />An input field for the insert code appears next to the product number in each row. The entered code is captured together with the row and resolved again when the row is transferred to the basket. Using the `$wsDirectOrder.items[…].insert` function, the previously captured code is written back into the field after the row is reloaded.

### Order history

The order history does not work with the basket but with the stored order data (`$order.orderList.item`). The ready-assembled field `itemNumberWithInsert` is not available there, so the display in the template must be composed by hand from the product number, the code, and the values from `$wsConfig.inserts` (position and separator).

## Related links

* [\$wsConfig](/en/frontend/referenz/module/wsconfig) — settings via `$wsConfig.inserts` (active, separator, position, default code).
* [\$wsBasket](/en/frontend/referenz/module/wsbasket) — output per item via `$item.insert` and `$item.itemNumberWithInsert`.
* [\$wsViews](/en/frontend/referenz/module/wsviews) — generating view URLs (`url()`, `viewUrl()`), to which the `insert` parameter can be appended.
* [content - Catalog](/en/konfiguration/content-katalog-kategorien-produkte) — configuration block `content.inserts` and the mandatory field assignment `usedFields.products`.
* [API reference Products](/en/schnittstellen/admin-interface-api/api-referenz-produkte) — maintaining the valid codes per product (`custom.validInsertCodes`); requires the field assignment `usedFields.products` (see [Prerequisites](#prerequisites)).
* [API reference Configuration](/en/schnittstellen/admin-interface-api/api-referenz-konfiguration) — maintaining the configuration block `content.inserts` via the configuration node endpoints.
* [Storefront API basket](/en/schnittstellen/storefront-api/storefront-api-warenkorb) — setting and reading the code via the `insert` field as well as `GET /api/v1/config/inserts`.
