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

# Actions - Overview

> Reference for WEBSALE actions: the link between user input and shop logic for basket, checkout, account, voucher and other interactive operations.

Actions are the link between what a user does in the shop and what the shop executes in response. Whether a customer adds a product to the basket, registers, or logs in — there is an action behind each of these operations.

Actions accept the user's input, process it in the background, and return to the frontend whether everything worked or an error occurred.

***

## Basic principle

The shop provides a set of predefined actions. They are defined by the system and cannot be named freely. Each action has a fixed name, for example `BasketItemAdd` (add a product to the basket), `Login` (log in user), or `AccountRegister` (create a new account).

Actions can be executed in three ways:

* Via a form — the most common case. The user fills out a form and submits it.
* Via a link — for actions without user input, for example logging out.
* Via AJAX — when the page should not be reloaded after execution.

Regardless of how an action is executed, the same process always runs in the background: the shop receives the request, processes it, and reports back whether the action was successful or an error occurred.

Some actions behave differently and return data directly instead of a new page, for example as JSON within the checkout. This deviating behavior is documented for the affected actions.

***

## Preparing actions

Before an action can be used in a template, a so-called action object must be created. You can think of it as a container that holds everything needed to execute the action and, after submission, also contains the shop's response.

The action object is created with [\$wsActions.create()](/en/frontend/referenz/module/wsactions#%24wsactions-create), where the name of the desired action is passed:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myAction = $wsActions.create("BasketItemAdd") }}
```

Optionally, the target page to which the user is redirected after the action runs successfully can already be passed here:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myAction = $wsActions.create("BasketItemAdd", target=$wsViews.viewUrl('basket.htm')) }}
```

The object does not trigger anything yet; it merely prepares the action. The action itself is executed only when the user submits the form, clicks a link, or an AJAX request is sent.

After execution, the shop automatically fills the action object with feedback. In the template, this can then be accessed via the variable `$myAction`, for example with `$myAction.success` or `$myAction.errors`. A complete description of all available properties can be found in the [\$wsActions module reference](/en/frontend/referenz/module/wsactions).

| **Property**      | **Description**                                                                                                                           |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `$action.id`      | The ID of the action, which is required in the form so the shop knows what to execute.                                                    |
| `$action.csrf`    | A security token that protects every request (more on this [here](#3-2-1-csrf-schutz)).                                                   |
| `$action.success` | Is `true` when the action was executed successfully.                                                                                      |
| `$action.error`   | Is `true` when an error occurred.                                                                                                         |
| `$action.errors`  | A list of all errors that occurred, with error code, affected field, and optional detail.                                                 |
| `$action.params`  | The most recently entered values. Useful for displaying a form pre-filled after an error so the user doesn't have to re-enter everything. |

***

## Executing actions

### Execution via forms

The most common way to execute an action is via an HTML form. The prepared action object is embedded into the form, and the action is executed as soon as the user submits the form.

The form is always sent to the URL of the current page so that the shop can rebuild the same page after execution and display the response:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<form method="POST" action="{{= $wsViews.current.url() }}">
```

Every form that executes an action requires three mandatory fields:

| **Field**  | **Value**                                     | **Description**                                                                                                                     |
| ---------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `wsact`    | `{{= $action.id }}`                           | Tells the shop which action should be executed.                                                                                     |
| `wscsrf`   | `{{= $action.csrf }}`                         | A security token to protect against unauthorized access (see INSERT LINK HERE).                                                     |
| `wstarget` | `e.g., {{= $wsViews.viewUrl('basket.htm') }}` | The page the user is redirected to after successful execution. The redirect also prevents a page reload from resubmitting the form. |

In addition to the mandatory fields, the form contains the action-specific fields. Which ones these are is described in the documentation of the respective action.

The following example shows a complete form for adding a product to the basket:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $myAction = $wsActions.create("BasketItemAdd") }}
<form method="POST" action="{{= $wsViews.current.url() }}">
  <input type="hidden" name="wsact"     value="{{= $myAction.id }}">
  <input type="hidden" name="wscsrf"    value="{{= $myAction.csrf }}">
  <input type="hidden" name="wstarget"  value="{{= $wsViews.viewUrl('basket.htm') }}">
  <input type="hidden" name="productId" value="12345">
  <input type="number" name="quantity"  value="1">
  <button type="submit">Add to basket</button>
</form>
```

### Tags - distinguishing multiple forms of the same action type

If a page contains multiple forms of the same action type, for example an "Add to basket" button in each product box on a category page, all of these forms share the same response by default. This means: if an error occurs for one product, all forms on the page would display this error.

A tag allows each action to be uniquely distinguished. The product ID, for example, is well-suited as a tag:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $action = $wsActions.create("BasketItemAdd", tag=$product.id) }}
```

From this, the shop generates a unique ID in the format `BasketItemAdd:42` (where `42` would be the product ID in this example). This gives each product its own action object, and errors appear only on the affected form.

For some actions, particularly in the checkout, the tag is used to specify the address type directly in the action name:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $commitBillAction     = $wsActions.create("CheckoutCommitDraftAddress:bill") }}
{{ var $commitShippingAction = $wsActions.create("CheckoutCommitDraftAddress:shipping") }}
```

### Securing actions

Actions can be protected against unauthorized access in two ways — via a CSRF token, which is mandatory for every action, and optionally via a captcha.

### CSRF protection

CSRF (`Cross-Site Request Forgery`) refers to an attack in which an external website unnoticeably sends requests to the shop on behalf of a logged-in user, for example to trigger an order or change account data. CSRF protection prevents the shop from accepting such requests.

For this purpose, a one-time CSRF token is generated for each user session. Because the token is bound to the current session, an external website cannot know it and therefore cannot trigger the action unnoticed. The token is available directly on the action object and is embedded as follows:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<input type="hidden" name="wscsrf" value="{{= $action.csrf }}">
```

### Captcha protection

For certain actions, for example registration or a contact form, a captcha can additionally be enabled. A captcha is a security check that ensures the form is filled out by a real human and not by an automated bot.

If captcha protection is active for an action, the action is only executed if the user has solved the captcha successfully. If the check fails, the action is not executed.

For protection to take effect, two prerequisites are required:

1. The action must be entered under `security.actionGuard` in the [shop configuration](/en/konfiguration/security-sicherheitsregeln) for captcha protection.
2. The captcha widget must be included in the template of the corresponding form. More on this [here](https://websale.atlassian.net/wiki/x/AwAhdw).

<Info>
  If an action is executed via a confirmation link in an email (opt-in link), no captcha check takes place. In this case, the link itself serves as proof that a human has acted.
</Info>

### Execution via links

Actions without user input, for example logging out or removing an item from the basket, can be triggered via a link without the need for a form.

For this purpose, a URL is generated with [\$wsActions.url()](/en/frontend/referenz/module/wsactions#\$wsactions-url). The method expects three arguments: the action name, the target page after execution, and optional parameters as a list. If no optional parameters are needed, an empty list `{}` is passed:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<a href="{{= $wsActions.url('Logout', $wsViews.viewUrl('home.htm'), {}) }}">Log out</a>
```

### Execution via AJAX

By default, the entire page is reloaded after a form is submitted. Sometimes this is not desired, however, for example when only a small area of the page should be updated without the user experiencing a visible reload.

In such cases, the action can be executed via AJAX. The data is sent to the shop in the background and the response (success or error) is processed directly via JavaScript without reloading the page. CSRF protection is required just as for forms; the token can be retrieved via [\$wsActions.csrfToken](/en/frontend/referenz/module/wsactions#\$wsactions-current-csrf).

A typical use case:\
The user adds a product to the basket and only the basket counter in the header updates; the rest of the page remains unchanged.

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
$.post("{{= $wsViews.viewUrl('ajax/actionResponse.json') }}", {
    "wscsrf":    "{{= $wsActions.csrfToken }}",
    "wsact":     "BasketItemAdd",
    "productId": "12345",
    "quantity":  2
}, function(data) {
    if (data.success) {
        // Action successful – e.g., update basket counter in the header
    } else {
        // Display error
        console.log(data.errors);
    }
});
```

### Executing multiple actions simultaneously

Sometimes multiple actions should be executed in sequence with a single click on "Submit". A typical example is the last step in the checkout, where the billing address and shipping address are confirmed and the order is completed.

For this purpose, the `wsmultiact` field is used instead of the normal `wsact` field, once per action. `wsact` and `wsmultiact` cannot be combined in the same form.

The actions are executed in the order in which the `wsmultiact` fields are listed in the form.\\

#### Assigning fields to an action

Because multiple actions in the same form accept fields, each field must be clearly assigned to a specific action. This is done by a prefix before the field name, separated by `|`. In the template it looks like this:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<input type="hidden" name="{{= $commitBillAction.id }}|addressType" value="bill">
```

This means: the field `addressType` with the value `bill` belongs to the action `$commitBillAction`.\\

#### An action's error should stop the next one

By default, all actions are executed, even if one of them fails. If a failed action should abort the subsequent one, the parameter `wsmultiactabortonerror` can be set to `on`:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<input type="hidden" name="wsmultiactabortonerror" value="on">
```

#### Ignoring an action's error

With `wsmultiactignoreerror`, individual actions can be marked as non-critical. If an action marked this way fails, this is not treated as a fatal error. The parameter can be specified multiple times, once per action:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<input type="hidden" name="wsmultiactignoreerror" value="{{= $action1.id }}">
<input type="hidden" name="wsmultiactignoreerror" value="{{= $action2.id }}">
```

Ignoring an error affects two situations:

* **Redirect despite error** \
  By default, the user remains on the current page in case of an error and is not redirected to the target page specified in `wstarget`. If the failed action is marked via `wsmultiactignoreerror`, the redirect still takes place.
* **Subsequent actions continue running** \
  If `wsmultiactabortonerror=on` is also set, an error would normally abort all subsequent actions. Actions marked via `wsmultiactignoreerror` do not trigger this abort — execution continues.

**Example: completing the checkout**\
The following example shows the last step of a checkout. With a click on "Order now", three actions are executed in sequence:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $commitBillAction     = $wsActions.create("CheckoutCommitDraftAddress:bill") }}
{{ var $commitShippingAction = $wsActions.create("CheckoutCommitDraftAddress:shipping") }}
{{ var $checkoutConfirm      = $wsActions.create("CheckoutConfirm") }}

