# Adobe Commerce (Magento)

Cette intégration explique comment ajouter un **bouton unique « Ajouter à Wallet »** dans la **Mon compte** zone de **Adobe Commerce (Magento 2)**. Cette intégration Magento Apple Wallet / Google Wallet aide les clients à enregistrer une **carte de fidélité ou d’adhésion** (et éventuellement une **carte-cadeau Wallet**) directement dans leur Wallet mobile, à l’aide d’un identifiant disponible dans la session client Adobe Commerce.

<figure><img src="/files/97a930d13654edc8792d17563e7e9375279483a5" alt="Adobe Commerce My Account page showing an “Add to Wallet” button."><figcaption></figcaption></figure>

<details>

<summary><strong>Exemples concrets</strong></summary>

* Un programme de fidélité affiche « Add to Wallet » à côté du numéro d’adhésion dans **Mon compte**.
* Un programme de cartes-cadeaux affiche un bouton « Add to Wallet » uniquement pour **les** cartes-cadeaux actives.
* Un parcours pick & collect affiche un CTA de carte de retrait sur une page de retrait dédiée, où une référence de retrait est disponible côté serveur.

</details>

Adobe Commerce et Magento Open Source partagent la même architecture de storefront Magento 2. Les modèles d’implémentation de cette page s’appliquent aux deux, avec de légères différences dans le déploiement et la configuration de sécurité.

