elementor-development

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Elementor Addon & Widget Development

Elementor插件与小部件开发

Consolidated reference for addon architecture, widget creation, manager registration, scripts/styles, data structure, deprecations, and CLI commands.
See also:
  • Widget Rendering Details -- full control registration, render(), content_template(), render attributes
  • Data Structure, Deprecations & CLI -- JSON format, element structure, deprecation timeline, CLI commands

这是一份关于插件架构、小部件创建、管理器注册、脚本/样式、数据结构、弃用处理以及CLI命令的综合参考文档。
另请参阅:
  • 小部件渲染细节 -- 完整的控件注册、render()、content_template()、渲染属性说明
  • 数据结构、弃用处理与CLI -- JSON格式、元素结构、弃用时间线、CLI命令

1. Addon Structure

1. 插件结构

Plugin Header

插件头

Every Elementor addon requires standard WordPress headers plus optional Elementor headers.
php
<?php
/**
 * Plugin Name:      Elementor Test Addon
 * Description:      Custom Elementor addon.
 * Plugin URI:       https://elementor.com/
 * Version:          1.0.0
 * Author:           Elementor Developer
 * Author URI:       https://developers.elementor.com/
 * Text Domain:      elementor-test-addon
 * Requires Plugins: elementor
 *
 * Elementor tested up to: 3.25.0
 * Elementor Pro tested up to: 3.25.0
 */

defined( 'ABSPATH' ) || exit;

function elementor_test_addon() {
    require_once __DIR__ . '/includes/plugin.php';
    \Elementor_Test_Addon\Plugin::instance();
}
add_action( 'plugins_loaded', 'elementor_test_addon' );
每个Elementor插件都需要标准WordPress插件头,外加可选的Elementor专属头信息。
php
<?php
/**
 * Plugin Name:      Elementor Test Addon
 * Description:      Custom Elementor addon.
 * Plugin URI:       https://elementor.com/
 * Version:          1.0.0
 * Author:           Elementor Developer
 * Author URI:       https://developers.elementor.com/
 * Text Domain:      elementor-test-addon
 * Requires Plugins: elementor
 *
 * Elementor tested up to: 3.25.0
 * Elementor Pro tested up to: 3.25.0
 */

defined( 'ABSPATH' ) || exit;

function elementor_test_addon() {
    require_once __DIR__ . '/includes/plugin.php';
    \Elementor_Test_Addon\Plugin::instance();
}
add_action( 'plugins_loaded', 'elementor_test_addon' );

Main Class (Singleton + Compatibility Checks)

主类(单例模式 + 兼容性检查)

php
namespace Elementor_Test_Addon;

final class Plugin {

    const VERSION                  = '1.0.0';
    const MINIMUM_ELEMENTOR_VERSION = '3.20.0';
    const MINIMUM_PHP_VERSION      = '7.4';

    private static $_instance = null;