<form method="POST" action="{{= $wsViews.current.url() }}">
  <input type="hidden" name="wscsrf"     value="{{= $commitBillAction.csrf }}">
  <input type="hidden" name="wsmultiact" value="{{= $commitBillAction.id }}">
  <input type="hidden" name="wsmultiact" value="{{= $commitShippingAction.id }}">
  <input type="hidden" name="wsmultiact" value="{{= $checkoutConfirm.id }}">
  <input type="hidden" name="wstarget"   value="{{= $wsViews.viewUrl('order-confirmation.htm') }}">
  <input type="hidden" name="{{= $commitBillAction.id }}|addressType"     value="bill">
  <input type="hidden" name="{{= $commitShippingAction.id }}|addressType" value="shipping">
  <button type="submit">Order now</button>
</form>
```

Execution order of the example:

1. `CheckoutCommitDraftAddress:bill` - apply the billing address
2. `CheckoutCommitDraftAddress:shipping` - apply the shipping address
3. `CheckoutConfirm` - complete the order

### Result of execution

#### Success

If the action was successful, `$myAction.success` equals `true`. In this case, a success message can be displayed or the user can be redirected to another page via `wstarget`.

#### Error

If the action fails, for example because a required field is missing or an email address is invalid, `$myAction.error` equals `true`. The error messages should be output in the template so the user knows what needs to be corrected:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ if $myAction.error }}
  <div class="alert alert-danger">
    Please correct the following entries:
    <ul>
      {{ foreach $error in $myAction.errors }}
        {{ if $error.text }}
          <li>{{= $error.text }} ({{= $error.field }}){{ if $error.subCode }} – {{= $error.subCode }}{{ /if }}</li>
        {{ else }}
          <li>{{= $error.code }} ({{= $error.field }}){{ if $error.subCode }} – {{= $error.subCode }}{{ /if }}</li>
        {{ /if }}
      {{ /foreach }}
    </ul>
  </div>
{{ /if }}
```

