Sylius11 min

Sylius Multi-Store : gerer plusieurs boutiques depuis un seul back-office

Par Pierre-Arthur Demengel
SyliusMulti-StoreChannelsE-commerceAdministration

Gerer plusieurs boutiques en ligne est un besoin frequent : marques differentes, pays differents, B2B et B2C sur la meme base. Sylius, grace a son systeme de channels, offre une solution elegante pour centraliser la gestion de plusieurs points de vente depuis un seul back-office. Dans ce tutoriel, je vous montre comment configurer et exploiter le multi-store avec Sylius.

Le systeme de channels : la fondation du multi-store

Un channel dans Sylius represente un canal de vente. C'est l'unite fondamentale qui determine ce qu'un visiteur voit et comment il interagit avec votre boutique. Chaque channel dispose de sa propre configuration :

  • Devise de base et devises disponibles
  • Langues disponibles et langue par defaut
  • Catalogue produits : quels produits sont actifs sur ce channel
  • Prix : chaque variant a un prix par channel (ChannelPricing)
  • Regles de promotion : des promotions specifiques a chaque channel
  • Methodes de livraison et paiement : configurables par channel
  • Theme : potentiellement un design different par channel
  • Configuration fiscale : zones de taxe et taux par channel

Creer un channel via l'admin

Dans l'administration Sylius, allez dans Configuration > Channels. Creez un nouveau channel en definissant :

# Exemple de configuration programmatique d'un channel
// src/DataFixtures/ChannelFixtures.php

$channelFR = new Channel();
$channelFR->setCode('france_store');
$channelFR->setName('Boutique France');
$channelFR->setHostname('www.maboutique.fr');
$channelFR->setDefaultLocale($localeFR);
$channelFR->setBaseCurrency($currencyEUR);
$channelFR->addCurrency($currencyEUR);
$channelFR->addLocale($localeFR);
$channelFR->addLocale($localeEN);
$channelFR->setTaxCalculationStrategy('order_items_based');
$channelFR->setThemeName('app/theme-france');

$channelBE = new Channel();
$channelBE->setCode('belgium_store');
$channelBE->setName('Boutique Belgique');
$channelBE->setHostname('www.maboutique.be');
$channelBE->setDefaultLocale($localeFR);
$channelBE->setBaseCurrency($currencyEUR);
$channelBE->addCurrency($currencyEUR);
$channelBE->addLocale($localeFR);
$channelBE->addLocale($localeNL);
$channelBE->setTaxCalculationStrategy('order_items_based');
$channelBE->setThemeName('app/theme-belgium');

Multi-devises : vendre en plusieurs monnaies

Sylius gere nativement le multi-devises. Chaque channel definit une devise de base et peut accepter d'autres devises. Le mecanisme fonctionne a deux niveaux :

  1. Prix catalogues : vous definissez un prix par variant et par channel dans la devise de base du channel
  2. Taux de change : Sylius convertit automatiquement les prix si le client choisit une autre devise
# Configuration des taux de change
// Dans l'admin : Configuration > Exchange Rates

// Ou programmatiquement :
$exchangeRate = new ExchangeRate();
$exchangeRate->setSourceCurrency($eur);
$exchangeRate->setTargetCurrency($gbp);
$exchangeRate->setRatio(0.8567);
$manager->persist($exchangeRate);

Pour les boutiques ou la precision des prix est critique (bijouterie, B2B), je recommande de definir des prix fixes par channel et par devise plutot que de compter sur la conversion automatique. Cela evite les prix a virgule disgracieux (47,83 euros au lieu de 47,90 euros).

Multi-langues : localiser votre boutique

Chaque channel peut proposer plusieurs langues. Les traductions s'appliquent a :

  • Noms et descriptions des produits
  • Noms des categories (taxons)
  • Attributs produits
  • Pages CMS (si vous utilisez un plugin CMS)
  • Interface utilisateur (via les fichiers de traduction Symfony)
# Exemple de configuration des locales dans services.yaml
sylius_locale:
    resources:
        locale:
            classes:
                model: Sylius\Component\Locale\Model\Locale

# Les traductions produit se font via l'interface admin
# ou via l'API :
# PUT /api/v2/admin/products/{code}/translations/fr_FR
# {
#     "name": "T-shirt Premium",
#     "description": "Notre t-shirt en coton bio...",
#     "slug": "t-shirt-premium"
# }

Detection automatique de la langue

Par defaut, Sylius utilise la locale du channel. Pour detecter automatiquement la langue du visiteur, ajoutez un event listener sur le kernel request :

// src/EventListener/LocaleDetectionListener.php
namespace App\EventListener;

use Symfony\Component\HttpKernel\Event\RequestEvent;

final class LocaleDetectionListener
{
    public function onKernelRequest(RequestEvent $event): void
    {
        $request = $event->getRequest();

        // Ne pas toucher a l'admin
        if (str_starts_with($request->getPathInfo(), '/admin')) {
            return;
        }

        // Priorite : session > cookie > header Accept-Language
        $locale = $request->getSession()->get('_locale')
            ?? $request->cookies->get('preferred_locale')
            ?? $request->getPreferredLanguage(['fr_FR', 'nl_BE', 'en_US']);

        if ($locale && $this->isLocaleAvailable($locale)) {
            $request->setLocale($locale);
        }
    }
}

