wix-cli-site-plugin

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Wix Site Plugin Builder

Wix 站点插件构建工具

Creates site plugin extensions for Wix CLI applications. Site plugins are custom elements that integrate into predefined slots within Wix business solutions (like Wix Stores, Wix Bookings), extending their functionality and user experience.
Site owners can place site plugins into UI slots using the plugin explorer in Wix editors.
为Wix CLI应用创建站点插件扩展。站点插件是可集成到Wix商业解决方案(如Wix Stores、Wix Bookings)中预定义插槽的自定义元素,用于扩展其功能和用户体验。
站点所有者可通过Wix编辑器中的插件资源管理器将站点插件放置到UI插槽中。

Quick Start Checklist

快速入门清单

Follow these steps in order when creating a site plugin:
  1. Create plugin folder:
    src/extensions/site/plugins/<plugin-name>/
  2. Create
    <plugin>.tsx
    extending
    HTMLElement
    with
    observedAttributes
  3. Create
    <plugin>.panel.tsx
    with WDS components and
    widget.getProp/setProp
  4. Create
    <plugin>.extension.ts
    with
    extensions.sitePlugin()
    and unique UUID
  5. Update
    src/extensions.ts
    to import and use the new extension
  6. Run
    npx tsc --noEmit
    to verify TypeScript compiles
  7. Run
    npx wix build
    and
    npx wix preview
    to test
  8. Verify plugin appears in plugin explorer for target slots
创建站点插件时,请按以下顺序执行步骤:
  1. 创建插件文件夹:
    src/extensions/site/plugins/<plugin-name>/
  2. 创建继承
    HTMLElement
    并包含
    observedAttributes
    <plugin>.tsx
    文件
  3. 创建包含WDS组件和
    widget.getProp/setProp
    <plugin>.panel.tsx
    文件
  4. 创建包含
    extensions.sitePlugin()
    和唯一UUID的
    <plugin>.extension.ts
    文件
  5. 更新
    src/extensions.ts
    以导入并使用新扩展
  6. 运行
    npx tsc --noEmit
    验证TypeScript编译通过
  7. 运行
    npx wix build
    npx wix preview
    进行测试
  8. 验证插件在目标插槽的插件资源管理器中显示

Architecture

架构

Site plugins consist of three required files:
站点插件包含三个必填文件

1. Plugin Component (
<plugin-name>.tsx
)

