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

# Integrating external content

> Seamlessly integrate the output of third-party programs into shop templates, check their availability, pass address data, and connect an editorial system.

A product configurator, a page-flip catalog, articles from an editorial system: content like this lives outside the shop but should look as if it belongs there. The usual route via a link takes the visitor out of the shop, and frames and popups come with their own drawbacks. WEBSALE V8s offers two methods for this, and the choice between them decides more than just the effort involved.

| Method | How it works | What happens if the third-party system fails |
| - | - | - |
| External includes | the shop fetches the content in real time while rendering the page | the page is delayed or the content is missing |
| JSON interface | the third-party system stores the content on the shop server in advance | nothing, the data is already there |

For content that rarely changes, the second route is the better one. For anything that has to be calculated at the moment of the request, only the first remains.

## External includes

### The two tags

Two tags embed the output of a third-party program at the position where they are placed. The difference lies in what the shop sends along.

| Tag | When |
| - | - |
| `WS-ExternInclude()` | when the third-party system needs form data that arrived in the shop via POST or GET |
| `WS-URLInclude()` | when only the address is to be embedded, without parameter rewriting and without form data |

With `WS-ExternInclude()`, all existing GET and POST parameters are combined and passed in the parameters `getbuf` and `postbuf`. Form data from a form in the shop is additionally sent to the third-party program via POST.

The output of the third-party program may itself contain WEBSALE tags. This lets you display shop data within third-party content.

### Specifying the address

