REX Ibexa Commerce 4.6 : créer un produit avec variantes, prix et stock

REX Ibexa Commerce 4.6 : créer un produit avec variantes, prix et stock

Après une première boutique de démonstration basée sur des produits simples, nous avons voulu valider le fonctionnement réel des variantes dans Ibexa Commerce 4.6.32.

L'objectif était concret : créer un T-shirt physique disponible en deux couleurs et trois tailles, attribuer un prix et un stock à chaque combinaison, l'afficher dans le storefront puis terminer une commande avec une variante précise.

Le résultat a été testé de bout en bout : la variante noire en taille M a été commandée, son code exact a été enregistré dans la commande et son stock est passé de 10 à 9.

Le résultat obtenu

Notre produit possède deux axes de variation :

Color : Black, Blue
Size  : S, M, L

Ibexa génère donc six variantes :

Code Couleur Taille Prix Stock initial
IBEXA-TSHIRT-BLACK-S Black S 29,90 € 12
IBEXA-TSHIRT-BLACK-M Black M 29,90 € 10
IBEXA-TSHIRT-BLACK-L Black L 31,90 € 8
IBEXA-TSHIRT-BLUE-S Blue S 29,90 € 11
IBEXA-TSHIRT-BLUE-M Blue M 29,90 € 9
IBEXA-TSHIRT-BLUE-L Blue L 31,90 € 7

1. Créer le groupe d'attributs

Un Attribute Group sert à organiser les définitions d'attributs dans le back-office. Il ne crée aucune variante à lui seul.

Nous avons créé le groupe Clothing avec une migration dédiée :

-   type: attribute_group
    mode: create
    identifier: clothing
    position: 10
    names:
        eng-GB: Clothing

Dans le back-office, ce groupe se trouve sous Product Catalog → Attribute Groups.

2. Créer Color et Size

L'attribut Color utilise le type natif color. Ses valeurs sont stockées sous forme de couleurs hexadécimales :

-   type: attribute
    mode: create
    identifier: color
    attribute_group_identifier: clothing
    attribute_type_identifier: color
    position: 0
    names:
        eng-GB: Color
    options:
        choices:
            -   value: '#000000'
                label:
                    eng-GB: Black
            -   value: '#0000FF'
                label:
                    eng-GB: Blue

Size est un attribut de sélection classique :

-   type: attribute
    mode: create
    identifier: size
    attribute_group_identifier: clothing
    attribute_type_identifier: selection
    position: 1
    names:
        eng-GB: Size
    options:
        choices:
            - { value: S, label: { eng-GB: S } }
            - { value: M, label: { eng-GB: M } }
            - { value: L, label: { eng-GB: L } }

À ce stade, nous avons seulement défini des caractéristiques réutilisables. Elles ne deviennent des axes de variantes qu'au niveau du Product Type.

3. Créer le Product Type physique

Nous avons créé demo_tshirt dans le groupe de Content Types product. Son champ Product Specification contient l'affectation des attributs :

fieldSettings:
    attributes_definitions:
        clothing:
            - { attributeDefinition: color, required: true, discriminator: true }
            - { attributeDefinition: size, required: true, discriminator: true }
    regions:
        default:
            region_identifier: default
            vat_category_identifier: standard

Deux options sont importantes :

  • required: true impose une valeur ;
  • discriminator: true indique que l'attribut différencie les variantes.

La base a confirmé que le type est physique, avec is_virtual = 0, et que les deux affectations sont obligatoires et discriminantes.

4. Créer le produit de base

Le produit parent reçoit un code stable :

-   type: content
    mode: create
    metadata:
        contentType: demo_tshirt
        mainTranslation: eng-GB
        remoteId: demo_product_tshirt
        alwaysAvailable: true
    fields:
        -   fieldDefIdentifier: specification
            languageCode: eng-GB
            value:
                code: IBEXA-TSHIRT
        -   fieldDefIdentifier: name
            languageCode: eng-GB
            value: 'Ibexa developer T-shirt'

Le produit parent porte les informations communes. Les codes vendables sont ensuite créés comme variantes.

5. Générer les six variantes

La migration product_variant reçoit le code du produit de base et les combinaisons d'attributs :

-   type: product_variant
    mode: create
    base_product_code: IBEXA-TSHIRT
    variants:
        -   code: IBEXA-TSHIRT-BLACK-M
            attributes:
                color: '#000000'
                size: M
        -   code: IBEXA-TSHIRT-BLUE-M
            attributes:
                color: '#0000FF'
                size: M

