Ibexa Commerce 4.6 : créer une boutique de démonstration complète

Ibexa Commerce 4.6 : créer une boutique de démonstration complète

Installer Ibexa Commerce ne suffit pas pour obtenir immédiatement une boutique exploitable. Il faut encore configurer la fiscalité, créer un type de produit, publier un catalogue, ajouter les prix et les stocks, puis préparer le paiement et la livraison.

Dans ce tutoriel, nous allons construire une petite boutique fonctionnelle avec Ibexa Commerce 4.6.32. Le résultat contient trois produits physiques, un catalogue public, un panier, un checkout, un paiement hors ligne et une livraison forfaitaire. Nous irons jusqu'au traitement complet d'une commande dans le back-office.

Ce guide est basé sur une installation réellement exécutée et testée. Les pages du catalogue et des trois produits répondent avec un statut HTTP 200.

Ce que nous allons construire

La démonstration contient :

  • un type de produit physique demo_product ;
  • trois produits avec image, description, prix et stock ;
  • un catalogue publié demo_catalog ;
  • la devise EUR et une TVA standard à 20 % ;
  • un paiement « Pay on delivery » ;
  • une livraison standard à 5,90 € ;
  • un storefront personnalisé avec Twig et CSS ;
  • un cycle de commande complet : panier, checkout, paiement, expédition et clôture.

Les trois produits utilisés sont les suivants :

Produit Code Prix Stock
Ibexa Commerce course IBEXA-COURSE-001 99,00 € 25
Commerce developer notebook IBEXA-NOTEBOOK-001 29,90 € 40
Commerce architecture poster IBEXA-POSTER-001 19,90 € 60

1. Vérifier l'édition et la version

Depuis la racine du projet :

composer show ibexa/commerce

Dans notre cas, Composer retourne la version v4.6.32. Le métapaquet Commerce installe notamment les composants Cart, Checkout, Payment, Shipping, Storefront et Order Management.

Cette vérification est importante : Ibexa Experience et Ibexa Commerce ne fournissent pas exactement les mêmes fonctionnalités. Une instance Experience existante doit recevoir les paquets et la configuration Commerce adaptés avant de pouvoir utiliser ces migrations.

2. Démarrer les services locaux

Le projet utilise Docker pour les services techniques et le serveur Symfony pour l'application :

docker compose up -d
symfony server:start --port=8003 -d

L'application est ensuite disponible sur :

http://127.0.0.1:8003

Le back-office se trouve sous /admin et le catalogue public sous /product-catalog.

Erreur Docker : tous les pools d'adresses sont utilisés

Nous avons rencontré l'erreur suivante :

all predefined address pools have been fully subnetted

Elle signifie que Docker ne parvient plus à attribuer automatiquement un nouveau sous-réseau. Une solution propre consiste à définir explicitement les sous-réseaux du projet dans compose.yaml, avec des plages qui ne chevauchent pas les réseaux existants.

3. Configurer la région et la TVA

Un produit Commerce a besoin d'une région et d'une catégorie de TVA. Dans config/packages/ibexa.yaml, nous déclarons une TVA standard à 20 % :

ibexa:
    repositories:
        default:
            product_catalog:
                engine: default
                regions:
                    default:
                        vat_categories:
                            standard: 20

La configuration storefront active ensuite l'euro, la région par défaut et notre catalogue :

ibexa:
    system:
        storefront_group:
            product_catalog:
                currencies:
                    - EUR
                regions:
                    - default
            storefront:
                name: Ibexa
                catalog: demo_catalog

4. Séparer les migrations de la démonstration

Les recettes Ibexa installent leurs propres migrations dans src/Migrations/Ibexa. Pour ne pas mélanger le code fourni par l'éditeur et notre démonstration, nous avons créé un dossier distinct :

src/Migrations/
├── Demo/
│   ├── 01_product_type.yaml
│   ├── 02_product.yaml
│   ├── 03_product_image.yaml
│   ├── 04_checkout.yaml
│   └── 05_additional_products.yaml
└── Ibexa/
    └── ... migrations des recettes

Ibexa est configuré pour lire notre dossier dans config/packages/ibexa_migrations.yaml :

ibexa_migrations:
    migration_directory: '%kernel.project_dir%/src/Migrations/Demo'
    migrations_files_subdir: '.'

