mcpField
M
magento-multi-store

magento-multi-store

github.com/finsilabs开发6078 次安装5 天前更新
代码仓库

关于 magento-multi-store

这项 Magento 配置技能讲解如何在单个安装中管理多个网站、商店和本地化视图,涵盖作用域配置、路由、商品分配及 Adobe Commerce B2B 共享目录。

主要功能

  1. 01Website、Store 与 Store View 层级
  2. 02按商店代码配置 Nginx 路由
  3. 03全局、网站和视图级设置
  4. 04网站商品分配与定价
  5. 05Adobe Commerce B2B 共享目录

适用场景

  1. 01在单个 Magento 安装中运营不同国家的店面
  2. 02为各网站设置货币和支付方式
  3. 03基于共享目录创建本地化视图
  4. 04管理 B2B 企业专属商品可见性与价格

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill magento-multi-store

安装后在 Claude Code 中输入/magento-multi-store确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

tile.json
evals/cli-website-provisioning-script/
criteria.json
task.md
evals/nginx-multi-store-routing-config/
criteria.json
task.md
evals/php-scoped-config-and-product-assignment/
criteria.json
task.md

详细介绍

Magento 多店铺设置

概述

Magento 的多店铺架构分为三个层级:Website → Store → Store View。Website 将拥有共享客户群和订单流程的多个店铺归为一组。Website 下的 Store 拥有自己的根类别和 URL 结构。Store 下的 Store View 通常代表不同语言或地区设置。配置值可以设为全局、Website 或 Store View 范围;较低层级的设置会覆盖较高层级的设置。Adobe Commerce(B2B)还提供 Shared Catalogs,用于按公司控制产品和价格的可见性。

何时使用此技能

  • 需要通过单个 Magento 安装运行多个品牌或面向不同国家/地区的店面时
  • 需要为每个 Website 设置不同的基础货币、税务配置或支付方式时
  • 需要在 B2C 店铺旁创建具有不同产品可见性的 B2B 门户时
  • 需要在同一产品目录下为多种语言创建本地化 Store View 时
  • 需要为每个 Website 配置独立的结账流程、配送方式或支付网关时
  • 需要管理共享产品目录,同时覆盖特定 Website 的定价和可见性时