Le fichier réel contient les six combinaisons. Donner nous-mêmes les codes rend le résultat prévisible pour les imports, les tests et les intégrations externes.

6. Le piège rencontré lors de la republication

Après la génération, nous avons essayé de republier le contenu avec une migration content update ne contenant que le champ name. Ibexa a refusé la migration :

Value for required field definition 'specification' with language 'eng-GB' is empty.

La correction consiste à renvoyer également la valeur du champ Product Specification obligatoire :

-   type: content
    mode: update
    match:
        field: content_remote_id
        value: demo_product_tshirt
    fields:
        -   fieldDefIdentifier: specification
            languageCode: eng-GB
            value:
                code: IBEXA-TSHIRT
        -   fieldDefIdentifier: name
            languageCode: eng-GB
            value: 'Ibexa developer T-shirt'

C'est un point important pour les migrations de mise à jour : un champ obligatoire non traduisible ne doit pas être oublié.

7. Ajouter prix et stock à chaque variante

Le prix et la disponibilité restent séparés de Product Specification :

-   type: product_price
    mode: create
    product_code: IBEXA-TSHIRT-BLACK-M
    currency_code: EUR
    amount: 29.90

-   type: product_availability
    mode: create
    product_code: IBEXA-TSHIRT-BLACK-M
    is_available: true
    is_infinite: false
    stock: 10

Cette séparation autorise un prix et un stock différents pour chaque combinaison. Dans notre exemple, les tailles L coûtent 31,90 € et les autres 29,90 €.

8. Inclure le Product Type dans le catalogue

Notre catalogue initial filtrait uniquement demo_product. Le T-shirt existait donc dans la base mais n'appartenait pas encore à l'offre du storefront.

Nous avons élargi le critère :

new ProductType(['demo_product', 'demo_tshirt'])

Après la mise à jour du catalogue, nous avons réindexé :

php bin/console ibexa:reindex

Le catalogue public et la fiche produit ont ensuite répondu en HTTP 200.

9. Ajouter un vrai visuel produit

Nous avons remplacé l'image placeholder par une photo catalogue carrée : T-shirt noir, fond studio clair et motif géométrique rouge et bleu.

La commande de démo utilise LocalProductServiceInterface pour renseigner le champ image du produit parent. Les variantes héritent ainsi du visuel commun dans le storefront et le checkout.

10. Tester une vraie commande

Nous avons sélectionné la variante noire en taille M :

IBEXA-TSHIRT-BLACK-M

Le storefront a affiché :

  • disponibilité : In stock ;
  • prix net : 29,90 € ;
  • livraison standard : 5,90 € ;
  • total avec taxes : 42,96 €.

Après validation du checkout, Ibexa a créé la commande de test en statut pending. Une vérification directe de la commande a confirmé :

product_code = IBEXA-TSHIRT-BLACK-M
quantity     = 1

Le stock de cette variante est passé de 10 à 9. Cette dernière vérification prouve que le panier, le checkout, la commande et la disponibilité utilisent bien le code de variante, et non seulement le produit parent.

Les fichiers de la démonstration

Les étapes sont séparées pour rendre l'apprentissage et le diagnostic plus simples :

src/Migrations/Demo/
├── 06_clothing_attribute_group.yaml
├── 07_clothing_attributes.yaml
├── 08_tshirt_product_type.yaml
├── 09_tshirt_product_variants.yaml
├── 10_publish_tshirt_variants.yaml
└── 11_tshirt_variant_commerce.yaml

Cette séparation permet de comprendre précisément où interviennent le groupe, les définitions d'attributs, le Product Type, les variantes et les données commerciales.

Conclusion

Les variantes Ibexa Commerce ne sont pas de simples options visuelles sur une fiche produit. Chaque combinaison possède une véritable identité commerciale : code, prix, disponibilité et stock.

Le flux validé est le suivant :

Attribute Group
→ Attribute Definitions
→ Product Type avec discriminateurs
→ Produit parent
→ Variantes
→ Prix et stocks
→ Catalogue
→ Réindexation
→ Panier et commande

Ce test nous a également donné deux enseignements pratiques : toujours inclure Product Specification lors d'une mise à jour de contenu et toujours vérifier le filtre du catalogue lorsqu'un nouveau Product Type n'apparaît pas dans le storefront.