The argument holds the address of the third-party program. Both tags support tag-in-tag, so the value of another tag can be part of the address. The tilde characters of the inner tag are replaced by dollar signs.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~WS-URLInclude(https://.../konfigurator.php?produktname=$PR-Name$&param=Wert)~

~WS-ExternInclude(https://.../konfigurator.php?produktname=$PR-Name$&param=Wert)~
```

In the second case, the shop additionally passes the same two parameters URL-encoded in the `getbuf` parameter:

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
getbuf=produktname%3dName%26param%3dWert
```

> [!NOTE]
>
> The shop establishes the connection to the third-party system on the server side, via a proxy. The visitor's browser sees none of this and does not call the third-party address itself.

Reference: WS-ExternInclude() · WS-URLInclude()

## Checking whether the third-party system responds

If the third-party system fails, nothing appears in its place in the shop, and page rendering is delayed until the timeout. The LiveCheck checks in advance whether the system is reachable and lets you respond, for example with substitute content.

### Setup

The checks are defined in the `<ExternSystemLiveChecks>` section of `shop.config`, with one `<+Entry>` per check. Up to ten checks are possible.

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<ExternSystemLiveChecks>
   <+Entry>
      ID         = cms-available
      URL        = https://www.ihre-domain.de/system-livecheck/index.php
      Type       = 1
      CheckMode  = successPersistant
      Timeout    = 1000
   </+Entry>
</ExternSystemLiveChecks>
```

| Parameter | Meaning |
| - | - |
| `ID` | Identifier used to call the check in the template |
| `URL` | Address that is checked |
| `Type` | Type of check, `1` makes an HTTP GET request |
| `CheckMode` | `always` checks again on every page view, `successPersistant` and `failPersistant` remember the result for the current session |
| `Timeout` | Time span in milliseconds within which a response must be received |

Reference: ExternSystemLiveChecks section

### The check file on the third-party server

For a check of type 1, the response `OK` counts as success. Any other response and any missing response counts as failure.

```php theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<?php
   echo "OK";
?>
```

For a more meaningful check, add your own checks at this point, for example for the availability of a database.

```php theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<?php
   // Eigene Prüfungen, dabei darf nichts ausgegeben werden.
   // Ergebnis in $result ablegen: true für erfolgreich, false für nicht erfolgreich.

   if ($result == true)
      echo "OK";
   else
      echo "Not OK";
?>
```

### Querying in the template

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{WS-ExternSystemLiveCheck(cms-available)}
   ~WS-ExternInclude(...)~
{/WS-ExternSystemLiveCheck(cms-available)}

{!WS-ExternSystemLiveCheck(cms-available)}
   Alternativer Inhalt, wenn das System nicht erreichbar ist
{/!WS-ExternSystemLiveCheck(cms-available)}
```

### Points to note

| Rule | Practical consequence |
| - | - |
| At most one request is made per identifier and page view | using the same identifier several times on one page costs nothing extra |
| With `successPersistant` or `failPersistant`, the result applies to the entire session | the shop then does not notice if the system recovers in the meantime |
| Each request takes 300 milliseconds on average | each additional check noticeably lengthens page rendering |
| An identifier without a valid configuration is not replaced | a typo in the identifier shows up as a leftover tag on the page |

> [!WARNING]
>
> The time span in `Timeout` is a trade-off. Too short, and the check fails even though the system is running. Too long, and every outage of the third-party system paralyzes page rendering for all visitors.

> [!NOTE]
>
> To keep the impact of an outage small, wrap the area containing the external include in an AJAX section. The content is then only fetched when the visitor requests it, not on every page view.

Reference: WS-ExternSystemLiveCheck()

Guide: How WEBSALE AJAX integrations work · Disabling the internal WEBSALE search when using external search providers

## Passing address data to a third-party system

If the third-party system needs the billing or delivery address, special tags pass it in the address of the call. A parameter determines how the data is protected.

### Defining the encoding

```ini theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<Basic>
   ...
   ExternalUserDataExchangePW = 1234567890123456
   ...
</Basic>
```

| Value | Effect |
| - | - |
| empty | the data is only transmitted hex-encoded |
| `NOHEX` | the data is transmitted unencoded |
| 16 characters | the data is encrypted with this password using Blowfish and then hex-encoded |

> [!WARNING]
>
> The password must be exactly 16 characters long. With any other length, the encryption does not take effect, and the data goes out merely hex-encoded.

### The tags

| Tag | Passes |
| - | - |
| `EXTDATA-A` | the billing address |
| `EXTDATA-D` | the delivery address |
| `EXTDATA-U` | customer-specific data |
| `EXTDATA-ALL` | all data together |

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<!-- Rechnungsadresse und Kundendaten unter eigenen Parameternamen -->
~WS-ExternInclude(https://domain.de/externalProg.cgi?data=$EXTDATA-A$&user=$EXTDATA-U$)~

<!-- alle Daten ohne eigene Parameternamen -->
~WS-ExternInclude(https://domain.de/externalProgXYZ.cgi?$EXTDATA-ALL$)~
```

The receiving system determines which parameter names are to be used.

### The data format

The data is generated in XML format, with the field number forming the element name:

```xml theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<1>Firma</1><3>Vorname</3><4>Nachname</4>
```

> [!NOTE]
>
> Only what is actually configured in `shop.config` for the respective address is passed. A field that the shop does not collect does not appear in the transfer.

The fields for the billing and delivery address largely overlap:

| Number | Content | Billing address | Delivery address |
| - | - | - | - |
| 81 | Customer number | yes | no |
| 1 | Company | yes | yes |
| 2 | Salutation code from `salutation.dat` | yes | yes |
| 3 | First name | yes | yes |
| 4 | Last name | yes | yes |
| 5 | Title code from `title.dat` | yes | yes |
| 6 | Street 1 | yes | yes |
| 7 | Street 2 | yes | yes |
| 8 | Postcode | yes | yes |
| 9 | City | yes | yes |
| 10 | Federal state or state | yes | yes |
| 11 | Three-letter ISO code of the country | yes | yes |
| 13 | Phone | yes | yes |
| 14 | Fax | yes | yes |
| 15 | Email address | yes | yes |
| 16 | Business phone | yes | yes |
| 17 | Mobile phone | yes | yes |
| 18 | Business fax | yes | yes |
| 19 | Date of birth as DD.MM.YYYY | yes | yes |
| 20 | PO box | no | yes |
| 21 | PO box | yes | no |
| 23 to 27 | Suffix 1 to 5 | yes | yes |
| 28 | Department | yes | yes |
| 29 | Cost center | yes | yes |
| 30 to 34 | Suffix 6 to 10 | yes | yes |
| 36 | PO box postcode | yes | yes |
| 37 | VAT ID | yes | no |
| 78, 79, 89 | User-defined lists 1 to 3 | yes | no |

> [!WARNING]
>
> The PO box has number 21 in the billing address and number 20 in the delivery address. If you evaluate the fields by number in the receiving system, you must distinguish between both cases.

There are two fields for customer-specific data:

| Number | Content |
| - | - |
| 0 | UserIndex, `0` means the visitor is not logged in |
| 17 | SuperUserID, empty means no SuperUser |

## Connecting an editorial system

> [!NOTE]
>
> This chapter is being revised. If you have any questions, please contact your WEBSALE contact person.

For content from an editorial system, the two routes mentioned at the beginning are available. The decision depends on whether the content includes active features.

| | JSON interface (recommended) | ExternInclude |
| - | - | - |
| Content arrives | as a file on the shop server | in real time from the system |
| System outage | no effect on the shop | the page remains empty |
| Speed | high | depends on the third-party system |
| Custom URLs and SEO | possible in a structured way | limited |
| Comments, likes, sharing features | not possible, static content only | possible |
| Adjustment needed in the editorial system | export in JSON format | output without header and footer, which the shop supplies |

> [!WARNING]
>
> We advise against integration via ExternInclude. The display then permanently depends on the availability of the third-party system, and the loading times no longer meet current technical standards.

Any editorial system that can export in JSON format can be connected.

### How it works

The editorial system stores two kinds of files in the shop's FTP area: one JSON file per content page, plus a mapping file that assigns each address its file.

The addresses of the content pages contain a common directory, for example `/cms/`. This directory is the trigger: A server rule recognizes addresses that start with it and redirects them in the background to a shop template. The originally requested address is passed as a one-time parameter, and this is exactly how the template knows which JSON file to load.

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
Aufruf:       https://www.ihr-shop.de/cms/Impressum
im Hintergrund: https://www.ihr-shop.de/?websale8=<Shop-ID>&tpl=tpl_cms.htm&otp1=cms/Impressum
```

The address visible in the browser does not change.

### Step 1: Activation and FTP access

Have the JSON interface activated. You will receive a separate FTP account for the files from the editorial system. The address rule must also be set up by WEBSALE system administration.

Three settings are part of this setup. WEBSALE uses default values for them; let us know of any different requirements during setup:

| Setting | Default |
| - | - |
| Template for displaying the content | `tpl_cms.htm` |
| Directory in the address | `/cms/` |
| One-time parameter | `OTP1` |

> [!NOTE]
>
> If you already use `OTP1` for something else, specify a different parameter during setup. Otherwise the two uses will overwrite each other.

### Step 2: Exporting content

One JSON file is created per content page and uploaded to the interface's FTP directory.

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
   "id": 1,
   "attributes": {
      "wsContentHeadline": "Impressum",
      "wsTemplateName": "tpl_imprint",
      "locale": "de",
      "wsMetaInformation": {
         "wsMetaTitle": "Impressum des Demoshops",
         "wsMetaDescription": "Hier stehen weitere Informationen zum Impressum",
         "wsPageSeoURL": "cms/Impressum",
         "wsMetaRobots": "noindex,nofollow"
      },
      "wsContent": [
         {
            "__component": "elemente.ws-column",
            "wsContentColumn": [
               {
                  "wsContentColumnMarkup": "<p>Lorem ipsum dolor.</p>",
                  "wsClassList": "col-12"
               }
            ]
         }
      ]
   },
   "content_type": "contentpage"
}
```

### Step 3: Exporting the mapping file

The mapping file links address and file.

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
   "mappings": [
      { "url": "cms/Impressum",   "file": "tpl_imprint.json" },
      { "url": "cms/Datenschutz", "file": "tpl_privacy.json" }
   ]
}
```

### Step 4: Creating the template

A single template is sufficient for all content pages, because the one-time parameter and the mapping file take over the control.

First, the mapping file is loaded and the requested address is searched for in it:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~EJD-LoadData(global,index-mapping.json,wsMapping)~
{EJD-DataOK(wsMapping)}
   ~EJD-SetUseID(wsMapping)~
   ~EJD-DA-TouchArrayElements(mappings)~
   ~DC-ZeroLoop1_set($EJD-LastValueAccessed$)~
   ~DC-Counter1_reset~
   {DC-ZeroLoop1}
      {@DC-ZeroLoop1}
         ~EJD-DA-TouchValue(mappings[$DC-ZeroLoop1_position$].url)~
         {DC-CompareStringInList($EJD-LastValueAccessed$,$WS-OTP1$)}
            ~EJD-DA-TouchValue(mappings[$DC-ZeroLoop1_position$].file)~
            ~DC-FPjsonData_set($EJD-LastValueAccessed$)~
         {/DC-CompareStringInList($EJD-LastValueAccessed$,$WS-OTP1$)}
      {/@DC-ZeroLoop1}
   {/DC-ZeroLoop1}
{/EJD-DataOK(wsMapping)}
```

The loop runs through all entries of the mapping file, compares the address with the one-time parameter and, if there is a match, stores the file name in the free placeholder `DC-FPjsonData`.

This file is then loaded and read. The following example sets the values for the head section of the page:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{DC-FPjsonData}
   ~EJD-LoadData(subshop,$DC-FPjsonData$,wsCMS)~
   ~EJD-SetUseID(wsCMS)~

   ~DC-FPjsonMeta_set(attributes.wsMetaInformation)~

   {!EJD-DA-IsNull($DC-FPjsonMeta$.wsMetaTitle)}
      <title>~EJD-DA-Value($DC-FPjsonMeta$.wsMetaTitle)~</title>
   {/!EJD-DA-IsNull($DC-FPjsonMeta$.wsMetaTitle)}

   {!EJD-DA-IsNull($DC-FPjsonMeta$.wsMetaDescription)}
      <meta name="description" content="~EJD-DA-Value($DC-FPjsonMeta$.wsMetaDescription)~">
   {/!EJD-DA-IsNull($DC-FPjsonMeta$.wsMetaDescription)}

   {!EJD-DA-IsNull($DC-FPjsonMeta$.wsMetaRobots)}
      <meta name="robots" content="~EJD-DA-Value($DC-FPjsonMeta$.wsMetaRobots)~">
   {/!EJD-DA-IsNull($DC-FPjsonMeta$.wsMetaRobots)}
{/DC-FPjsonData}
```

This results in:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<title>Impressum des Demoshops</title>
<meta name="description" content="Hier stehen weitere Informationen zum Impressum">
<meta name="robots" content="noindex,nofollow">
```

> [!NOTE]
>
> The `{DC-FPjsonData}` wrapper checks whether a file was found at all. Without it, the template tries to load a file without a name.

Reference: EJD tags for the JSON interface

Guide: JSON interface

## Related topics

* Guide: JSON interface
* Guide: How WEBSALE AJAX integrations work
* Guide: Exchanging data with external systems


## Related topics

- [Integrating FINDOLOGIC](https://dokumentation.websale.de/en/v8s/externe-dienste/integration-von-findologic.md)
- [Exchanging data with external systems](https://dokumentation.websale.de/en/v8s/externe-dienste/daten-mit-externen-systemen-austauschen.md)
- [External services: Overview](https://dokumentation.websale.de/en/v8s/externe-dienste/externe-dienste.md)
- [Using the ERP info data interface](https://dokumentation.websale.de/en/v8s/externe-dienste/wws-infodatenschnittstelle.md)
- [FACT-Finder campaigns](https://dokumentation.websale.de/en/v8s/integration-von-fact-finder/fact-finder-kampagnen.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.