elementor-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseElementor 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
选择器令牌
| Token | Description |
|---|---|
| Widget wrapper element |
| Control value |
| Unit control value |
| URL from media control |
| Group control CSS selector |
| 令牌 | 描述 |
|---|---|
| 小部件包裹元素 |
| 控件值 |
| 单位控件值 |
| 媒体控件中的URL |
| 组控件CSS选择器 |
Inline Editing Toolbars
内联编辑工具栏
| Mode | Toolbar | Use Case |
|---|---|---|
| No toolbar | Plain text headings |
| Bold, italic, underline | Short descriptions |
| Full (links, headings, lists) | Rich text content |
| 模式 | 工具栏 | 使用场景 |
|---|---|---|
| 无工具栏 | 纯文本标题 |
| 粗体、斜体、下划线 | 简短描述 |
| 完整功能(链接、标题、列表) | 富文本内容 |
3. Manager Registration
3. 管理器注册
Registration Hooks Reference
注册钩子参考
| Component | Hook | Manager Type | Method |
|---|---|---|---|
| Widgets | | | |
| Controls | | | |
| Dynamic Tags | | | |
| Finder | | | |
| Categories | | | |
| 组件 | 钩子 | 管理器类型 | 方法 |
|---|---|---|---|
| 小部件 | | | |
| 控件 | | | |
| 动态标签 | | | |
| 查找器 | | | |
| 分类 | | | |
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
前端钩子
| Hook | Purpose |
|---|---|
| Register scripts before Elementor |
| Register scripts after Elementor |
| Enqueue scripts before Elementor |
| Enqueue scripts after Elementor |
| Register styles before Elementor |
| Register styles after Elementor |
| Enqueue styles before Elementor |
| Enqueue styles after Elementor |
| 钩子 | 用途 |
|---|---|
| 在Elementor之前注册脚本 |
| 在Elementor之后注册脚本 |
| 在Elementor之前加载脚本 |
| 在Elementor之后加载脚本 |
| 在Elementor之前注册样式 |
| 在Elementor之后注册样式 |
| 在Elementor之前加载样式 |
| 在Elementor之后加载样式 |
Editor Hooks
编辑器钩子
| Hook | Purpose |
|---|---|
| Enqueue editor scripts (before) |
| Enqueue editor scripts (after) |
| Enqueue editor styles (before) |
| Enqueue editor styles (after) |
| 钩子 | 用途 |
|---|---|
| 加载编辑器脚本(之前) |
| 加载编辑器脚本(之后) |
| 加载编辑器样式(之前) |
| 加载编辑器样式(之后) |
Preview Hooks
预览钩子
| Hook | Purpose |
|---|---|
| Enqueue preview scripts |
| Enqueue preview 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. 常见错误
| Mistake | Fix |
|---|---|
Using | Use |
Calling | Use |
Using | Use |
Using | Use |
Skipping | Always verify Elementor is loaded before using its classes |
Missing | Add it so WordPress enforces Elementor dependency |
Using | Use |
| Not declaring widget script/style dependencies | Implement |
| Enqueueing scripts globally instead of per-widget | Register with |
Using | Use Elementor template syntax or DOM methods |
Not using | Always wrap user-visible strings in localization functions |
Missing | Add to every PHP file to prevent direct access |
Using | Return |
Not implementing | Without it, editor preview requires server round-trip on every change |
Using | Use |
| 错误 | 修复方案 |
|---|---|
使用 | 使用 |
调用 | 使用小部件管理器的 |
为颜色/排版使用 | 使用 |
使用带下划线前缀的 | 使用 |
跳过 | 在使用Elementor类之前,始终验证Elementor已加载 |
缺少 | 添加该字段,让WordPress强制依赖Elementor |
在JS模板中使用 | 使用 |
| 未声明小部件的脚本/样式依赖 | 实现 |
| 全局加载脚本而非按小部件加载 | 使用 |
在编辑器JS中使用 | 使用Elementor模板语法或DOM方法 |
不为可翻译字符串使用 | 始终将用户可见的字符串包裹在本地化函数中 |
| 缺少`defined('ABSPATH') | |
无必要地将 | 返回 |
未实现 | 缺少该方法时,编辑器预览每次变更都需要服务器往返请求 |
在 | 在JS模板中使用 |