wix-cli-site-plugin について
wix-cli-site-pluginは、Wix CLIアプリ向けのサイトプラグイン開発スキルです。Wixの各ソリューションのスロットに配置するカスタム要素、エディター設定パネル、拡張機能の登録方法を案内します。
主な機能
- 01カスタム要素プラグインの構成
- 02Wix Editor設定パネル
- 03スロット配置と登録
- 04プロパティと属性の連携
- 05カラー・フォントピッカー
活用シーン
- 01商品ページに設定可能なバッジを追加
- 02予約ページに確認メッセージを表示
- 03商品レビューの概要を表示
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wix/ skills --skill wix-cli-site-pluginインストール後、Claude Code で/wix-cli-site-pluginを入力して読み込まれたか確認します。
同梱ファイルreferences/EXAMPLES.mdreferences/SLOTS.md
詳細
Wix サイトプラグインビルダー
Wix CLI アプリケーション向けのサイトプラグイン拡張機能を作成します。サイトプラグインは、Wix のビジネスソリューション(Wix Stores、Wix Bookings、Wix eCommerce など)にあらかじめ定義されたスロットに統合され、機能とユーザーエクスペリエンスを拡張するカスタム要素です。
サイトオーナーは、Wix エディターのプラグインエクスプローラーを使用して、サイトプラグインを UI スロットに配置できます。
クイックスタートチェックリスト
サイトプラグインを作成するときは、次の手順を順番に実行してください。
- プラグインフォルダーを作成します:
src/extensions/site/plugins/<plugin-name>/ -
observedAttributesを実装したHTMLElementを拡張する<plugin-name>.tsxを作成します - WDS コンポーネントと
widget.getProp/setPropを使用する<plugin-name>.panel.tsxを作成します -
extensions.sitePlugin()と一意の UUID を使用する<plugin-name>.extension.tsを作成します -
src/extensions.tsを更新し、新しい拡張機能をインポートして使用します
アーキテクチャ
サイトプラグインは必須ファイル 3 つで構成されます。
1. プラグインコンポーネント(<plugin-name>.tsx)
ネイティブの HTMLElement を使用して、スロット内に表示されるカスタム要素コンポーネントです。
HTMLElementクラスを拡張します- リアクティブなプロパティ用に
observedAttributesを定義します - レンダリング用に
connectedCallback()とattributeChangedCallback()を実装します - テンプレート文字列を使ってインラインスタイルを指定します
- 属性にはケバブケースを使用します(例:
display-name)
2. 設定パネル(<plugin-name>.panel.tsx)
Wix エディターのサイドバーに表示される設定パネルです。
- Wix Design System(
@wix/design-system)のコンポーネントを使用します。コンポーネントのリファレンスについては、wds-docs を参照してください @wix/editorのウィジェット API を使ってプラグインのプロパティを管理しますwidget.getProp('kebab-case-name')で初期値を読み込みますwidget.setProp('kebab-case-name', value)でプロパティを更新します- ウィジェットのプロパティはカスタム要素の属性にバインドされているため、プロパティを変更すると対応する属性が自動的に更新されます
WixDesignSystemProvider > SidePanel > SidePanel.Contentでラップします
3. 拡張機能の設定(<plugin-name>.extension.ts)
プラグインの配置設定を定義します。
- プラグインを追加できるスロットを指定します
- アプリのインストール時に自動追加する動作を設定します
- タグ名とファイルパスを設定します
プラグインコンポーネントのパターン
サイトプラグインでは、ネイティブの HTMLElement カスタム要素を使用します。
// my-site-plugin.tsx
class MyElement extends HTMLElement {
static get observedAttributes() {
return ['display-name'];
}
constructor() {
super();
}
connectedCallback() {
this.render();
}
attributeChangedCallback() {
this.render();
}
render() {
const displayName = this.getAttribute('display-name') || "Your Plugin's Title";
this.innerHTML = `
<div style="font-size: 16px; padding: 16px; border: 1px solid #ccc; border-radius: 8px; margin: 16px;">
<h2>${displayName}</h2>
<hr />
<p>
This is a Site Plugin generated by Wix CLI.<br />
Edit your element's code to change this text.
</p>
</div>
`;
}
}
export default MyElement;
重要なポイント:
HTMLElementクラスを直接拡張します- リアクティブな属性を列挙する
observedAttributes静的ゲッターを定義します - 属性にはケバブケースを使用します(例:
display-name、bg-color) - 初回レンダリング用に
connectedCallback()を実装します - 属性の変更時に再レンダリングするため、
attributeChangedCallback()を実装します - テンプレート文字列を使ってインラインスタイルを指定します
this.getAttribute('attribute-name')を使って属性値を読み取りますdefine()は Wix が処理するため、コード内でcustomElements.define()を呼び出さないでください
設定パネルのパターン
// my-site-plugin.panel.tsx
import React, { type FC, useState, useEffect, useCallback } from 'react';
import { widget } from '@wix/editor';
import {
SidePanel,
WixDesignSystemProvider,
Input,
FormField,
} from '@wix/design-system';
import '@wix/design-system/styles.global.css';
const Panel: FC = () => {
const [displayName, setDisplayName] = useState<string>('');
useEffect(() => {
widget.getProp('display-name')
.then(displayName => setDisplayName(displayName || "Your Plugin's Title"))
.catch(error => console.error('Failed to fetch display-name:', error));
}, [setDisplayName]);
const handleDisplayNameChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const newDisplayName = event.target.value;
setDisplayName(newDisplayName);
widget.setProp('display-name', newDisplayName);
}, [setDisplayName]);
return (
<WixDesignSystemProvider>
<SidePanel width="300" height="100vh">
<SidePanel.Content noPadding stretchVertically>
<SidePanel.Field>
<FormField label="Display Name">
<Input
type="text"
value={displayName}
onChange={handleDisplayNameChange}
aria-label="Display Name"
/>
</FormField>
</SidePanel.Field>
</SidePanel.Content>
</SidePanel>
</WixDesignSystemProvider>
);
};
export default Panel;
重要なポイント:
widget.getProp()とwidget.setProp()のプロパティ名にはケバブケースを使用します(例:"display-name")onChangeハンドラーでは、ローカル状態とウィジェットのプロパティの両方を必ず更新します- ウィジェットのプロパティはカスタム要素の属性にバインドされているため、変更すると対応する属性が自動的に更新されます
- コンテンツは
WixDesignSystemProvider > SidePanel > SidePanel.Contentでラップします @wix/design-systemの WDS コンポーネントを使用します- スタイルには
@wix/design-system/styles.global.cssをインポートします - アクセシビリティのために
aria-labelを含めます
カラーおよびフォントのピッカーフィールド
サイトプラグインの設定パネルでは、@wix/editor の inputs.selectColor() と inputs.selectFont() を使用して、Wix エディター標準のカラーおよびフォントピッカーダイアログを開けます。
ColorPickerField
テーマカラーやグラデーションなどを含む Wix カラーピッカーを開きます。基本的な HTML の <input type="color"> ではありません。
import React, { type FC } from 'react';
import { inputs } from '@wix/editor';
import { FormField, Box, FillPreview, SidePanel } from '@wix/design-system';
interface ColorPickerFieldProps {
label: string;
value: string;
onChange: (value: string) => void;
}
export const ColorPickerField: FC<ColorPickerFieldProps> = ({
label,
value,
onChange,
}) => (
<SidePanel.Field>
<FormField label={label}>
<Box width="30px" height="30px">
<FillPreview
fill={value}
onClick={() => inputs.selectColor(value, { onChange: (val) => { if (val) onChange(val); } })}
/>
</Box>
</FormField>
</SidePanel.Field>
);
FontPickerField
フォントファミリー、サイズ、太字、斜体などのタイポグラフィ機能を備えた Wix フォントピッカーを開きます。
import React, { type FC } from 'react';
import { inputs } from '@wix/editor';
import { FormField, Button, Text, SidePanel } from '@wix/design-system';
interface FontValue {
font: string;
textDecoration: string;
}
interface FontPickerFieldProps {
label: string;
value: FontValue;
onChange: (value: FontValue) => void;
}
export const FontPickerField: FC<FontPickerFieldProps> = ({
label,
value,
onChange,
}) => (
<SidePanel.Field>
<FormField label={label}>
<Button
size="small"
priority="secondary"
onClick={() => inputs.selectFont(value, { onChange: (val) => onChange({ font: val.font, textDecoration: val.textDecoration || "" }) })}
fullWidth
>
<Text size="small" ellipsis>Change Font</Text>
</Button>
</FormField>
</SidePanel.Field>
);
重要:
- 必ず
@wix/editorのinputs.selectColor()をFillPreviewとともに使用してください。<Input type="color">は使用しないでください。 - 必ず
@wix/editorのinputs.selectFont()を、コールバックパターンinputs.selectFont(value, { onChange })で使用してください。 inputsは@wix/sdkではなく、@wix/editorからインポートしてください。
属性の命名規則
サイトプラグインでは、HTML 属性に一貫して kebab-case を使用します。
| ファイル | 規則 | 例 |
|---|---|---|
<plugin>.tsx(getAttribute) | kebab-case | this.getAttribute('display-name') |
<plugin>.tsx(observedAttributes) | kebab-case | ['display-name', 'bg-color'] |
<plugin>.panel.tsx(ウィジェット API) | kebab-case | widget.getProp('display-name') |
出力構成
サイトプラグインは src/extensions/site/plugins の下に配置します。各プラグインには専用のフォルダーがあり、その中のファイルにはプラグイン名が付けられています。
src/extensions/site/plugins/
└── {plugin-name}/
├── {plugin-name}.tsx # Main plugin component (HTMLElement)
├── {plugin-name}.panel.tsx # Settings panel component
└── {plugin-name}.extension.ts # Extension registration
public/
└── {plugin-name}-logo.svg # Plugin logo (optional)
参考資料
| トピック | 参考資料 |
|---|---|
| 完全な例 | EXAMPLES.md |
| スロット(アプリ ID、複数の配置場所、スロットの確認方法) | SLOTS.md |
| WDS コンポーネント | wds-docs |
利用可能なスロット
サイトプラグインは、Wix のビジネスソリューションにあらかじめ定義されたスロットに統合されます。各スロットは次の要素で識別されます。
- appDefinitionId:Wix アプリの ID(例:Stores、Bookings)
- widgetId:スロットを含むページの ID
- slotId:個々のスロットを識別する ID
一般的な配置場所には、商品ページ(Wix Stores)、チェックアウトおよびサイドカート(Wix eCommerce)、予約ページ(Wix Bookings)、サービスページ、イベントページ、ブログ記事ページなどがあります。
対応ページ、一般的な Wix アプリ ID、スロット ID の確認方法については、SLOTS.md を参照してください。
拡張機能の登録
拡張機能の登録は必須であり、2 つの手順が必要です。
ステップ 1:プラグイン固有の拡張ファイルを作成する
各サイトプラグインには、そのフォルダー内に拡張ファイルが必要です。
// my-site-plugin.extension.ts
import { extensions } from '@wix/astro/builders';
export default extensions.sitePlugin({
id: '{{GENERATE_UUID}}',
name: 'My Site Plugin',
marketData: {
name: 'My Site Plugin',
description: 'Marketing Description',
logoUrl: '{{BASE_URL}}/my-site-plugin-logo.svg',
},
placements: [{
appDefinitionId: 'a0c68605-c2e7-4c8d-9ea1-767f9770e087',
widgetId: '6a25b678-53ec-4b37-a190-65fcd1ca1a63',
slotId: 'product-page-details-6',
}],
installation: { autoAdd: true },
tagName: 'my-site-plugin',
element: './extensions/site/plugins/my-site-plugin/my-site-plugin.tsx',
settings: './extensions/site/plugins/my-site-plugin/my-site-plugin.panel.tsx',
});
重要:UUID の生成
id は一意で固定の UUID v4 文字列である必要があります。拡張ごとに新しい UUID を生成してください。randomUUID() を使用したり、例にある UUID をコピーしたりしないでください。{{GENERATE_UUID}} を、"95a28afd-7df1-4e09-9ec1-ce710b0389a0" のように新しく生成した UUID に置き換えてください。
| プロパティ | 型 | 説明 |
|---|---|---|
id | string | 一意で固定の UUID v4(新しく生成) |
name | string | プラグインの内部名 |
marketData.name | string | プラグインエクスプローラーとアプリダッシュボードに表示される名前 |
marketData.description | string | プラグインエクスプローラーとアプリダッシュボードに表示される説明 |
marketData.logoUrl | string | ロゴファイルへのパス({{BASE_URL}} は public フォルダーに解決されます) |
placements | array | プラグインを追加できるスロット配置の配列 |
placements.appDefinitionId | string | スロットを含む Wix アプリの ID |
placements.widgetId | string | スロットを含むページの ID |
placements.slotId | string | 特定のスロットの ID |
installation.autoAdd | boolean | アプリのインストール時にプラグインをスロットへ自動追加するかどうか |
tagName | string | HTML カスタム要素のタグ(ケバブケース。ハイフンを含める必要があります) |
element | string | プラグインコンポーネントへの相対パス |
settings | string | 設定パネルコンポーネントへの相対パス |
ステップ 2:メインの拡張ファイルに登録する
重要: プラグイン固有の拡張ファイルを作成したら、wix-cli-extension-registration を必ず読み、「App Registration」セクションの手順に従って src/extensions.ts を更新してください。
ステップ 2 を完了しないと、サイトプラグインはプラグインエクスプローラーで利用できません。
チェックアウトプラグイン
チェックアウトページ用のプラグインを作成する場合、インストール時の自動追加に対応していないことがあります。ユーザーがプラグインをサイトに追加する方法を提供するために、ダッシュボードページを作成する必要があります。ダッシュボードページのパターンについては、EXAMPLES.md を参照してください。
例
必要な 3 つのファイル(プラグインコンポーネント、設定パネル、拡張設定)をすべて含む完全な例については、EXAMPLES.md を参照してください。
ユースケースの例:
- ベストセラーバッジ - テキストと色を設定できる、商品ページ用のカスタマイズ可能なバッジ
- 予約確認 - 予約ページ用のカスタム確認メッセージ
- 商品レビューの概要 - 星評価とレビュー件数の表示
- データ駆動型プラグイン - Wix Data API との連携とエディター環境への対応を備えたプラグイン
ベストプラクティス
実装ガイドライン
- インラインスタイルを使用する - カスタム要素では CSS のインポートはサポートされていません
- エディター環境に対応する - データに依存するプラグインでは、エディターモード時にプレースホルダーを表示します
define()を呼び出さない -customElements.define()は Wix が自動的に処理します- すべての入力を検証する - 必須のプロパティが存在することを確認します
- 命名規則に従う - すべての属性とウィジェット API にケバブケースを使用します
- プラグインの目的を絞る - 各プラグインは 1 つの機能を適切に果たすようにします
- 複数のスロットでテストする - 複数の配置に対応する場合は、それぞれをテストします
- 両方の Stores バージョンをサポートする - 最大限の互換性を確保するため、旧バージョンと新バージョンの両方の Wix Stores 商品ページ用の配置を含めます
エディターのサンドボックス化
サイトプラグインは、エディターでレンダリングされる際にサンドボックス化されます。つまり、別のドメインから読み込まれたかのように扱われるため、ブラウザーのストレージ API へのアクセスに影響します。
エディターで制限される API:
localStorageおよびsessionStorage(Web Storage API)document.cookie(Cookie Store API)- IndexedDB API
- Cache API
サンドボックス化への対処方法:
制限される API にアクセスする前に、@wix/site-window の viewMode() 関数を使って現在のモードを確認します。
import { window as wixWindow } from '@wix/site-window';
const viewMode = await wixWindow.viewMode();
if (viewMode === 'Site') {
const item = localStorage.getItem('myKey');
} else {
// Mock storage or modify API usage for editor mode
}
サイトプラグインでの Wix SDK モジュールの使用
サイトプラグインでは、Wix SDK モジュールを直接インポートして使用できます。createClient() を使用する必要はありません。Wix ランタイムによって、クライアントコンテキストが自動的に提供されます。
// ✅ CORRECT — Import SDK modules directly
import { items } from "@wix/data";
import { currentCart } from "@wix/ecom";
import { products } from "@wix/stores";
class MyPlugin extends HTMLElement {
async loadData() {
// Call SDK methods directly — no createClient needed
const result = await items.query("MyCollection").find();
const cart = await currentCart.getCurrentCart();
const productList = await products.queryProducts().limit(10).find();
}
}
// ❌ WRONG — Do NOT use createClient in site plugins
import { createClient } from "@wix/sdk";
const wixClient = createClient({ modules: { items, products } });
await wixClient.items.query(...); // Wrong — API surface differs through client
パフォーマンスに関する考慮事項
- バンドルサイズを小さく保ちます。プラグインはユーザー向けページで読み込まれます。
- 初回レンダリング時の負荷の高い計算は避けます。
- 可能な場合は、データを遅延読み込みします。
- 効率的な再レンダリングのパターンを使用します。