Cette séparation rend le dépôt plus lisible et évite de versionner des dizaines de fichiers générés sans rapport direct avec la démonstration.

5. Commerce fournit-il déjà un type de produit ?

Une installation Commerce propre fournit le moteur de catalogue et le FieldType ibexa_product_specification, mais pas notre type de produit métier prêt à l'emploi. C'est donc à nous de définir la structure adaptée au projet : produit physique, formation, abonnement, livre, etc.

Dans cette démonstration, nous avons créé nous-mêmes le type demo_product. Un type de contenu devient un type de produit Commerce lorsqu'il appartient au groupe product et contient le champ obligatoire ibexa_product_specification. Ce champ porte notamment le code produit et relie la structure de contenu aux fonctionnalités commerciales.

Groupe, type, définition de champ et FieldType : quelle différence ?

Ces notions forment une hiérarchie :

Groupe de types « product »
└── Type de produit « demo_product »
    ├── définition de champ « specification » → FieldType ibexa_product_specification
    ├── définition de champ « name »          → FieldType ezstring
    ├── définition de champ « description »   → FieldType ezrichtext
    └── définition de champ « image »         → FieldType ezimage
        └── produit concret « IBEXA-COURSE-001 » avec ses valeurs
Élément Rôle Exemple dans la démo
Groupe de Content Types Classe et organise plusieurs schémas. Le service Commerce cherche ses types dans le groupe configuré product. product
Content Type / Product Type Définit le schéma d'un produit : quels champs existent et quelles règles ils suivent. demo_product
Field Definition Champ configuré à l'intérieur du schéma : identifiant, position, obligation, traduction, validation. le champ name, obligatoire et traduisible
FieldType Composant technique qui définit la nature et le comportement d'une valeur. ezstring, ezimage, ezrichtext
Produit Instance concrète du Product Type, contenant les valeurs des champs. IBEXA-COURSE-001

Le groupe product ne transforme pas, à lui seul, un Content Type en Product Type. Il sert de périmètre de classement et de recherche pour le service Commerce. La détection technique est ensuite effectuée par la présence du FieldType ibexa_product_specification.

Il faut également distinguer l'identifiant de la définition de champ et l'identifiant de son FieldType :

- identifier: specification          # nom du champ dans notre schéma
  type: ibexa_product_specification  # moteur technique utilisé par ce champ

Nous aurions pu appeler la définition product_data, mais son type devrait toujours être ibexa_product_specification. Pour rester lisibles et proches des conventions Ibexa, nous utilisons specification.

Ce que le champ Product Specification ne contient pas

Le champ ibexa_product_specification donne au contenu son identité commerciale et porte notamment son code produit unique. Sa présence permet à Ibexa Commerce de reconnaître le Content Type comme un Product Type.

Il ne faut cependant pas confondre ce champ avec toutes les données commerciales du produit :

Notion Où elle est gérée Rôle
Code produit Product Specification Identifie de manière unique le produit ou une variante.
Prix Product Price Associe un montant au produit dans une devise donnée.
Disponibilité et stock Product Availability Indique si le produit peut être vendu et la quantité disponible.
TVA Région et catégorie de TVA du Product Type Détermine le taux fiscal applicable selon la région.
Attributs Configuration du Product Type Décrivent des caractéristiques telles que la taille, la couleur ou le format et peuvent servir à générer des variantes.
Catalogue Product Catalog Sélectionne les produits visibles grâce à des règles de filtrage.

Cette séparation explique pourquoi créer le Content Type et son champ Product Specification ne suffit pas à obtenir un article immédiatement achetable : le prix et la disponibilité doivent ensuite être créés explicitement.

Produit physique ou virtuel

Lors de la création depuis Product Catalog → Product Types, Ibexa demande la nature du Product Type. Un produit physique entre dans un parcours comprenant normalement la livraison et le stock. Un produit virtuel représente un bien immatériel et ne nécessite pas d'expédition physique.

Notre type demo_product est physique : la commande de démonstration possède donc une expédition, un mode de livraison et un statut qui évolue jusqu'à Shipped.

Le chemin recommandé dans le back-office est Product Catalog → Product Types → Create. Ibexa crée alors la structure dans le groupe de produits configuré et ajoute le champ Product Specification obligatoire. La même structure reste visible dans Content structure → Content types → Product, car un Product Type est construit au-dessus du système de Content Types d'Ibexa.