Mapping de domaines : un domaine par boutique

Pour que chaque boutique ait son propre domaine (maboutique.fr, maboutique.be, maboutique.de), configurez le hostname de chaque channel. Sylius resout automatiquement le channel en fonction du domaine de la requete.

# Le channel resolver par defaut utilise le hostname
# Configuration nginx pour pointer tous les domaines vers la meme app

server {
    listen 80;
    server_name maboutique.fr maboutique.be maboutique.de;
    root /var/www/sylius/public;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        internal;
    }
}

Sylius determine le channel via le ChannelResolver. Si aucun hostname ne correspond, le channel par defaut est utilise.

Catalogue partage vs catalogues separes

C'est la question architecturale cle du multi-store. Deux approches :

Catalogue partage (recommande pour la plupart des cas)

Tous les produits existent dans une seule base. Chaque channel active ou desactive les produits qu'il souhaite proposer. Les avantages :

  • Une seule fiche produit a maintenir
  • Stock centralise
  • Reporting global simplifie

Catalogues completement separes

Si vos boutiques vendent des gammes totalement differentes (ex: une boutique mode et une boutique electronique), le catalogue partage n'a pas de sens. Dans ce cas, chaque produit est associe a un seul channel. Vous pouvez renforcer la separation en ajoutant une contrainte d'unicite :

// src/EventSubscriber/ProductChannelSubscriber.php
// Verifier qu'un produit n'est pas accidentellement active sur un channel non souhaite

public function onProductPreUpdate(GenericEvent $event): void
{
    $product = $event->getSubject();

    if (!$product instanceof ProductInterface) {
        return;
    }

    foreach ($product->getChannels() as $channel) {
        if (!$this->isChannelAllowedForProduct($product, $channel)) {
            $product->removeChannel($channel);
        }
    }
}

Themes differents par boutique

Sylius supporte le theming via le SyliusThemeBundle. Chaque channel peut utiliser un theme different, ce qui permet d'avoir des designs completement distincts tout en partageant la logique metier.

# themes/app/theme-france/composer.json
{
    "name": "app/theme-france",
    "title": "Theme France",
    "description": "Theme pour la boutique francaise",
    "authors": [
        { "name": "Pierre-Arthur Demengel" }
    ],
    "extra": {
        "sylius-theme": {
            "parents": []
        }
    }
}

# Structure du theme :
# themes/app/theme-france/
#   templates/
#     bundles/
#       SyliusShopBundle/
#         layout.html.twig    (override du layout)
#         Product/
#           show.html.twig    (override de la fiche produit)
#   assets/
#     css/
#     images/

Permissions par boutique

Dans un vrai multi-store, vous voulez que les gestionnaires d'une boutique ne puissent pas modifier les produits ou commandes d'une autre. Sylius Open Source ne propose pas cette granularite nativement. Sylius Plus l'inclut. En open source, implementez un Voter Symfony :

// src/Security/Voter/ChannelAccessVoter.php
namespace App\Security\Voter;

use Symfony\Component\Security\Core\Authorization\Voter\Voter;

final class ChannelAccessVoter extends Voter
{
    protected function supports(string $attribute, mixed $subject): bool
    {
        return $attribute === 'CHANNEL_ACCESS' && $subject instanceof ChannelAwareInterface;
    }

    protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
    {
        $user = $token->getUser();
        if (!$user instanceof AdminUser) {
            return false;
        }

        // Super admin a acces a tout
        if (in_array('ROLE_SUPER_ADMIN', $user->getRoles())) {
            return true;
        }

        // Verifier que l'admin a acces au channel de la ressource
        $allowedChannels = $user->getAllowedChannels();
        return $allowedChannels->contains($subject->getChannel());
    }
}

Cas pratiques courants

Multi-pays avec TVA differente

Creez un channel par pays. Chaque channel a sa propre zone de taxe avec les taux de TVA locaux. Sylius calcule automatiquement la TVA en fonction du channel du visiteur.

B2B et B2C depuis la meme base

Un channel B2C avec prix TTC et un channel B2B avec prix HT, des conditions de paiement differentes et un acces restreint par authentification. C'est un cas d'usage tres pertinent que je detaille dans l'article Sylius B2B.

Marques differentes

Une entreprise qui gere plusieurs marques peut utiliser un channel par marque, avec des domaines, themes et catalogues distincts. Le back-office centralise permet de piloter toutes les marques depuis un seul endroit.

Conclusion

Le multi-store est l'un des points forts de Sylius. Le systeme de channels couvre 80% des besoins multi-boutiques sans developpement supplementaire. Pour les 20% restants (permissions par boutique, themes avances, logique metier specifique par canal), Sylius Plus ou du developpement sur mesure comblent le gap.

Vous gerez plusieurs boutiques et cherchez a centraliser leur gestion ? Parlons de votre projet. Que vous soyez en France, en Belgique ou ailleurs en Europe, je peux vous accompagner dans la mise en place d'une architecture multi-store solide. Decouvrez aussi nos formules d'accompagnement.

Questions fréquentes

13 projets livrésGrand-Est & BelgiqueLighthouse >90Disponible immédiatement

Un projet en tête ?

Discutons de votre site web. Réponse garantie sous 24h.

Ou appelez directement :06 95 41 30 25

WhatsApp
Appeler