The error codes that a specific action can return are described in the documentation of the respective action. An explanation of all error properties can be found in the [\$wsActions module reference](/en/frontend/referenz/module/wsactions).

### Redirect

After an action has been executed successfully, the user can be redirected to a target page. This also prevents a page reload from resubmitting the form. More on this [here](#2-aktionen-vorbereiten).

***

## Actions overview

A complete overview of all available actions can be found in the respective topic areas:

* [Account](/en/frontend/referenz/aktionen/account)
* [Basket](/en/frontend/referenz/aktionen/basket)
* [Checkout](/en/frontend/referenz/aktionen/checkout)
* [Consent](/en/frontend/referenz/aktionen/consent)
* [DirectOrder](/en/frontend/referenz/aktionen/directorder)
* [Inquiry](/en/frontend/referenz/aktionen/inquiry)
* [Inventory](/en/frontend/referenz/aktionen/inventory)
* [Newsletter](/en/frontend/referenz/aktionen/newsletter)
* [ProductRating](/en/frontend/referenz/aktionen/productrating)
* [Session](/en/frontend/referenz/aktionen/session)
* [Stores](/en/frontend/referenz/aktionen/stores)
* [TestMode](/en/frontend/referenz/aktionen/testmode)
* [Voucher](/en/frontend/referenz/aktionen/voucher)
* [WatchList](/en/frontend/referenz/aktionen/watchlist)