Le premier fichier crée cette structure :

-   type: content_type
    mode: create
    metadata:
        identifier: demo_product
        mainTranslation: eng-GB
        nameSchema: '<name>'
        contentTypeGroups:
            - product
    fields:
        -   identifier: specification
            type: ibexa_product_specification
            required: true
            translatable: false
            fieldSettings:
                regions:
                    default:
                        region_identifier: default
                        vat_category_identifier: standard
        -   identifier: name
            type: ezstring
            required: true
            searchable: true
        -   identifier: description
            type: ezrichtext
            required: false
            searchable: true

Nous ajoutons ensuite un champ ezimage utilisé comme miniature du produit :

-   type: content_type
    mode: update
    match:
        field: content_type_identifier
        value: demo_product
    fields:
        -   identifier: image
            type: ezimage
            position: 3
            thumbnail: true

Le paramètre thumbnail: true permet à Ibexa d'utiliser cette image dans les cartes du catalogue.

6. Créer un produit, son prix et son stock

Un produit est créé comme un contenu du type demo_product. Le champ specification contient son code unique :

-   type: content
    mode: create
    metadata:
        contentType: demo_product
        mainTranslation: eng-GB
        remoteId: demo_product_ibexa_course
        alwaysAvailable: true
        section: 1
    location:
        parentLocationId: 60
    fields:
        -   fieldDefIdentifier: specification
            languageCode: eng-GB
            value:
                code: IBEXA-COURSE-001
        -   fieldDefIdentifier: name
            languageCode: eng-GB
            value: 'Ibexa Commerce course'

Le prix et la disponibilité sont deux étapes séparées :

-   type: product_price
    mode: create
    product_code: IBEXA-COURSE-001
    currency_code: EUR
    amount: 99.00

-   type: product_availability
    mode: create
    product_code: IBEXA-COURSE-001
    is_available: true
    is_infinite: false
    stock: 25

Cette distinction est utile : le contenu décrit le produit, tandis que Commerce gère séparément ses données commerciales.

7. Configurer paiement et livraison

Pour une démonstration locale, un paiement hors ligne évite toute intégration bancaire :

-   type: payment_method
    mode: create
    paymentType: offline
    identifier: demo_offline_payment
    enabled: true
    name:
        - languageCode: eng-GB
          value: 'Pay on delivery'

La livraison utilise un tarif fixe de 5,90 € :

-   type: shipping_method
    mode: create
    identifier: demo_standard_delivery
    enabled: true
    shippingType: flat_rate
    vatCategory: standard
    options:
        price: '5.90'
        currency: EUR
    regions:
        - default

Ce scénario suffit pour tester tout le checkout sans appeler un service externe.

8. Exécuter les migrations

Sur une installation Commerce neuve, les fichiers sont exécutés dans l'ordre :

php bin/console ibexa:migrations:migrate --file=01_product_type.yaml
php bin/console ibexa:migrations:migrate --file=02_product.yaml
php bin/console ibexa:migrations:migrate --file=03_product_image.yaml
php bin/console ibexa:migrations:migrate --file=04_checkout.yaml
php bin/console ibexa:migrations:migrate --file=05_additional_products.yaml

L'ordre est volontaire : le type doit exister avant les produits, et le champ image doit exister avant d'être alimenté.

9. Publier un catalogue avec une commande Symfony

La commande personnalisée suivante crée un catalogue publié filtré sur notre type de produit :

$catalog = $this->catalogService->createCatalog(new CatalogCreateStruct(
    'demo_catalog',
    new ProductType(['demo_product']),
    ['eng-GB' => 'Demo catalog'],
    ['eng-GB' => 'Published catalog for the Commerce demonstration.'],
    Status::PUBLISHED_PLACE,
    14,
));

La commande est idempotente pour le catalogue : si demo_catalog existe déjà, elle ne le recrée pas.

php bin/console app:commerce-demo:setup

Elle associe également à chaque produit son image et une description RichText. Le service local des produits est préférable à une modification SQL directe : il respecte les API et les événements Ibexa.

10. Reconstruire l'index

Après la création ou la modification de produits, il faut reconstruire l'index de recherche :

php bin/console ibexa:reindex --siteaccess=admin
php bin/console cache:clear

Sans cette étape, les produits peuvent exister dans la base tout en restant absents du catalogue ou des résultats de recherche.

