关于 elementor-development
为 Elementor 插件开发者整理的参考技能,涵盖插件架构、自定义控件及注册流程。也说明脚本与样式管理、渲染方式和常见兼容性问题。
主要功能
- 01Elementor 插件目录与主类结构
- 02自定义 Widget 与控件开发
- 03注册和移除组件的钩子
- 04前端、编辑器与预览资源管理
- 05渲染与常见问题参考
适用场景
- 01搭建新的 Elementor 插件
- 02为插件添加 Widget、控件或动态标签
- 03按需加载 Widget 脚本与样式
- 04排查旧钩子和渲染实现问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ peixotorms/ odinlayer-skills --skill elementor-development安装后在 Claude Code 中输入/elementor-development确认已加载。
附带文件resources/data-deprecations-cli.mdresources/widget-rendering.md
详细介绍
Elementor 附加组件与工具开发
有关附加组件架构、工具创建、管理器注册、脚本/样式、数据结构、弃用项和 CLI 命令的综合参考。
另请参阅:
- 工具渲染详情 —— 完整的控件注册、render()、content_template()、渲染属性
- 数据结构、弃用项与 CLI —— JSON 格式、元素结构、弃用时间线、CLI 命令
1. 附加组件结构
插件头信息
每个 Elementor 附加组件都需要标准的 WordPress 头信息,也可以包含 Elementor 专用头信息。
<?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' );
主类(单例 + 兼容性检查)
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() );
}
}
文件夹结构
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/
2. 工具开发
工具类骨架
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 */ }
}
注册自定义工具分类
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' );
选择器标记
| 标记 | 描述 |
|---|---|
{{WRAPPER}} | 工具包装元素 |
{{VALUE}} | 控件值 |
{{UNIT}} | 单位控件值 |
{{URL}} | 媒体控件中的 URL |
{{SELECTOR}} | 分组控件的 CSS 选择器 |
内联编辑工具栏
| 模式 | 工具栏 | 使用场景 |
|---|---|---|
'none' | 无工具栏 | 纯文本标题 |
'basic' | 粗体、斜体、下划线 | 简短描述 |
'advanced' | 完整工具栏(链接、标题、列表) | 富文本内容 |
3. 管理器注册
注册钩子参考
| 组件 | 钩子 | 管理器类型 | 方法 |
|---|---|---|---|
| 工具 | 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() |
注册工具
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' );
取消注册工具
function unregister_widgets( $widgets_manager ) {
$widgets_manager->unregister( 'heading' );
$widgets_manager->unregister( 'image' );
}
add_action( 'elementor/widgets/register', 'unregister_widgets' );
注册/取消注册控件
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' );
注册/取消注册动态标签
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' );
注册/取消注册查找器分类
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. 脚本与样式
前端钩子
| 钩子 | 用途 |
|---|---|
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 之后加载样式 |
编辑器钩子
| 钩子 | 用途 |
|---|---|
elementor/editor/before_enqueue_scripts | 加载编辑器脚本(之前) |
elementor/editor/after_enqueue_scripts | 加载编辑器脚本(之后) |
elementor/editor/before_enqueue_styles | 加载编辑器样式(之前) |
elementor/editor/after_enqueue_styles | 加载编辑器样式(之后) |
预览钩子
| 钩子 | 用途 |
|---|---|
elementor/preview/enqueue_scripts | 加载预览脚本 |
elementor/preview/enqueue_styles | 加载预览样式 |
前端注册模式
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' );
工具级依赖项
在工具类中声明;Elementor 仅在使用该工具时加载这些依赖项。
public function get_script_depends(): array {
return [ 'my-widget-script', 'external-library' ];
}
public function get_style_depends(): array {
return [ 'my-widget-style', 'external-framework' ];
}
控件级加载
class My_Control extends \Elementor\Base_Control {
protected function enqueue(): void {
wp_enqueue_script( 'control-script' );
wp_enqueue_style( 'control-style' );
}
}
8. 常见错误
| 错误 | 修正方法 |
|---|---|
使用 elementor/widgets/widgets_registered 钩子 | 使用 elementor/widgets/register(旧钩子已弃用) |
调用 register_widget_type() | 在 widgets 管理器上使用 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;{{ }} 会转义输出 |
| 未声明 widget 脚本/样式依赖项 | 实现 get_script_depends() / get_style_depends() |
| 全局加载脚本,而非按 widget 加载 | 使用 wp_register_script 注册,并通过 get_script_depends() 声明 |
在编辑器 JS 中使用 innerHTML = | 使用 Elementor 模板语法或 DOM 方法 |
未对可翻译字符串使用 esc_html__() | 始终使用本地化函数包装面向用户的字符串 |
缺少 defined('ABSPATH') || exit; 防护 | 在每个 PHP 文件中添加,以防止直接访问 |
无必要地让 has_widget_inner_wrapper 返回 true | 返回 false,以减少 DOM 节点(优化) |
未实现 content_template() | 若不实现,编辑器预览每次更改都需要与服务器往返通信 |
在 content_template() 中使用 add_render_attribute | 在 JS 模板中使用 view.addRenderAttribute() |
评论
支持 Markdown