核心说明

  1. 创建 Website → Store → Store View 层级

    注意: Magento 核心版本不包含 bin/magento store:website:create、store:group:create 或 store:store:create CLI 命令。请通过 Admin → Stores → All Stores 或以编程方式使用 PHP(如下所示)创建 Website、Store 和 Store View。一些第三方模块会添加对应的 CLI 命令,但它们并非核心功能。

    通过 PHP 以编程方式创建(主要方法):

    <?php
    // Create website via DataObject
    use Magento\Store\Model\Website;
    use Magento\Store\Model\Group;
    use Magento\Store\Model\Store;
    
    $website = $objectManager->create(Website::class);
    $website->setCode('uk_site')
            ->setName('UK Website')
            ->setDefaultGroupId(0) // Set after creating group
            ->save();
    
    $storeGroup = $objectManager->create(Group::class);
    $storeGroup->setWebsiteId($website->getId())
               ->setName('UK Store')
               ->setRootCategoryId(3) // Your UK root category ID
               ->save();
    
    $storeView = $objectManager->create(Store::class);
    $storeView->setWebsiteId($website->getId())
              ->setGroupId($storeGroup->getId())
              ->setCode('uk_en')
              ->setName('UK English')
              ->setIsActive(1)
              ->save();
    
  2. 配置 nginx 以支持多 Website 路由

    # /etc/nginx/sites-available/magento-multi-store.conf
    
    # Map host to Magento store code (MAGE_RUN_CODE + MAGE_RUN_TYPE)
    map $http_host $MAGE_RUN_CODE {
        hostnames;
        default         "";
        www.mystore.com "";         # Default (global config)
        uk.mystore.com  uk_en;     # UK store view
        de.mystore.com  de_de;     # German store view
        b2b.mystore.com b2b_en;   # B2B website
    }
    
    map $http_host $MAGE_RUN_TYPE {
        hostnames;
        default         "";
        www.mystore.com "";
        uk.mystore.com  "store";   # Route to store view
        de.mystore.com  "store";
        b2b.mystore.com "website"; # Route to website (different customer base)
    }
    
    server {
        listen 443 ssl http2;
        server_name ~^(.+\.)?mystore\.com$;
    
        root /var/www/magento/pub;
        index index.php;
    
        location ~ \.php$ {
            fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
            fastcgi_param MAGE_RUN_CODE $MAGE_RUN_CODE;
            fastcgi_param MAGE_RUN_TYPE $MAGE_RUN_TYPE;
            include fastcgi_params;
        }
    }
    
  3. 设置范围配置值

    配置可以设为全局、Website 或 Store View 范围:

    # Set base URL per website
    bin/magento config:set --scope=websites --scope-code=uk_site web/secure/base_url "https://uk.mystore.com/"
    bin/magento config:set --scope=websites --scope-code=uk_site web/unsecure/base_url "https://uk.mystore.com/"
    
    # Set currency per website
    bin/magento config:set --scope=websites --scope-code=uk_site currency/options/base GBP
    bin/magento config:set --scope=websites --scope-code=uk_site currency/options/default GBP
    bin/magento config:set --scope=websites --scope-code=uk_site currency/options/allow "GBP,EUR"
    
    # Set locale per store view
    bin/magento config:set --scope=stores --scope-code=de_de general/locale/code de_DE
    bin/magento config:set --scope=stores --scope-code=de_de general/locale/timezone "Europe/Berlin"
    
    # Disable a payment method for specific website
    bin/magento config:set --scope=websites --scope-code=uk_site payment/checkmo/active 0
    

    通过 PHP 以编程方式设置:

    <?php
    use Magento\Framework\App\Config\Storage\WriterInterface;
    use Magento\Store\Model\ScopeInterface;
    
    class ScopeConfigManager
    {
        public function __construct(
            private readonly WriterInterface $configWriter,
            private readonly \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList
        ) {}
    
        public function setScopedValue(
            string $path,
            mixed $value,
            string $scope,
            int $scopeId
        ): void {
            $this->configWriter->save($path, $value, $scope, $scopeId);
            // Flush config cache after write
            $this->cacheTypeList->cleanType('config');
        }
    
        public function setWebsiteShippingOrigin(string $websiteCode, array $originData): void {
            $website = \Magento\Framework\App\ObjectManager::getInstance()
                ->create(\Magento\Store\Model\Website::class)
                ->load($websiteCode, 'code');
    
            $this->setScopedValue(
                'shipping/origin/country_id',
                $originData['country'],
                ScopeInterface::SCOPE_WEBSITES,
                (int)$website->getId()
            );
        }
    }
    
  4. 管理特定 Website 的产品分配和定价

    可以将产品分配给特定 Website,同时共享全局目录:

    <?php
    // Assign a product to specific websites
    use Magento\Catalog\Model\ResourceModel\Product as ProductResource;
    
    class ProductWebsiteAssignment
    {
        public function __construct(
            private readonly ProductResource $productResource,
            private readonly \Magento\Store\Model\StoreManagerInterface $storeManager
        ) {}
    
        public function assignProductToWebsite(int $productId, string $websiteCode): void {
            $website = $this->storeManager->getWebsite($websiteCode);
            $this->productResource->websiteToProducts([
                ['product_id' => $productId, 'website_id' => $website->getId()],
            ]);
        }
    
        public function setWebsitePrice(int $productId, string $websiteCode, float $price): void {
            // Use tier prices with website scope for website-specific pricing
            $tierPriceResource = \Magento\Framework\App\ObjectManager::getInstance()
                ->create(\Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice::class);
            // Or use price scope: Admin → Config → Catalog → Price → Catalog Price Scope = Website
        }
    }
    

    启用 Website 范围的定价:

    bin/magento config:set catalog/price/scope 1  # 0 = Global, 1 = Website
    bin/magento indexer:reindex catalog_product_price
    
  5. 配置 Adobe Commerce B2B Shared Catalogs

    Shared Catalogs(B2B 功能)支持按公司控制产品和价格的可见性:

    <?php
    // Assign a company to a custom shared catalog
    use Magento\SharedCatalog\Api\SharedCatalogManagementInterface;
    use Magento\SharedCatalog\Api\Data\SharedCatalogInterface;
    
    class SharedCatalogManager
    {
        public function __construct(
            private readonly SharedCatalogManagementInterface $sharedCatalogManagement,
            private readonly \Magento\SharedCatalog\Api\SharedCatalogRepositoryInterface $catalogRepository,
            private readonly \Magento\Company\Api\CompanyRepositoryInterface $companyRepository
        ) {}
    
        public function assignCompanyToCatalog(int $companyId, int $sharedCatalogId): void {
            $sharedCatalog = $this->catalogRepository->get($sharedCatalogId);
            $company = $this->companyRepository->get($companyId);
            $company->getExtensionAttributes()->getQuoteConfig()?->setCustomerGroupId(
                $sharedCatalog->getCustomerGroupId()
            );
            $this->companyRepository->save($company);
        }
    }
    
    # CLI: Assign products to a shared catalog (by SKU list from CSV)
    bin/magento company:catalog:assign --catalog-id=2 --products-file=products.csv
    
    # Set catalog-specific pricing via import
    bin/magento import:start --entity=shared_catalog_product_price --behavior=add_update --import-file=prices.csv
    

