Magento 2 可以在后台创建商品属性,也可以通过模块 Data Patch 管理。需要在多个环境稳定部署时,推荐把属性定义写进代码,避免测试、预发布和生产环境配置不一致。

创建 Data Patch

文件:app/code/Alwayly/CatalogSetup/Setup/Patch/Data/AddMaterialAttribute.php

<?php
declare(strict_types=1);
namespace Alwayly\CatalogSetup\Setup\Patch\Data;

use Magento\Catalog\Model\Product;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

final class AddMaterialAttribute implements DataPatchInterface
{
    public function __construct(
        private readonly ModuleDataSetupInterface $moduleDataSetup,
        private readonly EavSetupFactory $eavSetupFactory
    ) {}

    public function apply(): self
    {
        $this->moduleDataSetup->getConnection()->startSetup();
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $eavSetup->addAttribute(Product::ENTITY, 'alwayly_material', [
            'type' => 'varchar',
            'label' => 'Material',
            'input' => 'text',
            'required' => false,
            'sort_order' => 120,
            'global' => ScopedAttributeInterface::SCOPE_STORE,
            'visible' => true,
            'user_defined' => true,
            'searchable' => true,
            'filterable' => false,
            'comparable' => true,
            'visible_on_front' => true,
            'used_in_product_listing' => true
        ]);
        $this->moduleDataSetup->getConnection()->endSetup();
        return $this;
    }

    public static function getDependencies(): array { return []; }
    public function getAliases(): array { return []; }
}

选择正确的后端类型

短文本通常使用 varchar,长文本使用 text,整数和选项值常用 int。类型一旦上线并产生数据,不应随意修改,否则可能造成数据迁移问题。

属性作用范围

  • Global:所有网站和商店共用。
  • Website:同一网站下共用。
  • Store View:每个商店视图可单独设置。

示例使用 Store View 范围,适合多语言材质名称。若只是内部编码,应使用 Global,避免重复维护。

执行和检查

bin/magento setup:upgrade
bin/magento cache:clean config eav
bin/magento indexer:reindex catalog_product_attribute catalogsearch_fulltext

运行后在后台打开属性集,确认新属性位于预期分组。部分项目需要在 Patch 中显式把属性加入指定属性集和属性组,不能假设所有自定义属性集都会自动出现。

前台读取

$attribute = $product->getCustomAttribute('alwayly_material');
$value = $attribute ? (string)$attribute->getValue() : '';

如果是下拉选项,前台通常需要读取选项文本,而不是直接输出 option ID。模板中还要进行正确的 HTML 转义。

验证清单

  1. 简单、可配置和虚拟商品都能保存属性。
  2. 不同 store view 的值符合作用范围。
  3. 搜索与商品列表索引能读取新属性。
  4. API 返回值符合预期。
  5. 重复执行 setup:upgrade 不会重复创建。