bagisto-attribute-development について
Bagistoの商品属性、ファミリー、オプション、値を変更するための開発スキルです。EAVの保存モデルと、商品データ編集時に守るべきロケールおよびチャネルのルールを説明します。
主な機能
- 01EAVによる商品データ保存を説明
- 02属性タイプと値カラムの対応を提示
- 03ロケールとチャネルのスコープを解説
- 04ファミリー、グループ、オプション、検証を網羅
- 05Repository経由のデータ変更を案内
- 06フラットインデックス更新の要件を説明
活用シーン
- 01Bagistoの商品属性を追加・変更
- 02ロケールやチャネル間で値が欠ける問題を調査
- 03select値をオプションIDで保存
- 04一覧属性の更新後に商品を再インデックス
MCP 対応
MCPサーバーではなく、開発スキルです。入力にはMCP連携の説明がありません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bagisto/ agent-skills --skill bagisto-attribute-developmentインストール後、Claude Code で/bagisto-attribute-developmentを入力して読み込まれたか確認します。
同梱ファイルattributes.mdeav.md
詳細
属性開発
Bagisto では、商品データは products の列ではなく、EAV(エンティティ、属性、値)として保存されます。商品行に含まれる情報はごくわずかで、名前、価格、説明、すべてのカスタムフィールドは product_attribute_values に、属性、ロケール、チャネルごとに1行ずつ保存されます。
Bagisto での間違いの多くは、この概念を正しく理解していないことに起因します。そのため、商品データに関わる変更を行う前に、eav.mdを読むことをおすすめします。
参照ファイル
| ファイル | 読むタイミング |
|---|---|
| eav.md | 値の保存と解決方法 — 列の対応表、スコープ、フラットインデックス |
| attributes.md | 属性、ファミリー、グループ、オプション、バリデーション、スウォッチの作成 |
構造
attribute_families a product type's whole form (e.g. "Default")
└── attribute_groups a tab/section within it (e.g. "General")
└── attributes a field (e.g. "name")
└── attribute_options for select, multiselect and checkbox
商品は1つのファミリーに属し、そのファミリーによって使用する属性が決まります。AttributeFamily::custom_attributes()とAttributeGroup::custom_attributes()は、それらをたどるリレーションです。
列の対応表
属性のtypeによって、product_attribute_valuesのどの列に値を格納するかが決まります。
| type | 列 |
|---|---|
text、textarea、multiselect、checkbox、file、image | text_value |
price | float_value |
boolean | boolean_value |
select | integer_value |
date | date_value |
datetime | datetime_value |
この対応表はAttribute::$attributeTypeFieldsにあり、モデルは解決済みの列名を$attribute->column_nameとして公開します。列を推測してはいけません。属性から読み取ってください。そうしないと、selectの値が誤ってtext_valueに書き込まれ、読み戻すとnullになります。
属性タイプの正式な一覧はAttributeTypeEnumです。その他の設定は、ValidationEnum(numeric、email、decimal、url、regex)とSwatchTypeEnum(dropdown、color、image、text)で定義されています。
スコープ:大半の不具合の原因となる2つのフラグ
各属性はvalue_per_localeとvalue_per_channelを持ちます。この2つのフラグによって、1つの商品に対する属性の行数と、読み取り時に返される値が決まります。
value_per_channel | value_per_locale | 商品ごとの行数 |
|---|---|---|
| false | false | 1 |
| false | true | ロケールごとに1行 |
| true | false | チャネルごとに1行 |
| true | true | チャネルとロケールの組み合わせごとに1行 |
Product::getCustomAttributeValue()は、要求されたチャネルとロケールに対応する行を解決します。要求された値が空の場合は、デフォルトのチャネルとロケールにフォールバックします。別のロケールで値が「消える」場合、そのほとんどは、これらのフラグを考慮せずに属性を書き込んでいることが原因です。
テーブルには(channel, locale, attribute_id, product_id)に一意インデックスが設定されており、これによってこのルールが強制されます。そのため、誤ったスコープの組み合わせで書き込むと、重複が黙って作成されるのではなく、制約違反になります。
必ず守ること
- リポジトリ経由で処理してください。
AttributeRepository、AttributeFamilyRepository、AttributeGroupRepository、AttributeOptionRepositoryを使用してください。product_attribute_valuesを直接書き換えてはいけません。 - 属性からカラムを読み取ってください。
column_nameまたは$attributeTypeFieldsを使用してください。テキスト型以外の属性が初めて使われたときに、 ハードコードされたカラムは不具合の原因になります。 - 書き込みのたびに
value_per_localeとvalue_per_channelを遵守してください。 読み取り時だけでは不十分です。 ロケールごとに値を持つ属性を1行だけ書き込むと、ほかのすべてのロケールの値が失われます。 select/multiselectの値はラベルではなくオプション ID です。selectはinteger_valueに ID を1つ保存し、multiselectはtext_valueにカンマ区切りの ID を保存します。- オプションラベルは翻訳可能です。 ラベルは
attribute_option_translationsに保存されるため、あるロケールで追加したラベルは、22すべてのロケールで追加する必要があります。 - 属性の
typeを変更すると、既存の値は参照されなくなります。 新しい型では別のカラムを読み取るためです。 編集ではなく、データマイグレーションとして扱ってください。 - 一覧表示に影響する変更をしたら再インデックスしてください。 フィルター可能属性と一覧表示属性は、フラットインデクサーによって
product_flatに非正規化して保存されます。インデックス処理が実行されるまでは、グリッドとストアフロントに古い値が表示されます。
必須のサブスキル: 変更完了と判断する前に、bagisto-change-verification を使用してください。