示例

自动化多 Website 部署配置
<?php
// Console command to provision a new website from config array
namespace MyVendor\MultiStore\Console\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class ProvisionWebsiteCommand extends Command
{
    protected function configure(): void
    {
        $this->setName('mystore:website:provision')
             ->setDescription('Provision a new website from config');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $websites = [
            [
                'code' => 'au_site',
                'name' => 'Australia',
                'domain' => 'au.mystore.com',
                'currency' => 'AUD',
                'locale' => 'en_AU',
                'timezone' => 'Australia/Sydney',
                'root_category_id' => 5,
            ],
        ];

        foreach ($websites as $config) {
            $output->writeln("Creating website: {$config['code']}");
            // Execute creation commands...
            $this->createWebsite($config, $output);
        }

        return Command::SUCCESS;
    }

    private function createWebsite(array $config, OutputInterface $output): void
    {
        // Implementation: create Website → Group → StoreView → set config
    }
}
在自定义模块中读取范围配置
<?php
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;

class StoreAwareConfig
{
    public function __construct(
        private readonly ScopeConfigInterface $scopeConfig
    ) {}

    public function getWebsiteConfig(string $path, ?string $websiteCode = null): mixed
    {
        return $this->scopeConfig->getValue(
            $path,
            ScopeInterface::SCOPE_WEBSITE,
            $websiteCode // null = current website
        );
    }

    public function getStoreConfig(string $path, ?string $storeCode = null): mixed
    {
        return $this->scopeConfig->getValue(
            $path,
            ScopeInterface::SCOPE_STORE,
            $storeCode // null = current store view
        );
    }

    // Usage
    public function getShippingOriginCountry(): string
    {
        return (string)$this->getStoreConfig('shipping/origin/country_id');
    }
}

最佳实践

  • 语言变体使用店铺代码路由(MAGE_RUN_TYPE=store),仅在需要独立客户群、订单和支付方式时使用 Website 路由(MAGE_RUN_TYPE=website)
  • 上线前启用 Website 范围的定价——之后从全局范围切换到 Website 范围需要完整重建价格索引,并可能破坏现有目录规则
  • 在 nginx/Apache 层设置 MAGE_RUN_CODE 和 MAGE_RUN_TYPE,不要在 index.php 中设置——这样可将路由配置保留在基础设施层,并便于复制
  • 分别测试每个 Website 的结账流程——支付网关、税类和配送方式都可以按 Website 配置;一个 Website 的结账流程正常,并不意味着其他 Website 也正常
  • 每次执行 config:set 后清理配置缓存——范围配置更改会被缓存;自动化预配置脚本执行后,请运行 bin/magento cache:clean config
  • 在高流量环境中为每个 Website 使用独立的 Redis 数据库——某个 Website 的缓慢重新索引可能耗尽共享缓存存储资源并影响所有 Website
  • 记录 Website/Store/Store View ID 的对应关系——ID 会因环境而异;所有配置脚本中都应使用代码(uk_en),而不是数字 ID

常见问题

问题解决方案
新网站显示全局价格,忽略网站配置启用网站范围的定价:先运行 bin/magento config:set catalog/price/scope 1,然后重新索引 catalog_product_price
nginx 未将 MAGE_RUN_CODE 传递给 PHP确认 fastcgi_param MAGE_RUN_CODE 位于 location ~ \.php$ 块内,而非块外——这是常见的配置位置错误
来自一个网站的客户可以登录另一个网站默认情况下,设置了 MAGE_RUN_TYPE=website 的网站会共用客户池,除非你启用了按网站范围设置的客户账户共享:Admin → Config → Customer → Account Sharing
产品显示在错误的网站上在 Admin → Catalog 中检查产品的“Product in Websites”属性;必须将产品明确分配到其应显示的每个网站
范围配置未生效配置值会被缓存——更改后务必运行 bin/magento cache:clean config;还要确认范围代码的拼写完全一致
B2B 共享目录未筛选产品客户必须分配给具有正确目录的公司;访客和未加入公司的客户只能看到公共共享目录

相关技能

  • @magento-module-development
  • @magento-graphql
  • @magento-indexing-caching
  • @international-ecommerce
  • @b2b-commerce

评论

支持 Markdown