11. Personnaliser le storefront sans modifier vendor/

Il ne faut jamais éditer directement les templates du paquet Storefront. Nous surchargeons le template dans le projet :

templates/themes/storefront/storefront/catalog.html.twig
templates/themes/storefront/storefront/product.html.twig

La surcharge conserve le template officiel et ajoute notre feuille de style :

{% extends '@IbexaStorefront/themes/storefront/storefront/product.html.twig' %}

{% block stylesheets %}
    {{ parent() }}
    <link rel="stylesheet" href="{{ asset('assets/demo/product.css') }}">
{% endblock %}

Notre CSS ajoute notamment :

  • une grille de produits plus aérée ;
  • des cartes avec ombre, arrondis et animation au survol ;
  • une meilleure hiérarchie typographique ;
  • une mise en avant du prix et du bouton d'ajout au panier ;
  • un comportement responsive sur mobile.

Les personnalisations restent ainsi indépendantes du code installé par Composer.

12. Tester le parcours de commande

Le test fonctionnel complet suit ce parcours :

  1. ouvrir /product-catalog ;
  2. ouvrir une fiche produit ;
  3. ajouter le produit au panier ;
  4. saisir l'adresse de livraison ;
  5. sélectionner « Standard delivery » ;
  6. sélectionner « Pay on delivery » ;
  7. confirmer la commande ;
  8. ouvrir la commande dans /admin/order/list ;
  9. confirmer le paiement ;
  10. préparer puis expédier la livraison ;
  11. terminer la commande.

Les statuts observés suivent la progression métier :

Pending → Processing → Completed

Le paiement passe à Paid et l'expédition à Shipped. Cette vérification est plus importante qu'un simple affichage du catalogue : elle valide l'interaction entre Cart, Checkout, Payment, Shipping et Order Management.

Commande Ibexa Commerce terminée avec données client anonymisées

La capture publiée utilise volontairement un nom, un e-mail, un téléphone et une adresse fictifs. Les données personnelles de la commande originale ne doivent jamais apparaître dans un article public.

13. URLs utiles

Storefront

http://127.0.0.1:8003/product-catalog
http://127.0.0.1:8003/product-catalog/ibexa-commerce-course
http://127.0.0.1:8003/product-catalog/commerce-developer-notebook
http://127.0.0.1:8003/product-catalog/commerce-architecture-poster

Back-office

http://127.0.0.1:8003/admin/product/list
http://127.0.0.1:8003/admin/product-type/list
http://127.0.0.1:8003/admin/catalog
http://127.0.0.1:8003/admin/order/list
http://127.0.0.1:8003/admin/payment-method
http://127.0.0.1:8003/admin/shipping_method

Les routes /product/list et /order/list sans préfixe /admin ne sont pas des pages publiques. Elles peuvent provoquer une erreur de SiteAccess ou tenter de charger un template storefront qui n'est pas prévu pour le back-office.

14. Garder un dépôt Git propre

Le .gitignore exclut les éléments locaux ou régénérables :

/.idea/
/.vscode/
/public/var/
/public/assets/ibexa/
/public/assets/storefront/
/public/assets/richtext/
/public/assets/translations/
/src/Migrations/Ibexa/

En revanche, le CSS de la démo, les images utilisées par les produits, la commande Symfony et src/Migrations/Demo restent versionnés. Ils sont nécessaires pour reproduire le résultat.

15. Commandes de contrôle

Avant de livrer ou de commiter :

php bin/console lint:yaml config/packages/ibexa_migrations.yaml src/Migrations/Demo
php bin/console lint:twig templates/themes/storefront/storefront
php bin/console ibexa:reindex --siteaccess=admin
git diff --check

Un contrôle HTTP simple permet aussi de vérifier les pages :

curl -I http://127.0.0.1:8003/product-catalog

Conclusion

Cette démonstration montre qu'Ibexa Commerce ne se limite pas à une liste de produits. Son modèle sépare clairement le contenu éditorial, les données commerciales, les catalogues, la tarification, le stock, le paiement, la livraison et les commandes.

La bonne approche consiste à automatiser les données reproductibles avec des migrations et une commande Symfony, puis à personnaliser le storefront dans le projet sans modifier les paquets installés. Nous obtenons ainsi une base propre pour aller plus loin : promotions, variantes, catégories, comptes clients, paiement en ligne ou intégration à une instance multisite existante.