1. 插件组件(
<plugin-name>.tsx

Custom element component that renders in the slot using native HTMLElement:
  • Extend
    HTMLElement
    class
  • Define
    observedAttributes
    for reactive properties
  • Implement
    connectedCallback()
    and
    attributeChangedCallback()
    for rendering
  • Use inline styles via template strings
  • Attributes use kebab-case (e.g.,
    display-name
    )
在插槽中渲染的自定义元素组件,基于原生HTMLElement:
  • 继承
    HTMLElement
  • 定义
    observedAttributes
    以声明响应式属性
  • 实现
    connectedCallback()
    attributeChangedCallback()
    用于渲染
  • 通过模板字符串使用内联样式
  • 属性采用短横线命名法(如
    display-name

2. Settings Panel (
<plugin-name>.panel.tsx
)

2. 设置面板(
<plugin-name>.panel.tsx

Settings panel shown in the Wix Editor sidebar:
  • Uses Wix Design System components (see WDS-COMPONENTS.md)
  • Manages plugin properties via
    @wix/editor
    widget API
  • Loads initial values with
    widget.getProp('kebab-case-name')
  • Updates properties with
    widget.setProp('kebab-case-name', value)
  • Wrapped in
    WixDesignSystemProvider > SidePanel > SidePanel.Content
在Wix编辑器侧边栏显示的设置面板:
  • 使用Wix设计系统组件(详见WDS-COMPONENTS.md
  • 通过
    @wix/editor
    widget API管理插件属性
  • 使用
    widget.getProp('kebab-case-name')
    加载初始值
  • 使用
    widget.setProp('kebab-case-name', value)
    更新属性
  • 包裹在
    WixDesignSystemProvider > SidePanel > SidePanel.Content

3. Extension Configuration (
<plugin-name>.extension.ts
)

3. 扩展配置(
<plugin-name>.extension.ts

Defines the plugin's placement configuration:
  • Specifies which slots the plugin can be added to
  • Configures auto-add behavior on app installation
  • Sets the tag name and file paths
定义插件的放置配置:
  • 指定插件可添加到的插槽
  • 配置应用安装时的自动添加行为
  • 设置标签名称和文件路径

Plugin Component Pattern

插件组件模式

Site plugins use native
HTMLElement
custom elements:
typescript
// 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;
Key Points:
  • Extend
    HTMLElement
    class directly
  • Define
    observedAttributes
    static getter to list reactive attributes
  • Attributes use kebab-case (e.g.,
    display-name
    ,
    bg-color
    )
  • Implement
    connectedCallback()
    for initial render
  • Implement
    attributeChangedCallback()
    to re-render when attributes change
  • Use inline styles via template strings
  • Use
    this.getAttribute('attribute-name')
    to read attribute values
站点插件使用原生
HTMLElement
自定义元素:
typescript
// 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
    静态getter以列出响应式属性
  • 属性采用短横线命名法(如
    display-name
    bg-color
  • 实现
    connectedCallback()
    用于初始渲染
  • 实现
    attributeChangedCallback()
    以便属性变化时重新渲染
  • 通过模板字符串使用内联样式
  • 使用
    this.getAttribute('attribute-name')
    读取属性值

Settings Panel Pattern

设置面板模式

typescript
// 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;
Key Points:
  • Prop names in
    widget.getProp()
    and
    widget.setProp()
    use kebab-case (e.g.,
    "display-name"
    )
  • Always update both local state AND widget prop in onChange handlers
  • Wrap content in
    WixDesignSystemProvider > SidePanel > SidePanel.Content
  • Use WDS components from
    @wix/design-system
  • Import
    @wix/design-system/styles.global.css
    for styles
  • Include
    aria-label
    for accessibility
typescript
// 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处理程序中始终同时更新本地状态和widget属性
  • 将内容包裹在
    WixDesignSystemProvider > SidePanel > SidePanel.Content
  • 使用
    @wix/design-system
    中的WDS组件
  • 导入
    @wix/design-system/styles.global.css
    以应用样式
  • 包含
    aria-label
    以满足无障碍要求

Attribute Naming Convention

属性命名规范

Site plugins use kebab-case consistently for HTML attributes:
FileConventionExample
<plugin>.tsx
(getAttribute)
kebab-case
this.getAttribute('display-name')
<plugin>.tsx
(observedAttributes)
kebab-case
['display-name', 'bg-color']
<plugin>.panel.tsx
(widget API)
kebab-case
widget.getProp('display-name')
站点插件的HTML属性统一采用短横线命名法
文件命名规范示例
<plugin>.tsx
(getAttribute)
短横线命名法
this.getAttribute('display-name')
<plugin>.tsx
(observedAttributes)
短横线命名法
['display-name', 'bg-color']
<plugin>.panel.tsx
(widget API)
短横线命名法
widget.getProp('display-name')

Output Structure

输出结构

Site plugins live under
src/extensions/site/plugins
. Each plugin has its own folder with files named after the plugin.
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)
站点插件位于
src/extensions/site/plugins
目录下。每个插件拥有独立文件夹,文件名称与插件名称一致。
src/extensions/site/plugins/
└── {plugin-name}/
    ├── {plugin-name}.tsx           # 主插件组件(HTMLElement)
    ├── {plugin-name}.panel.tsx     # 设置面板组件
    └── {plugin-name}.extension.ts  # 扩展注册文件
public/
└── {plugin-name}-logo.svg          # 插件图标(可选)

References

参考资料

TopicReference
Complete ExamplesEXAMPLES.md
Slots (App IDs, multiple placements, finding slots)SLOTS.md
WDS ComponentsWDS-COMPONENTS.md
主题参考链接
完整示例EXAMPLES.md
插槽(应用ID、多位置部署、查找插槽)SLOTS.md
WDS组件WDS-COMPONENTS.md

Available Slots

可用插槽

Site plugins integrate into predefined slots in Wix business solutions. Each slot is identified by:
  • appDefinitionId: The ID of the Wix app (e.g., Stores, Bookings)
  • widgetId: The ID of the page containing the slot
  • slotId: The specific slot identifier
Common placement areas include product pages (Wix Stores), booking pages (Wix Bookings), service pages, and event pages.
For supported pages, common Wix App IDs, and how to find slot IDs, see SLOTS.md.
站点插件可集成到Wix商业解决方案中的预定义插槽中。每个插槽通过以下标识区分:
  • appDefinitionId:Wix应用的ID(如Stores、Bookings)
  • widgetId:包含插槽的页面ID
  • slotId:具体插槽的标识符
常见放置区域包括产品页面(Wix Stores)、预订页面(Wix Bookings)、服务页面和活动页面。
如需了解支持的页面、常见Wix应用ID以及如何查找插槽ID,请查看SLOTS.md

Extension Registration

扩展注册

Extension registration is MANDATORY and has TWO required steps.
扩展注册是强制性的,包含两个必填步骤。

Step 1: Create Plugin-Specific Extension File

步骤1:创建插件专属扩展文件

Each site plugin requires an extension file in its folder:
typescript
// 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',
});
CRITICAL: UUID Generation
The
id
must be a unique, static UUID v4 string. Generate a fresh UUID for each extension - do NOT use
randomUUID()
or copy UUIDs from examples. Replace
{{GENERATE_UUID}}
with a freshly generated UUID like
"95a28afd-7df1-4e09-9ec1-ce710b0389a0"
.
PropertyTypeDescription
id
stringUnique static UUID v4 (generate fresh)
name
stringInternal name for the plugin
marketData.name
stringDisplay name in plugin explorer and app dashboard
marketData.description
stringDescription shown in plugin explorer and app dashboard
marketData.logoUrl
stringPath to logo file (
{{BASE_URL}}
resolves to public folder)
placements
arrayArray of slot placements where plugin can be added
placements.appDefinitionId
stringID of the Wix app containing the slot
placements.widgetId
stringID of the page containing the slot
placements.slotId
stringID of the specific slot
installation.autoAdd
booleanWhether to auto-add plugin to slots on app installation
tagName
stringHTML custom element tag (kebab-case, must contain a hyphen)
element
stringRelative path to plugin component
settings
stringRelative path to settings panel component
每个站点插件在其文件夹中需要一个扩展文件:
typescript
// 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}}
替换为新生成的UUID,例如
"95a28afd-7df1-4e09-9ec1-ce710b0389a0"
属性类型描述
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具体插槽的标识符
installation.autoAdd
boolean应用安装时是否自动将插件添加到插槽中
tagName
stringHTML自定义元素标签(短横线命名法,必须包含连字符)
element
string插件组件的相对路径
settings
string设置面板组件的相对路径

Step 2: Register in Main Extensions File

步骤2:在主扩展文件中注册

CRITICAL: After creating the plugin-specific extension file, you MUST read wix-cli-extension-registration and follow the "App Registration" section to update
src/extensions.ts
.
Without completing Step 2, the site plugin will not be available in the plugin explorer.
**重要提示:**创建插件专属扩展文件后,必须阅读wix-cli-extension-registration并按照「应用注册」部分的说明更新
src/extensions.ts
未完成步骤2的情况下,站点插件将不会在插件资源管理器中显示。

Examples

示例

For complete examples with all three required files (plugin component, settings panel, extension configuration), see EXAMPLES.md.
Example use cases:
  • Best Seller Badge - Customizable badge on product pages with text and color settings
  • Booking Confirmation - Custom confirmation message for booking pages
  • Product Reviews Summary - Star rating and review count display
  • Data-Driven Plugin - Plugin with Wix Data API integration and editor environment handling
如需包含所有三个必填文件(插件组件、设置面板、扩展配置)的完整示例,请查看EXAMPLES.md
示例用例:
  • 畅销商品徽章 - 产品页面上的可自定义徽章,支持文本和颜色设置
  • 预订确认信息 - 预订页面的自定义确认消息
  • 产品评论摘要 - 星级评分和评论数量展示
  • 数据驱动插件 - 集成Wix Data API并处理编辑器环境的插件

Best Practices

最佳实践

Implementation Guidelines

实现指南

  • Use inline styles - CSS imports are not supported in custom elements
  • Handle editor environment - Show placeholders when in editor mode for data-dependent plugins
  • Editor sandboxing - Plugins are sandboxed in the Editor;
    localStorage
    ,
    sessionStorage
    , and cookies are restricted. Use
    viewMode()
    to detect editor and mock storage if needed
  • Validate all input - Check required props are present
  • Follow naming conventions - kebab-case for all attributes and widget API
  • Keep plugins focused - Each plugin should do one thing well
  • Test in multiple slots - If supporting multiple placements, test each one
  • 使用内联样式 - 自定义元素不支持CSS导入
  • 处理编辑器环境 - 对于依赖数据的插件,在编辑器模式下显示占位符
  • 编辑器沙箱限制 - 插件在编辑器中处于沙箱环境;
    localStorage
    sessionStorage
    和Cookie受到限制。可使用
    viewMode()
    检测编辑器环境并模拟存储
  • 验证所有输入 - 检查必填属性是否存在
  • 遵循命名规范 - 所有属性和widget API使用短横线命名法
  • 保持插件聚焦 - 每个插件应专注于完成单一功能
  • 在多插槽中测试 - 如果支持多个位置,请在每个位置进行测试

Performance Considerations

性能考量

  • Keep bundle size small - plugins load on user-facing pages
  • Avoid heavy computations on initial render
  • Lazy load data when possible
  • Use efficient re-rendering patterns
  • 保持包体积小巧 - 插件会在用户页面加载
  • 避免初始渲染时的大量计算
  • 尽可能懒加载数据
  • 使用高效的重新渲染模式

Verification

验证

After implementation, use wix-cli-app-validation to validate TypeScript compilation, build, preview, and runtime behavior.
实现完成后,使用wix-cli-app-validation验证TypeScript编译、构建、预览和运行时行为。

Code Quality Requirements

代码质量要求

  • Strict TypeScript (no
    any
    , explicit return types)
  • Native HTMLElement class for plugin components
  • React functional components with hooks for settings panels
  • Proper error handling and loading states
  • No
    @ts-ignore
    comments
  • Inline styles via template strings (no CSS imports)
  • Handle Wix Editor environment when using Wix Data API
  • Consistent attribute naming using kebab-case throughout
  • 严格TypeScript规范(禁止
    any
    类型,显式声明返回类型)
  • 插件组件使用原生HTMLElement类
  • 设置面板使用React函数式组件和Hooks
  • 完善的错误处理和加载状态
  • 禁止
    @ts-ignore
    注释
  • 通过模板字符串使用内联样式(禁止CSS导入)
  • 使用Wix Data API时处理Wix编辑器环境
  • 全程统一使用短横线命名法命名属性