{% hint style="info" %}
Pour l’utilisation générique du SDK cinto (mode ID de carte, détection de plateforme, personnalisation du QR sur ordinateur), voir [Sur votre site web](https://github.com/TheWalletCrew/docs/blob/main/enroll/on-your-website.md).
{% endhint %}

### Fonctionnement

Le SDK cinto de The Wallet Crew affiche le bon CTA selon l’appareil.

Sur iOS, le bouton télécharge une carte Apple Wallet. Sur Android, il ouvre Google Wallet. Sur ordinateur, le SDK redirige vers une page de carte hébergée qui peut être scannée ou ouverte sur mobile.

Dans cette configuration Adobe Commerce, la carte est récupérée à l’aide de :

* Un **type de carte** (exemple : `utilisateur`)
* Un identifiant client Magento envoyé comme un **identifiant externe** (exemple : `magento.customer_Id`)
* Un **HMAC** signature qui prouve que l’identifiant a été émis par le backend de la marque

{% hint style="warning" %}
Le HMAC doit être calculé côté serveur. Il ne doit pas être généré dans le navigateur.
{% endhint %}

### Prérequis

* Un modèle de carte et une émission de carte déjà configurés dans The Wallet Crew.
* L’identifiant de tenant The Wallet Crew est disponible (utilisé par l’URL du script SDK).
* Un identifiant client stable disponible dans la session sur la page de compte. Cet identifiant est utilisé par The Wallet Crew pour récupérer ou créer la carte. Le nom de la clé d’identifiant (exemple : `magento.customer_Id`) est défini lors de l’onboarding du projet.

### Ajoutez le bouton à la page de compte client Adobe Commerce

Les pages storefront Adobe Commerce sont construites à partir de **XML de mise en page** et **modèles PHTML**. Rendre le bouton depuis un bloc Magento conserve les secrets côté serveur et permet un échappement sûr des attributs HTML.

L’implémentation de référence ci-dessous ajoute le bouton à la page de tableau de bord client par défaut (`customer/account`).

#### Stockez le secret utilisé pour calculer le HMAC

Le secret HMAC doit rester côté serveur. Deux options courantes sont utilisées dans les projets Adobe Commerce.

**Option A (recommandée) : stocker les valeurs dans `app/etc/env.php`**

Stockez les valeurs dans la configuration de déploiement afin qu’elles ne puissent pas être modifiées depuis l’Admin Adobe Commerce.

{% code title="app/etc/env.php (exemple)" %}

```php
<?php
return [
    // ...
    'walletcrew' => [
        'tenant_id' => '<<tenantId>>',
        'hmac_secret' => '<<hmacSecret>>',
    ],
];
```

{% endcode %}

**Option B : stocker le secret comme variable d’environnement**

Cela maintient les secrets hors du code source et de la base de données. Cela fonctionne aussi bien avec les déploiements conteneurisés.

{% code title="Variables d’environnement (exemple)" %}

```
THEWALLETCREW_TENANT_ID=<<tenantId>>
THEWALLETCREW_HMAC_SECRET=<<hmacSecret>>
```

{% endcode %}

{% hint style="info" %}
Dans **Adobe Commerce Cloud**, les variables d’environnement sont souvent utilisées comme source de vérité pour les secrets. Le `app/etc/env.php` fichier est généralement généré lors du déploiement.
{% endhint %}

{% hint style="warning" %}
Il faut éviter de stocker le secret dans les fichiers de thème ou de le rendre dans le HTML. Seul le HMAC calculé doit atteindre le storefront.
{% endhint %}

#### Implémentation de référence (XML de mise en page + bloc + PHTML)

Cette implémentation crée :

* un **Bloc** classe qui lit l’identifiant client connecté et calcule le HMAC
* un **modèle PHTML** qui affiche le chargeur SDK + `<div data-neostore-addToWalletButton ...>`
* un **XML de mise en page** entrée qui insère le bloc dans le tableau de bord du compte client

Cela nécessite aussi un squelette de module minimal pour qu’Adobe Commerce puisse charger les fichiers.

{% code title="app/code/Vendor/WalletCrewCinto/registration.php" %}

```php
<?php
use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Vendor_WalletCrewCinto',
    __DIR__
);
```

{% endcode %}

{% code title="app/code/Vendor/WalletCrewCinto/etc/module.xml" %}

```xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_WalletCrewCinto" setup_version="1.0.0"/>
</config>
```

{% endcode %}

Une fois les fichiers déployés, activez le module et actualisez les fichiers générés et les caches.

{% code title="Activer le module (exemple)" %}

```bash
bin/magento module:enable Vendor_WalletCrewCinto
bin/magento setup:upgrade
bin/magento cache:flush
```

{% endcode %}

{% stepper %}
{% step %}

#### Ajoutez le XML de mise en page sur le tableau de bord client

Ajoutez une mise à jour de mise en page pour injecter un bloc dans le conteneur de contenu du tableau de bord.

{% code title="app/code/Vendor/WalletCrewCinto/view/frontend/layout/customer\_account\_index.xml" %}

```xml
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="Vendor\WalletCrewCinto\Block\AddToWallet"
                   name="walletcrew.add_to_wallet"
                   template="Vendor_WalletCrewCinto::add-to-wallet.phtml"
                   cacheable="false"/>
        </referenceContainer>
    </body>
</page>
```

{% endcode %}

`cacheable="false"` garantit que les identifiants spécifiques au client ne sont pas mis en cache entre les sessions.
{% endstep %}

{% step %}

#### Implémentez le bloc (calcul du HMAC côté serveur)

Le bloc lit l’identifiant client connecté et calcule `hash_hmac('sha256', $value, $secret)`.

{% code title="app/code/Vendor/WalletCrewCinto/Block/AddToWallet.php" %}

```php
<?php
declare(strict_types=1);

namespace Vendor\WalletCrewCinto\Block;

use Magento\Customer\Model\Session as CustomerSession;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\Escaper;
use Magento\Framework\View\Element\Template;

final class AddToWallet extends Template
{
    public function __construct(
        Template\Context $context,
        private readonly CustomerSession $customerSession,
        private readonly DeploymentConfig $deploymentConfig,
        private readonly Escaper $escaper,
        array $data = []
    ) {
        parent::__construct($context, $data);
    }

    public function getTenantId(): string
    {
        $fromEnvPhp = (string)($this->deploymentConfig->get('walletcrew/tenant_id') ?? '');
        if ($fromEnvPhp !== '') {
            return $fromEnvPhp;
        }

        return (string)(getenv('THEWALLETCREW_TENANT_ID') ?: getenv('WALLETCREW_TENANT_ID'));
    }

    public function getCustomerId(): ?string
    {
        $id = $this->customerSession->getCustomerId();
        return $id ? (string)$id : null;
    }

    public function getCustomerIdHmac(): ?string
    {
        $customerId = $this->getCustomerId();
        if ($customerId === null) {
            return null;
        }

        $secret = (string)($this->deploymentConfig->get('walletcrew/hmac_secret') ?? '');
        if ($secret === '') {
            $secret = (string)(getenv('THEWALLETCREW_HMAC_SECRET') ?: getenv('WALLETCREW_HMAC_SECRET'));
        }
        if ($secret === '') {
            return null;
        }

        return hash_hmac('sha256', $customerId, $secret);
    }

    public function escAttr(?string $value): string
    {
        return $this->escaper->escapeHtmlAttr((string)$value);
    }
}
```

{% endcode %}

{% hint style="info" %}
Cet exemple utilise l’identifiant client Magento comme `magento.customer_Id`. Si un identifiant CRM est stocké sur l’entité client, il peut être utilisé à la place.
{% endhint %}
{% endstep %}

{% step %}

#### Affichez le bouton cinto dans un modèle PHTML

Le modèle injecte l’identifiant de tenant, l’identifiant client et le HMAC à partir du bloc.

{% code title="app/code/Vendor/WalletCrewCinto/view/frontend/templates/add-to-wallet.phtml" %}

```php
<?php
/** @var \Vendor\WalletCrewCinto\Block\AddToWallet $block */
$tenantId = $block->getTenantId();
$customerId = $block->getCustomerId();
$hmac = $block->getCustomerIdHmac();

if (!$tenantId || !$customerId || !$hmac) {
    return;
}
?>

<script type="text/javascript">
(function (n, e, o) {
var s=n.createElement("script");s.src="https://sdk.neostore.cloud/scripts/"+e+"/cinto@1";s.async=1;
s.onload=function(){neostore.cinto.initialize(e,o)};n.body.appendChild(s);
})(document, "<?= $block->escAttr($tenantId) ?>", { language: "fr" });
</script>

<div data-neostore-addToWalletButton
     data-neostore-passType="user"
     data-neostore-externalIdentifiers-magento.customer_Id-value="<?= $block->escAttr($customerId) ?>"
     data-neostore-externalIdentifiers-magento.customer_Id-hmac="<?= $block->escAttr($hmac) ?>"
</div>
```

{% endcode %}

Si une autre langue est requise, mettez à jour `{ language: "fr" }`. Si elle est omise, le SDK utilise la langue du navigateur.

{% hint style="info" %}
La documentation complète du SDK cinto (options, solution de secours sur ordinateur et détection de plateforme) est disponible dans [Sur votre site web](https://github.com/TheWalletCrew/docs/blob/main/enroll/on-your-website.md).
{% endhint %}
{% endstep %}
{% endstepper %}

#### Notes sur le nom de l’identifiant externe

Les navigateurs mettent les attributs HTML en minuscules. Le SDK cinto inclut une règle d’échappement pour préserver les caractères majuscules en les précédant de `_`.

C’est pourquoi `magento.customer_Id` est écrit avec un underscore avant `I`. Sans l’underscore, `customer_Id` serait interprété comme `customerid`.

#### Facultatif : liste d’autorisation CSP d’Adobe Commerce

Certaines configurations Adobe Commerce imposent une Content Security Policy qui peut bloquer les scripts tiers par défaut. Si le script SDK est bloqué, ajoutez à la liste d’autorisation `https://sdk.neostore.cloud`.

{% hint style="info" %}
La configuration CSP de Magento varie selon les versions et les configurations. Si CSP est activé, il faut l’aligner avec la stratégie CSP existante du projet.
{% endhint %}

Si le projet utilise le mécanisme de liste blanche CSP de Magento, autoriser l’hôte du SDK pour `script-src` suffit généralement.

{% code title="app/code/Vendor/WalletCrewCinto/etc/csp\_whitelist.xml (exemple)" %}

```xml
<?xml version="1.0"?>
<csp_whitelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Csp:etc/csp_whitelist.xsd">
    <policies>
        <policy id="script-src">
            <values>
                <value id="walletcrew-sdk" type="host">https://sdk.neostore.cloud</value>
            </values>
        </policy>
    </policies>
</csp_whitelist>
```

{% endcode %}

{% hint style="warning" %}
Les projets Adobe Commerce centralisent souvent la gestion CSP (mode rapport uniquement vs appliqué). L’emplacement et le processus de la liste d’autorisation doivent correspondre aux conventions du projet.
{% endhint %}

### Validez le résultat

La validation couvre généralement le rendu sur la plateforme et l’installation de la carte.

1. Sur iOS Safari, le CTA doit afficher **Ajouter à Apple Wallet**.
2. Sur Chrome Android, le CTA doit afficher **Ajouter à Google Wallet**.
3. Sur ordinateur, le CTA doit rediriger vers une page de carte hébergée.
4. Après l’installation, la carte doit être visible dans Apple Wallet ou Google Wallet.

### Dépannage

**Le bouton ne s’affiche pas**

Les causes courantes sont un script SDK bloqué (CSP) ou un balisage manquant. Le HTML final doit contenir le chargeur du SDK cinto et le `<div data-neostore-addToWalletButton ...>` élément.

**Cliquer sur le bouton provoque une erreur**

Cela signifie généralement que l’identifiant externe ou le HMAC ne correspond pas à ce que The Wallet Crew attend. Vérifiez :

* Le nom de la clé d’identifiant externe correspond à celui configuré pour Magento (exemple : `magento.customer_Id`).
* Le HMAC a été calculé avec le bon secret de tenant et la valeur exacte de l’identifiant.

**La mauvaise langue s’affiche**

Définissez `{ language: "fr" }` (ou un autre code de langue ISO 639) dans les `options de initialize()` .

### FAQ

<details>

<summary><strong>Cela nécessite-t-il un module personnalisé ?</strong></summary>

Pas nécessairement. Une surcharge de thème peut suffire lorsque les valeurs côté serveur de l’identifiant client et du HMAC peuvent être affichées. Un module personnalisé est généralement préférable, car il garde le calcul du HMAC hors des modèles et centralise le chargement du secret (configuration de déploiement ou variables d’environnement).

</details>

<details>

<summary><strong>Quel identifiant client doit être utilisé ?</strong></summary>

L’identifiant client interne d’Adobe Commerce est couramment utilisé car il est stable et toujours disponible sur la page de compte. Un projet peut aussi utiliser un identifiant CRM s’il est stocké sur l’entité client. L’identifiant doit rester stable dans le temps.

</details>

<details>

<summary><strong>D’où vient le secret HMAC ?</strong></summary>

Le HMAC est calculé avec un secret de tenant provenant de The Wallet Crew. Cela rend l’échange d’identifiant inviolable et empêche l’énumération. Le secret est généralement stocké dans la configuration de déploiement Adobe Commerce (`app/etc/env.php`) ou comme variable d’environnement, et n’est jamais exposé au storefront.

</details>

<details>

<summary><strong>La même approche peut-elle être utilisée pour les cartes-cadeaux ?</strong></summary>

Oui. Le même modèle de carte-cadeau Wallet Magento fonctionne lorsque la carte-cadeau est émise comme type de carte dans The Wallet Crew et qu’un identifiant de carte-cadeau stable existe dans Adobe Commerce (ou dans un système connecté). La zone Mon compte peut afficher un bouton pour chaque carte-cadeau en changeant `data-neostore-passType` et la clé/la valeur de l’identifiant externe vers l’identifiant de la carte-cadeau, puis en signant cet identifiant avec le HMAC côté serveur.

</details>

<details>

<summary><strong>Comment gérer la rotation du secret ?</strong></summary>

Un plan de rotation utilise généralement une courte période de chevauchement. Pendant cette période, le backend peut accepter à la fois l’ancien et le nouveau secret pour la validation du HMAC. Après cette période, seul le nouveau secret reste actif.

</details>

<details>

<summary><strong>Le bouton peut-il être affiché ailleurs que sur la page de compte ?</strong></summary>

Oui. Le même SDK peut être utilisé sur n’importe quelle page authentifiée où un identifiant stable est disponible côté serveur. Parmi les exemples courants : une page de liste de cartes-cadeaux, un tableau de bord de fidélité ou une page pick & collect lorsqu’une carte de retrait est utilisée comme jeton de scan en magasin.

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.thewalletcrew.io/connectors/fr/e-commerce/adobe-commerce-magento.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