    public static function instance() {
        if ( is_null( self::$_instance ) ) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function __construct() {
        if ( $this->is_compatible() ) {
            add_action( 'elementor/init', [ $this, 'init' ] );
        }
    }

    public function is_compatible(): bool {
        if ( ! did_action( 'elementor/loaded' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_missing_main_plugin' ] );
            return false;
        }
        if ( ! version_compare( ELEMENTOR_VERSION, self::MINIMUM_ELEMENTOR_VERSION, '>=' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_minimum_elementor_version' ] );
            return false;
        }
        if ( version_compare( PHP_VERSION, self::MINIMUM_PHP_VERSION, '<' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_minimum_php_version' ] );
            return false;
        }
        return true;
    }

    public function init(): void {
        add_action( 'elementor/widgets/register', [ $this, 'register_widgets' ] );
        add_action( 'elementor/controls/register', [ $this, 'register_controls' ] );
    }

    public function register_widgets( $widgets_manager ): void {
        require_once __DIR__ . '/widgets/widget-1.php';
        $widgets_manager->register( new \Elementor_Widget_1() );
    }

    public function register_controls( $controls_manager ): void {
        require_once __DIR__ . '/controls/control-1.php';
        $controls_manager->register( new \Elementor_Control_1() );
    }
}
php
namespace Elementor_Test_Addon;

final class Plugin {

    const VERSION                  = '1.0.0';
    const MINIMUM_ELEMENTOR_VERSION = '3.20.0';
    const MINIMUM_PHP_VERSION      = '7.4';

    private static $_instance = null;

    public static function instance() {
        if ( is_null( self::$_instance ) ) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function __construct() {
        if ( $this->is_compatible() ) {
            add_action( 'elementor/init', [ $this, 'init' ] );
        }
    }

    public function is_compatible(): bool {
        if ( ! did_action( 'elementor/loaded' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_missing_main_plugin' ] );
            return false;
        }
        if ( ! version_compare( ELEMENTOR_VERSION, self::MINIMUM_ELEMENTOR_VERSION, '>=' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_minimum_elementor_version' ] );
            return false;
        }
        if ( version_compare( PHP_VERSION, self::MINIMUM_PHP_VERSION, '<' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_minimum_php_version' ] );
            return false;
        }
        return true;
    }

    public function init(): void {
        add_action( 'elementor/widgets/register', [ $this, 'register_widgets' ] );
        add_action( 'elementor/controls/register', [ $this, 'register_controls' ] );
    }

    public function register_widgets( $widgets_manager ): void {
        require_once __DIR__ . '/widgets/widget-1.php';
        $widgets_manager->register( new \Elementor_Widget_1() );
    }

    public function register_controls( $controls_manager ): void {
        require_once __DIR__ . '/controls/control-1.php';
        $controls_manager->register( new \Elementor_Control_1() );
    }
}

Folder Structure

文件夹结构

elementor-test-addon/
  elementor-test-addon.php      # Main file with headers
  includes/
    plugin.php                  # Main class (singleton)
    widgets/                    # Widget classes
    controls/                   # Custom controls
    dynamic-tags/               # Dynamic tag classes
    finder/                     # Finder category classes
  assets/
    js/                         # Frontend/editor JS
    css/                        # Frontend/editor CSS
    images/

elementor-test-addon/
  elementor-test-addon.php      # 带插件头的主文件
  includes/
    plugin.php                  # 主类(单例模式)
    widgets/                    # 小部件类
    controls/                   # 自定义控件
    dynamic-tags/               # 动态标签类
    finder/                     # 查找器分类类
  assets/
    js/                         # 前端/编辑器JS
    css/                        # 前端/编辑器CSS
    images/

2. Widget Development

2. 小部件开发

Widget Class Skeleton

小部件类骨架

php
class Elementor_Test_Widget extends \Elementor\Widget_Base {

    // --- Required ---
    public function get_name(): string {
        return 'test_widget';
    }

    public function get_title(): string {
        return esc_html__( 'Test Widget', 'textdomain' );
    }

    public function get_icon(): string {
        return 'eicon-code';
    }

    public function get_categories(): array {
        return [ 'general' ];
    }

    // --- Optional ---
    public function get_keywords(): array {
        return [ 'test', 'example' ];
    }

    public function get_custom_help_url(): string {
        return 'https://example.com/widget-help';
    }

    public function get_script_depends(): array {
        return [ 'widget-custom-script' ];
    }

    public function get_style_depends(): array {
        return [ 'widget-custom-style' ];
    }

    public function has_widget_inner_wrapper(): bool {
        return false; // DOM optimization: single wrapper
    }

    protected function is_dynamic_content(): bool {
        return false; // Enable output caching for static content
    }

    protected function get_upsale_data(): array {
        return [
            'condition'   => ! \Elementor\Utils::has_pro(),
            'image'       => esc_url( ELEMENTOR_ASSETS_URL . 'images/go-pro.svg' ),
            'image_alt'   => esc_attr__( 'Upgrade', 'textdomain' ),
            'title'       => esc_html__( 'Promotion heading', 'textdomain' ),
            'description' => esc_html__( 'Get the premium version.', 'textdomain' ),
            'upgrade_url' => esc_url( 'https://example.com/upgrade-to-pro/' ),
            'upgrade_text' => esc_html__( 'Upgrade Now', 'textdomain' ),
        ];
    }

    protected function register_controls(): void { /* see resources/widget-rendering.md */ }
    protected function render(): void { /* see resources/widget-rendering.md */ }
    protected function content_template(): void { /* see resources/widget-rendering.md */ }
}
php
class Elementor_Test_Widget extends \Elementor\Widget_Base {

    // --- 必填方法 ---
    public function get_name(): string {
        return 'test_widget';
    }

    public function get_title(): string {
        return esc_html__( 'Test Widget', 'textdomain' );
    }

    public function get_icon(): string {
        return 'eicon-code';
    }

    public function get_categories(): array {
        return [ 'general' ];
    }

    // --- 可选方法 ---
    public function get_keywords(): array {
        return [ 'test', 'example' ];
    }

    public function get_custom_help_url(): string {
        return 'https://example.com/widget-help';
    }

    public function get_script_depends(): array {
        return [ 'widget-custom-script' ];
    }

    public function get_style_depends(): array {
        return [ 'widget-custom-style' ];
    }

    public function has_widget_inner_wrapper(): bool {
        return false; // DOM优化:仅使用单个包裹层
    }

    protected function is_dynamic_content(): bool {
        return false; // 为静态内容启用输出缓存
    }

    protected function get_upsale_data(): array {
        return [
            'condition'   => ! \Elementor\Utils::has_pro(),
            'image'       => esc_url( ELEMENTOR_ASSETS_URL . 'images/go-pro.svg' ),
            'image_alt'   => esc_attr__( 'Upgrade', 'textdomain' ),
            'title'       => esc_html__( 'Promotion heading', 'textdomain' ),
            'description' => esc_html__( 'Get the premium version.', 'textdomain' ),
            'upgrade_url' => esc_url( 'https://example.com/upgrade-to-pro/' ),
            'upgrade_text' => esc_html__( 'Upgrade Now', 'textdomain' ),
        ];
    }

    protected function register_controls(): void { /* 详情请参阅resources/widget-rendering.md */ }
    protected function render(): void { /* 详情请参阅resources/widget-rendering.md */ }
    protected function content_template(): void { /* 详情请参阅resources/widget-rendering.md */ }
}

Register Custom Widget Category

注册自定义小部件分类

php
function add_elementor_widget_categories( $elements_manager ) {
    $elements_manager->add_category( 'my-category', [
        'title' => esc_html__( 'My Category', 'textdomain' ),
        'icon'  => 'fa fa-plug',
    ] );
}
add_action( 'elementor/elements/categories_registered', 'add_elementor_widget_categories' );
php
function add_elementor_widget_categories( $elements_manager ) {
    $elements_manager->add_category( 'my-category', [
        'title' => esc_html__( 'My Category', 'textdomain' ),
        'icon'  => 'fa fa-plug',
    ] );
}
add_action( 'elementor/elements/categories_registered', 'add_elementor_widget_categories' );

Selector Tokens

选择器令牌

TokenDescription
{{WRAPPER}}
Widget wrapper element
{{VALUE}}
Control value
{{UNIT}}
Unit control value
{{URL}}
URL from media control
{{SELECTOR}}
Group control CSS selector
令牌描述
{{WRAPPER}}
小部件包裹元素
{{VALUE}}
控件值
{{UNIT}}
单位控件值
{{URL}}
媒体控件中的URL
{{SELECTOR}}
组控件CSS选择器

Inline Editing Toolbars

内联编辑工具栏

ModeToolbarUse Case
'none'
No toolbarPlain text headings
'basic'
Bold, italic, underlineShort descriptions
'advanced'
Full (links, headings, lists)Rich text content

模式工具栏使用场景
'none'
无工具栏纯文本标题
'basic'
粗体、斜体、下划线简短描述
'advanced'
完整功能(链接、标题、列表)富文本内容

3. Manager Registration

3. 管理器注册

Registration Hooks Reference

注册钩子参考

ComponentHookManager TypeMethod
Widgets
elementor/widgets/register
\Elementor\Widgets_Manager
register()
/
unregister()
Controls
elementor/controls/register
\Elementor\Controls_Manager
register()
/
unregister()
Dynamic Tags
elementor/dynamic_tags/register
\Elementor\Core\DynamicTags\Manager
register()
/
unregister()
Finder
elementor/finder/register
Categories_Manager
register()
/
unregister()
Categories
elementor/elements/categories_registered
Elements_Manager
add_category()
组件钩子管理器类型方法
小部件
elementor/widgets/register
\Elementor\Widgets_Manager
register()
/
unregister()
控件
elementor/controls/register
\Elementor\Controls_Manager
register()
/
unregister()
动态标签
elementor/dynamic_tags/register
\Elementor\Core\DynamicTags\Manager
register()
/
unregister()
查找器
elementor/finder/register
Categories_Manager
register()
/
unregister()
分类
elementor/elements/categories_registered
Elements_Manager
add_category()

Register Widgets

注册小部件

php
function register_new_widgets( $widgets_manager ) {
    require_once __DIR__ . '/widgets/widget-1.php';
    $widgets_manager->register( new \Elementor_Widget_1() );
}
add_action( 'elementor/widgets/register', 'register_new_widgets' );
php
function register_new_widgets( $widgets_manager ) {
    require_once __DIR__ . '/widgets/widget-1.php';
    $widgets_manager->register( new \Elementor_Widget_1() );
}
add_action( 'elementor/widgets/register', 'register_new_widgets' );

Unregister Widgets

注销小部件

php
function unregister_widgets( $widgets_manager ) {
    $widgets_manager->unregister( 'heading' );
    $widgets_manager->unregister( 'image' );
}
add_action( 'elementor/widgets/register', 'unregister_widgets' );
php
function unregister_widgets( $widgets_manager ) {
    $widgets_manager->unregister( 'heading' );
    $widgets_manager->unregister( 'image' );
}
add_action( 'elementor/widgets/register', 'unregister_widgets' );

Register/Unregister Controls

注册/注销控件

php
function register_new_controls( $controls_manager ) {
    require_once __DIR__ . '/controls/control-1.php';
    $controls_manager->register( new \Elementor_Control_1() );
}
add_action( 'elementor/controls/register', 'register_new_controls' );

function unregister_controls( $controls_manager ) {
    $controls_manager->unregister( 'control-1' );
}
add_action( 'elementor/controls/register', 'unregister_controls' );
php
function register_new_controls( $controls_manager ) {
    require_once __DIR__ . '/controls/control-1.php';
    $controls_manager->register( new \Elementor_Control_1() );
}
add_action( 'elementor/controls/register', 'register_new_controls' );

function unregister_controls( $controls_manager ) {
    $controls_manager->unregister( 'control-1' );
}
add_action( 'elementor/controls/register', 'unregister_controls' );

Register/Unregister Dynamic Tags

注册/注销动态标签

php
function register_dynamic_tags( $dynamic_tags_manager ) {
    require_once __DIR__ . '/dynamic-tags/tag-1.php';
    $dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_1() );
}
add_action( 'elementor/dynamic_tags/register', 'register_dynamic_tags' );

function unregister_dynamic_tags( $dynamic_tags_manager ) {
    $dynamic_tags_manager->unregister( 'dynamic-tag-1' );
}
add_action( 'elementor/dynamic_tags/register', 'unregister_dynamic_tags' );
php
function register_dynamic_tags( $dynamic_tags_manager ) {
    require_once __DIR__ . '/dynamic-tags/tag-1.php';
    $dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_1() );
}
add_action( 'elementor/dynamic_tags/register', 'register_dynamic_tags' );

function unregister_dynamic_tags( $dynamic_tags_manager ) {
    $dynamic_tags_manager->unregister( 'dynamic-tag-1' );
}
add_action( 'elementor/dynamic_tags/register', 'unregister_dynamic_tags' );

Register/Unregister Finder Categories

注册/注销查找器分类

php
function register_finder_categories( $finder_manager ) {
    require_once __DIR__ . '/finder/finder-1.php';
    $finder_manager->register( new \Elementor_Finder_Category_1() );
}
add_action( 'elementor/finder/register', 'register_finder_categories' );

function unregister_finder_categories( $finder_manager ) {
    $finder_manager->unregister( 'finder-category-1' );
}
add_action( 'elementor/finder/register', 'unregister_finder_categories' );

php
function register_finder_categories( $finder_manager ) {
    require_once __DIR__ . '/finder/finder-1.php';
    $finder_manager->register( new \Elementor_Finder_Category_1() );
}
add_action( 'elementor/finder/register', 'register_finder_categories' );

function unregister_finder_categories( $finder_manager ) {
    $finder_manager->unregister( 'finder-category-1' );
}
add_action( 'elementor/finder/register', 'unregister_finder_categories' );

4. Scripts & Styles

4. 脚本与样式

Frontend Hooks

前端钩子

HookPurpose
elementor/frontend/before_register_scripts
Register scripts before Elementor
elementor/frontend/after_register_scripts
Register scripts after Elementor
elementor/frontend/before_enqueue_scripts
Enqueue scripts before Elementor
elementor/frontend/after_enqueue_scripts
Enqueue scripts after Elementor
elementor/frontend/before_register_styles
Register styles before Elementor
elementor/frontend/after_register_styles
Register styles after Elementor
elementor/frontend/before_enqueue_styles
Enqueue styles before Elementor
elementor/frontend/after_enqueue_styles
Enqueue styles after Elementor
钩子用途
elementor/frontend/before_register_scripts
在Elementor之前注册脚本
elementor/frontend/after_register_scripts
在Elementor之后注册脚本
elementor/frontend/before_enqueue_scripts
在Elementor之前加载脚本
elementor/frontend/after_enqueue_scripts
在Elementor之后加载脚本
elementor/frontend/before_register_styles
在Elementor之前注册样式
elementor/frontend/after_register_styles
在Elementor之后注册样式
elementor/frontend/before_enqueue_styles
在Elementor之前加载样式
elementor/frontend/after_enqueue_styles
在Elementor之后加载样式

Editor Hooks

编辑器钩子

HookPurpose
elementor/editor/before_enqueue_scripts
Enqueue editor scripts (before)
elementor/editor/after_enqueue_scripts
Enqueue editor scripts (after)
elementor/editor/before_enqueue_styles
Enqueue editor styles (before)
elementor/editor/after_enqueue_styles
Enqueue editor styles (after)
钩子用途
elementor/editor/before_enqueue_scripts
加载编辑器脚本(之前)
elementor/editor/after_enqueue_scripts
加载编辑器脚本(之后)
elementor/editor/before_enqueue_styles
加载编辑器样式(之前)
elementor/editor/after_enqueue_styles
加载编辑器样式(之后)

Preview Hooks

预览钩子

HookPurpose
elementor/preview/enqueue_scripts
Enqueue preview scripts
elementor/preview/enqueue_styles
Enqueue preview styles
钩子用途
elementor/preview/enqueue_scripts
加载预览脚本
elementor/preview/enqueue_styles
加载预览样式

Frontend Registration Pattern

前端注册模式

php
function my_plugin_frontend_scripts() {
    wp_register_script( 'my-widget-script', plugins_url( 'assets/js/widget.js', __FILE__ ) );
    wp_register_style( 'my-widget-style', plugins_url( 'assets/css/widget.css', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_frontend_scripts' );
php
function my_plugin_frontend_scripts() {
    wp_register_script( 'my-widget-script', plugins_url( 'assets/js/widget.js', __FILE__ ) );
    wp_register_style( 'my-widget-style', plugins_url( 'assets/css/widget.css', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_frontend_scripts' );

Widget-Level Dependencies

小部件级依赖

Declare in the widget class; Elementor loads them only when the widget is used.
php
public function get_script_depends(): array {
    return [ 'my-widget-script', 'external-library' ];
}

public function get_style_depends(): array {
    return [ 'my-widget-style', 'external-framework' ];
}
在小部件类中声明;Elementor仅在使用该小部件时才加载这些依赖。
php
public function get_script_depends(): array {
    return [ 'my-widget-script', 'external-library' ];
}

public function get_style_depends(): array {
    return [ 'my-widget-style', 'external-framework' ];
}

Control-Level Enqueue

控件级加载

php
class My_Control extends \Elementor\Base_Control {

    protected function enqueue(): void {
        wp_enqueue_script( 'control-script' );
        wp_enqueue_style( 'control-style' );
    }
}

php
class My_Control extends \Elementor\Base_Control {

    protected function enqueue(): void {
        wp_enqueue_script( 'control-script' );
        wp_enqueue_style( 'control-style' );
    }
}

8. Common Mistakes

8. 常见错误

MistakeFix
Using
elementor/widgets/widgets_registered
hook
Use
elementor/widgets/register
(old hook deprecated)
Calling
register_widget_type()
Use
register()
on the widgets manager
Using
scheme
for colors/typography
Use
global
with
Global_Colors
/
Global_Typography
constants
Using
_register_controls()
with underscore prefix
Use
register_controls()
(no underscore)
Skipping
did_action('elementor/loaded')
check
Always verify Elementor is loaded before using its classes
Missing
Requires Plugins: elementor
header
Add it so WordPress enforces Elementor dependency
Using
{{ }}
for HTML output in JS templates
Use
{{{ }}}
(triple) for unescaped HTML;
{{ }}
escapes output
Not declaring widget script/style dependenciesImplement
get_script_depends()
/
get_style_depends()
Enqueueing scripts globally instead of per-widgetRegister with
wp_register_script
, declare via
get_script_depends()
Using
innerHTML =
in editor JS
Use Elementor template syntax or DOM methods
Not using
esc_html__()
for translatable strings
Always wrap user-visible strings in localization functions
Missing
defined('ABSPATH') || exit;
guard
Add to every PHP file to prevent direct access
Using
has_widget_inner_wrapper
returning
true
without need
Return
false
to reduce DOM nodes (optimization)
Not implementing
content_template()
Without it, editor preview requires server round-trip on every change
Using
add_render_attribute
inside
content_template()
Use
view.addRenderAttribute()
in JS templates
错误修复方案
使用
elementor/widgets/widgets_registered
钩子
使用
elementor/widgets/register
(旧钩子已弃用)
调用
register_widget_type()
使用小部件管理器的
register()
方法
为颜色/排版使用
scheme
使用
global
搭配
Global_Colors
/
Global_Typography
常量
使用带下划线前缀的
_register_controls()
使用
register_controls()
(无下划线)
跳过
did_action('elementor/loaded')
检查
在使用Elementor类之前,始终验证Elementor已加载
缺少
Requires Plugins: elementor
插件头
添加该字段,让WordPress强制依赖Elementor
在JS模板中使用
{{ }}
输出HTML
使用
{{{ }}}
(三重括号)输出未转义的HTML;
{{ }}
会转义输出
未声明小部件的脚本/样式依赖实现
get_script_depends()
/
get_style_depends()
方法
全局加载脚本而非按小部件加载使用
wp_register_script
注册,通过
get_script_depends()
声明
在编辑器JS中使用
innerHTML =
使用Elementor模板语法或DOM方法
不为可翻译字符串使用
esc_html__()
始终将用户可见的字符串包裹在本地化函数中
缺少`defined('ABSPATH')
无必要地将
has_widget_inner_wrapper
设为
true
返回
false
以减少DOM节点(优化)
未实现
content_template()
缺少该方法时,编辑器预览每次变更都需要服务器往返请求
content_template()
中使用
add_render_attribute
在JS模板中使用
view.addRenderAttribute()