Elementor 开发者文档
Elementor 开发者文档中文翻译,介绍小工具、控件与扩展接口。
- Index
- 插件包装器示例
- 兼容性检查
- 文件与文件夹结构
- 构建扩展插件
- 初始化流程
- Loading Process
- Main Class
- Using Namespaces
- Header Comments
- Composer
- 实验功能激活
- 实验功能停用
- 实验功能状态
- 刷新 CSS
- Elementor CLI
- 套件导出
- 套件导入
- Library Connect
- 库断开连接
- 库导入目录
- 库导入
- 库同步
- License Activation
- License Deactivation
- 替换 URL
- 系统信息
- 清除主题构建器条件
- 更新数据库
- 添加新操作
- Add New Group
- Advanced Example
- 右键菜单操作
- Context Menu Groups
- Context Menu Types
- Elementor 上下文菜单
- 移除操作
- 移除群组
- Simple Example
- 更新操作
- 更新群组
- Add New Control
- 复杂示例
- Control Enqueue
- 控件设置
- 控制结构
- 控制模板
- Control Values
- Elementor 控件
- Remove Controls
- 简单示例
- Container Element
- 通用元素
- 通用结构
- 全局样式
- 数据结构
- 页面内容
- Page Settings
- 中继器
- 响应式数据
- 小部件元素
- Advanced Example
- Complex Example
- Deprecated Action Hooks
- Deprecated Arguments
- Deprecated Filter Hooks
- Deprecated Function
- Elementor 弃用功能
- Simple Example
- 添加新的动态标签
- 高级示例
- 复杂示例
- 动态标签分类
- 动态标签控件
- 动态标签数据
- Dynamic Tags Groups
- 动态标签渲染
- 动态标签结构
- Dynamic Tags
- 移除动态标签
- 简单示例
- 默认面板
- Elementor 面板
- Elementor 预览
- Elementor 选项卡
- 历史面板
- Elementor 编辑器
- 菜单面板
- 页面设置面板
- 站点设置面板
- User Preferences Panel
- 小部件面板
- AI
- 条件显示
- 警告控制
- 入场动画控制
- 盒阴影控制
- 按钮控件
- 选择控件
- 代码控制
- 颜色控制
- 日期时间控件
- 弃用通知控件
- 尺寸控制
- 分隔线控件
- 退出动画控制
- 字体控制
- 画廊控件
- 标题控件
- 隐藏控件
- Hover Animation Control
- 图标控件
- 图标控件
- Image Dimensions Control
- 媒体控件
- 通知控件
- 数值控制
- Popover Toggle Control
- 控制项弹出框
- 原始 HTML 控件
- 重复器控件
- 控制项分组
- 选择控件
- Select2 控件
- 滑块控件
- 开关控件
- 控制选项卡
- 文本阴影控制
- 文本控件
- 文本域控件
- 控件类型
- URL 控件
- 视觉选择控件
- WYSIWYG 控件
- 动态内容
- 前端可用
- 全局样式
- 背景组控件
- 边框组控件
- 盒阴影分组控件
- CSS 滤镜组控件
- 图像尺寸组控件
- 文本阴影组控件
- 文本描边组控件
- 排版组控件
- 组合控制
- Elementor 编辑器控件
- 标签与描述
- 常规控件
- 响应式控件
- 选择器字典
- CSS 选择器
- 使用控件
- Add Items to an Existing Category
- 添加新的查找器项目
- 高级示例
- Finder 分类
- Finder 结构
- Elementor Finder
- 移除查找器分类
- 移除查找器项目
- 简单示例
- Action Controls
- Action Data
- 导出时的处理
- Action Run
- Action Structure
- Add New Action
- 高级示例
- Elementor 表单操作
- 简单示例
- Add New Field
- 高级示例
- 字段内容模板
- 字段控件
- Field Data
- 字段依赖关系
- 字段渲染
- Field Structure
- Field Validation
- Elementor 表单字段
- Remove Fields
- 简单示例
- What is an Elementor addon?
- 最佳实践
- Elementor 组件
- 创建您的首个扩展插件
- 什么是 Elementor?
- Elementor 内部机制
- 要求
- 文档网站
- Description Meta Tag
- Register Theme Features
- Register WooCommerce Features
- Content Width
- Enable Skip Link
- Enqueue Styles
- Enqueue Theme Styles
- Page Title
- Register Post Type Features
- Register Elementor Theme Locations
- Register Navigation Menus
- Skip Link URL
- Viewport Content
- Hello Elementor 主题
- 自定义查询过滤器
- Elementor 初始化
- Elementor 已加载
- Font Display
- 表单验证
- Elementor Forms
- Frontend Content
- Elementor Hooks
- 注入控件
- JS Hooks
- Mask Shapes
- 解析元素 CSS
- PHP Hooks
- 占位图
- 禁用 Google 字体加载
- Print Widget Template
- Render Frontend Elements
- Render Widget Content
- Save Editor Data
- Shape Dividers
- 小部件分类
- 小部件皮肤
- Elementor Hosting
- Dynamic Page Cache
- Cache Changed URLs
- Purge Everything
- API -- `$e.commands`
- API - `$e.components`
- API - `$e.hooks`
- Elementor Managers
- Registering Controls
- Registering Dynamic Tags
- 注册查找器类别
- Registering Widgets
- Unregistering Controls
- Unregistering Dynamic Tags
- Unregistering Finder Categories
- Unregistering Widgets
- Control Scripts
- Control Styles
- Editor Scripts
- 编辑器样式
- Frontend Scripts
- Frontend Styles
- Scripts & Styles
- 预览脚本
- 预览样式
- Widget Scripts
- Widget Styles
- Add New Condition
- 进阶示例
- Condition Check
- 条件数据
- Condition Group Type
- Condition Structure
- Theme Conditions
- 简单示例
- Sub-Conditions
- Displaying Locations
- Theme Locations
- Migrating Themes with Functions
- Migrating Themes with Hooks
- Migrating Themes
- Original Theme
- Registering Locations
- Add New Widget
- Advanced Example
- Elementor 小工具
- Remove Widgets
- Rendering HTML Attributes
- Rendering Inline Editing
- Rendering Media
- Rendering Repeaters
- Rendering Style
- Rendering Text
- Simple Example
- 小部件分类
- Widget Controls
- Widget Data
- Widget Dependencies
- Widget Information
- Widget DOM Optimization
- Widget Optimization
- Widget Output Caching
- 小部件推广
- Widget Rendering
- Widget Settings
- Widget Structure
Index
Elementor 开发者文档
学习如何扩展 Elementor 核心以创建您自己的插件。在这里,您将找到详细的文档、便捷的代码片段和完整的代码示例。
入门指南
学习如何扩展 Elementor 核心以创建您自己的插件。在这里,您将找到详细的文档、便捷的代码片段和完整的代码示例。
Elementor 内部机制
Elementor 拥有底层技术,我们称之为内部机制。了解在开发 Elementor 插件时应掌握的概念。
Elementor 组件
Elementor 包含众多开发者可以修改以扩展其功能的组件。本节列出了当前文档涵盖的组件。
插件包装器示例
让我们为 Elementor 插件创建一个包装器,它整合了目前所学的所有内容——文件/文件夹结构、每个 WordPress 插件所需的基本头部注释、命名空间以及兼容性检查。
文件夹结构
该插件将采用以下文件夹结构:
elementor-test-addon/
|
├─ includes/
| |
| ├─ controls/
| | ├─ control-1.php
| | └─ control-2.php
| |
| ├─ widgets/
| | ├─ widget-1.php
| | └─ widget-2.php
| |
| └─ plugin.php
|
└─ elementor-test-addon.php
The Entire Code
The addon code should look as follows:
elementor-test-addon.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
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
function elementor_test_addon() {
// Load plugin file
require_once( __DIR__ . '/includes/plugin.php' );
// Run the plugin
\Elementor_Test_Addon\Plugin::instance();
}
add_action( 'plugins_loaded', 'elementor_test_addon' );
includes/plugin.php
namespace Elementor_Test_Addon;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Plugin class.
*
* The main class that initiates and runs the addon.
*
* @since 1.0.0
*/
final class Plugin {
/**
* Addon Version
*
* @since 1.0.0
* @var string The addon version.
*/
const VERSION = '1.0.0';
/**
* Minimum Elementor Version
*
* @since 1.0.0
* @var string Minimum Elementor version required to run the addon.
*/
const MINIMUM_ELEMENTOR_VERSION = '3.20.0';
/**
* Minimum PHP Version
*
* @since 1.0.0
* @var string Minimum PHP version required to run the addon.
*/
const MINIMUM_PHP_VERSION = '7.4';
/**
* Instance
*
* @since 1.0.0
* @access private
* @static
* @var \Elementor_Test_Addon\Plugin The single instance of the class.
*/
private static $_instance = null;
/**
* Instance
*
* Ensures only one instance of the class is loaded or can be loaded.
*
* @since 1.0.0
* @access public
* @static
* @return \Elementor_Test_Addon\Plugin An instance of the class.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Constructor
*
* Perform some compatibility checks to make sure basic requirements are meet.
* If all compatibility checks pass, initialize the functionality.
*
* @since 1.0.0
* @access public
*/
public function __construct() {
if ( $this->is_compatible() ) {
add_action( 'elementor/init', [ $this, 'init' ] );
}
}
/**
* Compatibility Checks
*
* Checks whether the site meets the addon requirement.
*
* @since 1.0.0
* @access public
*/
public function is_compatible(): void {
// Check if Elementor installed and activated
if ( ! did_action( 'elementor/loaded' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_missing_main_plugin' ] );
return false;
}
// Check for required Elementor version
if ( ! version_compare( ELEMENTOR_VERSION, self::MINIMUM_ELEMENTOR_VERSION, '>=' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_minimum_elementor_version' ] );
return false;
}
// Check for required PHP version
if ( version_compare( PHP_VERSION, self::MINIMUM_PHP_VERSION, '<' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_minimum_php_version' ] );
return false;
}
return true;
}
/**
* Admin notice
*
* Warning when the site doesn't have Elementor installed or activated.
*
* @since 1.0.0
* @access public
*/
public function admin_notice_missing_main_plugin(): void {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Plugin name 2: Elementor */
esc_html__( '"%1$s" requires "%2$s" to be installed and activated.', 'elementor-test-addon' ),
'<strong>' . esc_html__( 'Elementor Test Addon', 'elementor-test-addon' ) . '</strong>',
'<strong>' . esc_html__( 'Elementor', 'elementor-test-addon' ) . '</strong>'
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
/**
* Admin notice
*
* Warning when the site doesn't have a minimum required Elementor version.
*
* @since 1.0.0
* @access public
*/
public function admin_notice_minimum_elementor_version(): void {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Plugin name 2: Elementor 3: Required Elementor version */
esc_html__( '"%1$s" requires "%2$s" version %3$s or greater.', 'elementor-test-addon' ),
'<strong>' . esc_html__( 'Elementor Test Addon', 'elementor-test-addon' ) . '</strong>',
'<strong>' . esc_html__( 'Elementor', 'elementor-test-addon' ) . '</strong>',
self::MINIMUM_ELEMENTOR_VERSION
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
/**
* Admin notice
*
* Warning when the site doesn't have a minimum required PHP version.
*
* @since 1.0.0
* @access public
*/
public function admin_notice_minimum_php_version(): void {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Plugin name 2: PHP 3: Required PHP version */
esc_html__( '"%1$s" requires "%2$s" version %3$s or greater.', 'elementor-test-addon' ),
'<strong>' . esc_html__( 'Elementor Test Addon', 'elementor-test-addon' ) . '</strong>',
'<strong>' . esc_html__( 'PHP', 'elementor-test-addon' ) . '</strong>',
self::MINIMUM_PHP_VERSION
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
/**
* Initialize
*
* Load the addons functionality only after Elementor is initialized.
*
* Fired by `elementor/init` action hook.
*
* @since 1.0.0
* @access public
*/
public function init(): void {
add_action( 'elementor/widgets/register', [ $this, 'register_widgets' ] );
add_action( 'elementor/controls/register', [ $this, 'register_controls' ] );
}
/**
* 注册小工具
*
* 加载小工具文件并注册新的 Elementor 小工具。
*
* 由 `elementor/widgets/register` 动作钩子触发。
*
* @param \Elementor\Widgets_Manager $widgets_manager Elementor 小工具管理器。
*/
public function register_widgets( $widgets_manager ): void {
require_once( __DIR__ . '/includes/widgets/widget-1.php' );
require_once( __DIR__ . '/includes/widgets/widget-2.php' );
$widgets_manager->register( new Widget_1() );
$widgets_manager->register( new Widget_2() );
}
/**
* 注册控件
*
* 加载控件文件并注册新的 Elementor 控件。
*
* 由 `elementor/controls/register` 动作钩子触发。
*
* @param \Elementor\Controls_Manager $controls_manager Elementor 控件管理器。
*/
public function register_controls( $controls_manager ): void {
require_once( __DIR__ . '/includes/controls/control-1.php' );
require_once( __DIR__ . '/includes/controls/control-2.php' );
$controls_manager->register( new Control_1() );
$controls_manager->register( new Control_2() );
}
}
兼容性检查
在初始化之前,插件应检查其基本要求是否满足。如果这些要求未满足,插件不应运行。
Basic Checks
Since the addon extends Elementor’s core functionality, it should check to make sure that both the Elementor and PHP versions are compatible.
final class Plugin {
/**
* Minimum Elementor Version
*
* @since 1.0.0
* @var string Minimum Elementor version required to run the addon.
*/
const MINIMUM_ELEMENTOR_VERSION = '3.20.0';
/**
* Minimum PHP Version
*
* @since 1.0.0
* @var string Minimum PHP version required to run the addon.
*/
const MINIMUM_PHP_VERSION = '7.4';
/**
* Constructor
*
* Perform some compatibility checks to make sure basic requirements are meet.
* If all compatibility checks pass, initialize the functionality.
*
* @since 1.0.0
* @access public
*/
public function __construct() {
if ( $this->is_compatible() ) {
// Run init process here...
}
}
/**
* Compatibility Checks
*
* Checks whether the site meets the addon requirement.
*
* @since 1.0.0
* @access public
* @return bool
*/
public function is_compatible(): bool {
// Check if Elementor is installed and activated
if ( ! did_action( 'elementor/loaded' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_missing_main_plugin' ] );
return false;
}
// Check for required Elementor version
if ( ! version_compare( ELEMENTOR_VERSION, self::MINIMUM_ELEMENTOR_VERSION, '>=' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_minimum_elementor_version' ] );
return false;
}
// Check for required PHP version
if ( version_compare( PHP_VERSION, self::MINIMUM_PHP_VERSION, '<' ) ) {
add_action( 'admin_notices', [ $this, 'admin_notice_minimum_php_version' ] );
return false;
}
return true;
}
/**
* Admin notice
*
* Warning when the site doesn't have Elementor installed or activated.
*
* @since 1.0.0
* @access public
*/
public function admin_notice_missing_main_plugin(): void {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Plugin name 2: Elementor */
esc_html__( '"%1$s" requires "%2$s" to be installed and activated.', 'elementor-test-addon' ),
'<strong>' . esc_html__( 'Elementor Test Addon', 'elementor-test-addon' ) . '</strong>',
'<strong>' . esc_html__( 'Elementor', 'elementor-test-addon' ) . '</strong>'
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
/**
* Admin notice
*
* Warning when the site doesn't have a minimum required Elementor version.
*
* @since 1.0.0
* @access public
*/
public function admin_notice_minimum_elementor_version(): void {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Plugin name 2: Elementor 3: Required Elementor version */
esc_html__( '"%1$s" requires "%2$s" version %3$s or greater.', 'elementor-test-addon' ),
'<strong>' . esc_html__( 'Elementor Test Addon', 'elementor-test-addon' ) . '</strong>',
'<strong>' . esc_html__( 'Elementor', 'elementor-test-addon' ) . '</strong>',
self::MINIMUM_ELEMENTOR_VERSION
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
/**
* Admin notice
*
* Warning when the site doesn't have a minimum required PHP version.
*
* @since 1.0.0
* @access public
*/
public function admin_notice_minimum_php_version(): void {
if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );
$message = sprintf(
/* translators: 1: Plugin name 2: PHP 3: Required PHP version */
esc_html__( '"%1$s" requires "%2$s" version %3$s or greater.', 'elementor-test-addon' ),
'<strong>' . esc_html__( 'Elementor Test Addon', 'elementor-test-addon' ) . '</strong>',
'<strong>' . esc_html__( 'PHP', 'elementor-test-addon' ) . '</strong>',
self::MINIMUM_PHP_VERSION
);
printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
}
}
You can add as many compatibility checks as needed, the best example is Elementor Pro, but it can be anything. If one of the basic requirements fails, the addon shouldn't run.
文件与文件夹结构
所有 WordPress 插件指南 都应适用于 Elementor 插件。您应保持文件夹结构简单,并将相似的文件放在一起。
文件
您的插件根目录 /elementor-test-addon/ 应包含一个 elementor-test-addon.php 文件。最佳实践是使文件夹和主文件同名。
elementor-test-addon/
|
└─ elementor-test-addon.php
其他文件是可选的。如果插件有其他文件,应尽可能将它们组织到子文件夹中。
文件夹
最佳实践是将相似的文件放在一起。例如,您应将 CSS 文件分组在一起,JS 文件分组在一起。此规则也适用于文件类型和功能——例如,“小部件”应分组在一起,控件应分组在一起等。
单一组件插件
创建单一组件插件时,可以使用更简单的文件夹结构:
elementor-test-addon/
|
├─ assets/
|
├─ widgets/
|
└─ elementor-test-addon.php
多组件插件
随着插件变得更大、更复杂,您应将文件组织到文件夹中。我们推荐以下文件夹结构:
elementor-test-addon/
|
├─ assets/
| ├─ images/
| ├─ css/
| └─ js/
|
├─ includes/
| ├─ controls/
| ├─ dynamic-tags/
| ├─ finder/
| └─ widgets/
|
└─ elementor-test-addon.php
构建扩展插件
Elementor 扩展插件本质上是为 Elementor 增加功能的 WordPress 插件。在开始创建 Elementor 扩展插件之前,你需要具备创建 WordPress 插件的背景知识。之后,你需要学习 Elementor 扩展插件构建的基础知识。
WordPress 插件
WordPress 拥有一个高度可扩展的代码库。它允许任何人通过使用插件来扩展核心功能。如需深入了解,请查阅 WordPress 开发者资源 中的 插件手册。
Elementor 扩展插件
在创建 Elementor 扩展插件时,你应该遵循所有 WordPress 编码标准和最佳实践。此外,你还应遵循本网站概述的 Elementor 标准和最佳实践。
要开始创建 Elementor 扩展插件,你首先需要构建一个专注于 Elementor 的简单 WordPress 插件,请参考以下信息:
下一步是什么?
当你完成构建一个包装器后,就可以开始扩展 Elementor 组件了。请查看以下教程,了解如何扩展各个组件的详细信息和示例:
当然,这些只是扩展 Elementor 的一些方式。
初始化流程
通过所有兼容性检查后,我们可以安全地运行插件并开始扩展 Elementor 的功能。我们可以加载其他文件、挂载过滤器和动作钩子,并编写自定义代码。
Registering Custom Scripts & Styles
The addon can register and enqueue scripts and styles. Let's see an example of how this is done:
final class Plugin {
/**
* Initialize
*
* Load the addons functionality only after Elementor is initialized.
*
* Fired by `elementor/init` action hook.
*
* @since 1.0.0
* @access public
*/
public function init(): void {
add_action( 'elementor/frontend/after_register_styles', [ $this, 'register_frontend_styles' ] );
add_action( 'elementor/frontend/after_register_scripts', [ $this, 'register_frontend_scripts' ] );
add_action( 'elementor/frontend/after_enqueue_styles', [ $this, 'enqueue_frontend_styles' ] );
add_action( 'elementor/frontend/after_enqueue_scripts', [ $this, 'enqueue_frontend_scripts' ] );
}
public function register_frontend_styles(): void {
wp_register_style( 'frontend-style-1', plugins_url( 'assets/css/frontend-style-1.css', __FILE__ ) );
wp_register_style( 'frontend-style-2', plugins_url( 'assets/css/frontend-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
public function register_frontend_scripts(): void {
wp_register_script( 'frontend-script-1', plugins_url( 'assets/js/frontend-script-1.js', __FILE__ ) );
wp_register_script( 'frontend-script-2', plugins_url( 'assets/js/frontend-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
}
public function enqueue_frontend_styles(): void {
wp_enqueue_style( 'frontend-style-1' );
wp_enqueue_style( 'frontend-style-2' );
}
public function enqueue_frontend_scripts(): void {
wp_enqueue_script( 'frontend-script-1' );
wp_enqueue_script( 'frontend-script-2' );
}
}
Registering New Widgets
To add new widgets to Elementor, we need to register them using the widget manager mechanism. It’s a pretty simple process, we hook to the widget registration hook, include the widget's files and register the widget's classes.
final class Plugin {
/**
* Initialize
*
* Load the addons functionality only after Elementor is initialized.
*
* Fired by `elementor/init` action hook.
*
* @since 1.0.0
* @access public
*/
public function init(): void {
add_action( 'elementor/widgets/register', [ $this, 'register_widgets' ] );
}
/**
* Register Widgets
*
* Load widgets files and register new Elementor widgets.
*
* Fired by `elementor/widgets/register` action hook.
*
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
*/
public function register_widgets( $widgets_manager ): void {
require_once( __DIR__ . '/includes/widgets/widget-1.php' );
require_once( __DIR__ . '/includes/widgets/widget-2.php' );
$widgets_manager->register( new \Widget_1() );
$widgets_manager->register( new \Widget_2() );
}
}
Registering New Controls
Now let's see how to register new controls using the controls manager. Again, we are hooking to the control registration action to load the controls files and register the control classes.
final class Plugin {
/**
* Initialize
*
* Load the addons functionality only after Elementor is initialized.
*
* Fired by `elementor/init` action hook.
*
* @since 1.0.0
* @access public
*/
public function init(): void {
add_action( 'elementor/controls/register', [ $this, 'register_controls' ] );
}
/**
* Register Controls
*
* Load controls files and register new Elementor controls.
*
* Fired by `elementor/controls/register` action hook.
*
* @param \Elementor\Controls_Manager $controls_manager Elementor controls manager.
*/
public function register_controls( $controls_manager ): void {
require_once( __DIR__ . '/includes/controls/control-1.php' );
require_once( __DIR__ . '/includes/controls/control-2.php' );
$controls_manager->register( new \Control_1() );
$controls_manager->register( new \Control_2() );
}
}
Loading Process
Now that we have a WordPress plugin with all the header comments containing the basic information, we need to load the actual functionality. We should tell WordPress to load our functionality once activated plugins have been loaded. This is important as we need to make sure Elementor is loaded.
WordPress Lifecycle Hooks
To load our functionality we will wrap our code into a separate function. This code will be loaded when the WordPress plugins_loaded action hook is fired.
The following code can be used to run our functionality:
function elementor_test_addon() {
// your code here
}
add_action( 'plugins_loaded', 'elementor_test_addon' );
Please note that this hook fires before WordPress themes are setup, before the init and wp_loaded action hooks.
Example
Let's say our addon has the following folder structure:
elementor-test-addon/
|
├─ includes/
| |
| ├─ controls/
| ├─ widgets/
| |
| ├─ controls-manager.php
| └─ widgets-manager.php
|
└─ elementor-test-addon.php
Our /includes/ folder contains the different components, and each component has a manager that registers the different items.
The main elementor-test-addon.php file loads the functionality:
<?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
*/
function elementor_test_addon() {
// Load plugin file
require_once( __DIR__ . '/includes/widgets-manager.php' );
require_once( __DIR__ . '/includes/controls-manager.php' );
}
add_action( 'plugins_loaded', 'elementor_test_addon' );
Until now, we have yet to start on Elementor functionality, it was all WordPress related setup.
Main Class
We can move the different components into a single class - our main class. It should check basic requirements and load the files required to activate the addon's functionality, and then load the various components.
Class Structure
A good example of an addon class is one that hosts the following functionality:
final class Plugin {
private static $_instance = null;
public static function instance() {}
public function __construct() {}
public function is_compatible(): bool {}
public function init(): void {}
}
Single Instance
The main class should use a singleton design pattern to make sure it loads only once:
final class Plugin {
/**
* Instance
*
* @since 1.0.0
* @access private
* @static
* @var \Elementor_Test_Addon\Plugin The single instance of the class.
*/
private static $_instance = null;
/**
* Instance
*
* Ensures only one instance of the class is loaded or can be loaded.
*
* @since 1.0.0
* @access public
* @static
* @return \Elementor_Test_Addon\Plugin An instance of the class.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
}
\Plugin::instance();
Constructor
The constructor should perform compatibility checks to make sure the basic requirements are met. If all checks pass, the main functionality should be initialized.
final class Plugin {
/**
* Constructor
*
* Perform some compatibility checks to make sure basic requirements are meet.
* If all compatibility checks pass, initialize the functionality.
*
* @since 1.0.0
* @access public
*/
public function __construct() {
if ( $this->is_compatible() ) {
add_action( 'elementor/init', [ $this, 'init' ] );
}
}
/**
* Compatibility Checks
*
* Checks whether the site meets the addon requirement.
*
* @since 1.0.0
* @access public
*/
public function is_compatible(): bool {
// Compatibility checks here...
}
/**
* Initialize
*
* Load the addons functionality only after Elementor is initialized.
*
* Fired by `elementor/init` action hook.
*
* @since 1.0.0
* @access public
*/
public function init(): void {
// Addon functionality here...
}
}
Now let's examine a few examples of addon compatibility checks:
Using Namespaces
PHP namespaces are a way of encapsulating your addon's functionality. Just like the filesystem, the namespace system can make your code organized and easy to use.
Elementor uses namespaces in its code to group related classes, interfaces, functions, and constants. We recommend that developers use namespaces when developing addons.
Should you use Namespaces?
Use of namespaces is a personal choice. WordPress, for example, does not use namespaces, while Elementor's code contains many namespaces.
For Elementor addons, developers are not required to use namespaces. Addons will work with or without them.
Example Namespace Structure
Elementor's namespaces are organize in sub-namespaces to organize similar functionality:
\Elementor\
\Elementor\Core
\Elementor\Core\Editor
\Elementor\Core\Breakpoints
\Elementor\Core\Files
Defining Main Namespaces
Due to limitations in the WordPress architecture, you can't add namespaces to the main file where the header comments are located. This is why both Elementor and Elementor Pro load the plugin.php file where the functionality is located and where the main namespace is defined.
Addon developers can use the same structure:
elementor-test-addon/
|
├─ includes/
| ├─ controls/
| ├─ widgets/
| |
| └─ plugin.php
|
└─ elementor-test-addon.php
Example
The main elementor-test-addon.php file loads the functionality:
<?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
*/
function elementor_test_addon() {
// Load plugin file
require_once( __DIR__ . '/includes/plugin.php' );
// Run the plugin
\Elementor_Test_Addon\Plugin::instance();
}
add_action( 'plugins_loaded', 'elementor_test_addon' );
The /includes/plugin.php file defines the namespace and more functionality:
<?php
namespace Elementor_Test_Addon;
final class Plugin {
}
Notes
Please note that the above example incorporates three PHP classes named Plugin, one in Elementor, another one in Elementor Pro and the last one in our test addon. However since they all are using different namespaces, each has its own scope so there is no name collision:
\Elementor\Plugin()
\ElementorPro\Plugin()
\Elementor_Test_Addon\Plugin()
Header Comments
Header comments are the standard way WordPress uses to provide information about plugins. The addon's main PHP file should include a header comment with basic information. Addons can also add optional Elementor header comments.
WordPress Header Comments
To get started, we will use some very basic fields at the top of the main file:
<?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
*/
WordPress will display this information in the "WordPress Dashboard" > "Plugins" screen:
For the full list of available header fields checkout the WordPress header requirements.
Elementor Header Comments
Elementor has its own header comments where you can note the Elementor version that the addon was tested against. This is an optional header, but we recommend using it.
/**
* Elementor tested up to: x.x.x
* Elementor Pro tested up to: x.x.x
*/
Elementor has a compatibility tag to prevent compatibility problems between addons and different versions of Elementor. The compatibility tag notifies users if addons are incompatible with the user's version of Elementor. This increases transparency between Elementor and its addons. It also makes debugging easier.
Composer
开发者可以通过 Composer 安装 Elementor 和 Elementor Pro,而无需使用网页浏览器。只需几个简单的 CLI 命令即可完成。
什么是 Composer?
Composer 是一个 PHP 依赖管理工具。它简化了在 PHP 项目中安装依赖库的过程。
然而,Composer 本身并不包含 WordPress 插件和主题。为此,开发者使用 wpackagist.org,这是一个开源服务,它将 WordPress 插件和主题镜像为 Composer 仓库。
安装 Elementor
在你的 composer.json 文件中注册 WordPress Packagist 仓库:
{
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org",
"only": [
"wpackagist-plugin/*",
"wpackagist-theme/*"
]
}
]
}
安装最新版本的 Elementor:
composer require wpackagist-plugin/elementor
或者选择特定版本:
composer require wpackagist-plugin/elementor:3.25.0
安装 Elementor Pro
在你的 composer.json 文件中注册 Elementor 仓库:
{
"repositories": [
{
"type": "composer",
"url": "https://composer.elementor.com",
"only": [
"elementor/elementor-pro"
]
}
]
}
配置 composer 以使用 Elementor Pro 许可证密钥:
composer config --global --auth http-basic.composer.elementor.com token <license-key>
要将 Elementor Pro 安装到 wp-content/plugins 文件夹而不是 vendor 文件夹,请使用 composer 自定义安装器:
composer config --no-plugins allow-plugins.composer/installers true
composer require composer/installers
安装最新版本的 Elementor Pro:
composer require elementor/elementor-pro
或者选择特定版本:
composer require elementor/elementor-pro:3.25.0
激活
要激活 Elementor 和 Elementor Pro,请使用以下 WP-CLI 和 Elementor CLI 命令。
激活 Elementor 插件:
wp plugin activate elementor
激活 Elementor Pro 插件:
wp plugin activate elementor-pro
激活 Elementor Pro 许可证:
wp elementor-pro license activate <license-key>
可选地,你可以在多站点网络中激活 Elementor 和 Elementor Pro:
wp plugin activate elementor --network
wp plugin activate elementor-pro --network
wp site list --field=url | xargs -n1 -I % wp --url=% elementor-pro license activate <license-key>
实验功能激活
Elementor 允许您在实验性功能正式发布前提前使用。您可以通过管理面板或使用 experiments activate 命令行来激活实验功能。
命令
wp elementor experiments activate <experiment-name>
参数
<experiment-name>
(必填) 实验功能的名称。
使用示例
wp elementor experiments activate container
此命令将激活 container 实验功能。
实验功能停用
Elementor 用户可以访问尚未正式发布的实验性功能。这些实验可以从管理面板停用,或通过命令行使用 experiments deactivate 命令停用。
命令
wp elementor experiments deactivate <experiment-name>
参数
<experiment-name>
(必填) 实验功能的名称。
使用示例
wp elementor experiments deactivate container
此命令将停用 container 实验功能。
实验功能状态
Elementor 的实验功能可以在正式发布前使用。要从命令行检查某个实验功能是处于激活还是未激活状态,请使用 experiments status 命令。
命令
wp elementor experiments status <experiment-name>
参数
<experiment-name>
(必需) 实验功能的名称。
使用示例
wp elementor experiments status container
此命令将检查 container 实验功能是处于 active(激活)还是 inactive(未激活)状态。
刷新 CSS
在 Elementor 中设置的样式保存在数据库中,这些信息用于在 /wp-content/uploads/elementor/css/ 文件夹中生成 CSS 文件。Elementor CLI 的 flush-css 命令将删除所有缓存的 CSS 文件,并使用数据库中存储的最新设置重新创建它们。
命令
wp elementor flush-css [--regenerate] [--network]
参数
[--regenerate]
(可选) 重新创建 CSS 文件。否则,更新的 CSS 文件将在下次访问页面时由 Elementor 创建。
[--network]
(可选) 刷新网络中所有站点的 CSS 文件。
使用示例
wp elementor flush-css
此命令将刷新所有 Elementor 页面的 CSS 文件。它不会创建新的 CSS 文件,仅刷新旧文件。
wp elementor flush-css --regenerate
此命令将刷新所有 Elementor 页面的 CSS 文件并重新创建新的 CSS 文件。
wp elementor flush-css --network
此命令将刷新网络中所有站点的所有 Elementor 页面的 CSS 文件。
Elementor CLI
Elementor 集成了 WP-CLI,使您能够通过命令行界面运行某些 Elementor 任务,而无需使用网页浏览器。
什么是 WordPress CLI?
WP-CLI 是 WordPress 的命令行界面。它提供了 WordPress 管理栏的替代方案。使用命令行使开发者、代理商和托管服务提供商能够更轻松地以更少的点击次数运行操作、远程运行它们,甚至可以根据特定条件执行复杂的脚本。
什么是 Elementor CLI?
Elementor CLI 是一组集成到 WP-CLI 中的命令,允许开发者从命令行运行某些 Elementor 任务。
语法
CLI 命令语法:
wp elementor <command> [--argument]
或
wp elementor-pro <command> [--argument]
可用命令
目前,以下 Elementor 命令可用:
帮助
要通过命令行查看所有可用 Elementor 命令的列表,请使用 wp help 命令。
要获取单个命令的信息,请使用以下格式:
wp help elementor <command>
或
wp help elementor-pro <command>
套件导出
导出多个独立模板并非易事。Elementor 可以将网站的所有内容、模板和站点设置打包成一个套件进行导出。这些套件可以从管理面板导出,也可以通过命令行使用 kit export 命令导出。
命令
wp elementor kit export <file-path> [--include]
参数
<file-path>
(必需) 套件文件的路径。
[--include]
(可选) 要包含在导出中的数据类型。可能的值包括 content、templates、site-settings。如果未指定此参数,则将包含所有数据类型。
使用示例
wp elementor kit export path/to/export-file-name.zip
此命令会将所有站点数据导出到指定的文件名。
wp elementor kit export path/to/export-file-name.zip --include=site-settings,content
此命令将仅导出站点设置和内容到指定的文件名。
套件导入
Elementor 套件是模板、页面、弹窗等的集合。您无需单独导入每个模板,可以一次性导入所有内容。套件可以从管理面板导入,也可以使用 kit import 命令通过命令行导入。
命令
wp elementor kit import <file-path> [--include] [--overrideConditions] [--sourceType]
参数
<file-path>
(必需) 套件文件的路径。
[--include]
(可选) 导入时要包含的数据类型。可能的值有 content、templates、site-settings。如果未指定此参数,则将包含所有数据类型。
[--overrideConditions]
(可选) 需要覆盖条件的模板 ID。
[--sourceType]
(可选) 当前会话中使用的源类型。可用值为 local、remote、library。默认值为 local。
使用示例
wp elementor kit import path/to/elementor-kit.zip
此命令将导入整个套件文件的内容。
wp elementor kit import path/to/elementor-kit.zip --include=site-settings,content
此命令将仅导入站点设置和内容。
wp elementor kit import path/to/elementor-kit.zip --overrideConditions=3478,4520
此命令将导入所有内容,并为给定的模板 ID 覆盖条件。
wp elementor kit import path/to/elementor-kit.zip --unfilteredFilesUpload=enable
此命令将允许导入过程导入未经过滤的文件。
Library Connect
通过命令行将站点连接到 Elementor 库,只需提供 WordPress 用户和连接令牌。
命令
wp elementor library connect [--user] [--token]
参数
[--user]
(可选) 要连接的用户。接受用户 ID、用户登录名或电子邮件。
[--token]
(可选) 来自 Elementor 账户仪表板的连接令牌。
使用示例
wp elementor library connect --user=admin --token=xxx
此命令将把 WordPress admin 用户连接到 Elementor 库。
注意事项
::: warning 注意
此命令由 Elementor 团队使用,用于与 Elementor 服务器连接,以便通过 CLI 更新库以进行测试和调试。目前,外部开发者无法获取 token。
:::
库断开连接
通过命令行断开站点与 Elementor 库的连接,只需提供 WordPress 用户信息。
命令
wp elementor library disconnect [--user]
参数
[--user]
(可选) 要断开的用户。接受用户 ID、用户登录名或电子邮件。
使用示例
wp elementor library disconnect --user=admin
此命令将断开 WordPress admin 用户与 Elementor 库的连接。
库导入目录
逐个导入模板非常耗时。您可以一次性导入目录中的所有模板。Elementor CLI 的 library import-dir 命令将通过命令行导入所有模板 JSON 文件。
命令
wp elementor library import-dir <dir-path>
参数
<dir-path>
(必需) 目录的路径。
使用示例
wp elementor library import-dir path/to/custom-templates/
此命令将把 path/to/custom-templates/ 目录中的所有模板 JSON 文件导入到库中。
库导入
用户可以通过上传单个模板 JSON 文件或包含多个 JSON 文件的 ZIP 文件,从库中导入 Elementor 模板。Elementor CLI 的 library import 命令将通过命令行导入模板。
命令
wp elementor library import <file-path> [--returnType]
参数
<file-path>
(必需) 模板文件的路径。
[--returnType]
(可选) 输出格式。可用值为 ids 和 info。默认为 info。
使用示例
wp elementor library import path/to/elementor-12345-2022-03-04.json
此命令将把 path/to/elementor-12345-2022-03-04.json 模板导入到库中。
wp elementor library import path/to/elementor-12345-2022-03-04.json --returnType=ids
此命令将把 path/to/elementor-12345-2022-03-04.json 模板导入到库中,并返回已导入项目的 ID。
库同步
Elementor 在本地维护着一个可从 Elementor 模板库下载的可用模板列表。系统会安排一个临时任务,每 12 小时同步一次可用模板。Elementor CLI 的 library sync 命令可通过命令行触发从云端进行的同步。
命令
wp elementor library sync [--force] [--network]
参数
[--force]
(可选) 即使库看起来已经是最新状态,也强制进行库同步。
[--network]
(可选) 为网络中的每个站点同步库。
使用示例
wp elementor library sync
此命令将使用 Elementor 云端库同步本地库。
wp elementor library sync --force
即使库看起来已经是最新状态,此命令也将使用 Elementor 云端库进行同步。
wp elementor library sync --network
此命令将为网络中的每个站点使用 Elementor 云端库同步其库。
License Activation
Elementor Pro is a premium product that requires a license. To activate the license for a site you need a valid license key. A license can be activated from the admin panel or from the command line using the license activate command.
Command
wp elementor-pro license activate <license-key>
Arguments
<license-key>
(Required) The Elementor Pro license key.
Usage Examples
wp elementor-pro license activate XXX
This command will activate the Elementor Pro license.
License Deactivation
Some Elementor Pro licenses can activate multiple sites. If no more activations are left on a license, you can deactivate some sites to free up more activations. You can deactivate a site from the admin panel or from the command line using the license deactivate command.
Command
wp elementor-pro license deactivate
Arguments
None.
Usage Examples
wp elementor-pro license deactivate
This command will deactivate a site's Elementor Pro license.
替换 URL
更改 URL 的网站,无论是迁移到不同域名还是简单地从 HTTP 转移到 HTTPS,都需要更新数据库中的 URL。Elementor 提供了一个工具,可以在所有 Elementor 页面中将旧 URL 替换为新 URL。Elementor CLI 的 replace-urls 命令正是用于此目的。
命令
wp elementor replace-urls <old> <new> [--force]
参数
<old>
(必需) 旧 URL。
<new>
(必需) 新 URL。
[--force]
(可选) 抑制错误消息。
使用示例
wp elementor replace-urls http://elementor.com https://elementor.com
此命令将把所有 http://elementor.com HTTP URL 替换为 https://elementor.com HTTPS URL。
wp elementor replace-urls http://elementor.com https://elementor.com --force
此命令将把所有 http://elementor.com HTTP URL 替换为 https://elementor.com HTTPS URL,且不抛出错误。
系统信息
系统信息显示网站配置的详细信息。这些数据可用于调试问题,帮助开发人员和支持工程师识别问题。Elementor CLI 的 system info 命令将以 JSON 格式打印站点的系统信息。
命令
wp elementor system-info
参数
无。
使用示例
wp elementor system-info
此命令将显示完整的系统信息。
清除主题构建器条件
Elementor 主题构建器用于创建网站部件模板。这些模板可以根据预定义的条件进行应用。所有条件都会被缓存。Elementor CLI 的 theme-builder clear-conditions 命令将清除缓存的条件,以触发重新生成过程。
命令
wp elementor-pro theme-builder clear-conditions
参数
无。
使用示例
wp elementor-pro theme-builder clear-conditions
此命令将清除条件缓存并重新生成条件。
更新数据库
在某些情况下,新的 Elementor 版本会对数据库执行更改(例如迁移到套件、用全局样式替换方案等)。Elementor CLI 的 update db 命令将通过命令行触发数据库更新功能。
命令
wp elementor update db [--force] [--network]
和
wp elementor-pro update db [--force] [--network]
参数
[--force]
(可选) 即使看起来更新正在进行中,也强制更新数据库。
[--network]
(可选) 为网络中的每个站点更新数据库。
使用示例
wp elementor update db
此命令将在需要时更新数据库。
wp elementor-pro update db
此命令将在需要时更新 Elementor Pro 数据库。
wp elementor update db --force
此命令将在另一个进程正在运行时也更新数据库。
wp elementor update db --network
此命令将为网络中的每个站点更新数据库。
添加新操作
要向上下文菜单添加新操作,我们需要定义一个新的操作对象,并将该对象插入到相关的上下文菜单组中。
添加新小部件操作
在下面的示例中,我们将向现有的 custom-widget-actions 组添加一个新操作。此操作将添加一个指向 Elementor 网站的外部链接。
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
const newAction = {
name: 'elementor-link',
icon: 'eicon-alert',
title: 'Elementor Link',
isEnabled: () => true,
callback: () => window.open( 'https://elementor.com/', '_blank' ).focus(),
};
if ( 'widget' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-widget-actions' === group.name ) {
group.actions.push( newAction );
}
} );
}
return customGroups;
} );
添加新列操作
现在我们将向现有的 custom-column-actions 组添加一个新操作。此操作将在浏览器控制台中记录一些文本。
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
const newAction = {
name: 'log',
icon: 'eicon-code',
title: 'Some Console Log',
isEnabled: () => true,
callback: () => console.log( 'some text...' ),
};
if ( 'column' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-column-actions' === group.name ) {
group.actions.push( newAction );
}
} );
}
return customGroups;
} );
添加新区块操作
接下来,我们将向现有的 custom-section-actions 组添加一个新操作。此操作将打开页面设置面板。
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
const newAction = {
name: 'page-settings',
icon: 'eicon-cog',
title: 'Page Settings',
isEnabled: () => true,
callback: () => $e.run( 'panel/page-settings/settings' ),
};
if ( 'section' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-section-actions' === group.name ) {
group.actions.push( newAction );
}
} );
}
return customGroups;
} );
Add New Group
To add a new group to the context menu, we need to define a new group object and insert it into the relevant menu type (i.e. widget, column or section).
Add New Widget Group
In the example below, we'll add a new group to the widgets context menu. This group will add new actions only when right-clicking widgets in the preview.
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
const newGroup = {
name: 'custom-widget-actions',
actions: [
{
name: 'widget-action-1',
icon: 'eicon-alert',
title: 'Widget Action 1',
isEnabled: () => true,
callback: () => console.log( 'Test 1' ),
},
{
name: 'widget-action-2',
icon: 'eicon-alert',
title: 'Widget Action 2',
isEnabled: () => true,
callback: () => console.log( 'Test 2' ),
}
],
}
if ( 'widget' === elementType ) {
customGroups.push( newGroup );
}
return customGroups;
} );
Add New Column Group
Now we'll add a new group to the column context menu.
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
const newGroup = {
name: 'custom-column-actions',
actions: [
/* Actions */
],
}
if ( 'column' === elementType ) {
customGroups.push( newGroup );
}
return customGroups;
} );
Add New Section Group
Next we'll add a new group to the section context menu.
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
const newGroup = {
name: 'custom-section-actions',
actions: [
/* Actions */
],
}
if ( 'section' === elementType ) {
customGroups.push( newGroup );
}
return customGroups;
} );
Advanced Example
In this example, we'll build a full Elementor addon that sends and opens Google PageSpeed in a new tab to test page performance.
Folder Structure
The addon will have two files. The main file will register and enqueue a JS file in the editor, and the JS will add the page-speed action to the Elementor context menu.
elementor-page-speed-context-menu/
|
├─ assets/js/
| └─ page-speed-context-menu.js
|
└─ elementor-page-speed-context-menu.php
Plugin Files
elementor-page-speed-context-menu.php
<?php
/**
* Plugin Name: Elementor PageSpeed Context Menu
* Description: Add PageSpeed to Elementor context menu.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-page-speed-context-menu
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
function elementor_page_speed_context_menu_scripts() {
wp_enqueue_script(
'elementor-page-speed-context-menu',
plugins_url( 'assets/js/page-speed-context-menu.js', __FILE__ ),
[],
'1.0.0',
false
);
}
add_action( 'elementor/editor/after_enqueue_scripts', 'elementor_page_speed_context_menu_scripts' );
assets/js/page-speed-context-menu.js
window.addEventListener( 'elementor/init', () => {
const currentPageURL = elementor.documents.currentDocument.config.urls.permalink;
const pageSpeedURL = `https://developers.google.com/speed/pagespeed/insights/?url=${currentPageURL}&tab=desktop`;
const elTypes = [ 'widget', 'column', 'section' ];
// Google PageSpeed action object
const newAction = {
name: 'google-page-speed',
icon: 'eicon-wrench',
title: 'Google PageSpeed',
isEnabled: () => true,
callback: () => window.open( pageSpeedURL, '_blank' ).focus(),
};
// Add "Google PageSpeed" action to widget/column/section context menus.
elTypes.forEach( ( elType ) => {
elementor.hooks.addFilter( `elements/${elType}/contextMenuGroups`, ( groups, view ) => {
groups.forEach( ( group ) => {
if ( 'general' === group.name ) {
group.actions.push( newAction );
}
} );
return groups;
} );
} );
} );
The Result
右键菜单操作
右键菜单弹窗包含多个组,这些组内包含称为“操作”的项。操作应用于选定的元素(区块、列、小部件)。在底层,这些操作是 JS 回调函数。
操作对象
操作是一个包含以下属性和方法的 JS 对象:
const action = {
name: 'action-id',
icon: 'eicon-code',
title: 'Action Label',
shortcut: '',
isEnabled: () => true,
callback: () => {},
};
- 操作名称 - 代码中使用的唯一 ID。
- 操作图标 - 操作图标,可在 Elementor Icons 或 FontAwesome Icons 中找到。
- 操作标题 - 向用户显示的标签。
- 操作快捷键 - 触发操作的键盘快捷键。
- 是否启用 - 定义操作是启用还是禁用。
- 操作回调 - 应用于选定元素的 JS 回调函数。
::: warning 请注意 操作键盘快捷键将不在文档中介绍,因为它需要额外的 JS 组件配置。 :::
管理操作
通过挂钩到 JS elements/context-menu/groups 过滤器钩子,您可以添加、修改或删除操作项。
Context Menu Groups
Group Object
An Elementor context menu is basically a JS array of group objects. Each group object has two properties:
const group = {
name: '',
actions: [],
}
- Group Name - A unique ID used in the code.
- Group Actions - An array of action objects.
Available Groups
The built-in context menu groups for elements (section, column and widget) include:
- General (
general) - actions to edit the elements (e.g. duplicate). - Add (
addNew) - actions to add new items to the element. - Clipboard (
clipboard) - actions to copy, paste, paste style etc. - Save (
save) - actions to save as a global widget or save as a template. - Tools (
tools) - actions to open tools (e.g. navigator). - {Custom} - actions added by external developers.
- Delete (
delete) - actions to delete elements.
Groups By Element Type
Below are the default groups displayed in each element:
Section
- General
- Clipboard
- Save
- Tools
- Delete
Column
- General
- Add
- Clipboard
- Tools
- Delete
Widget
- General
- Clipboard
- Save
- Tools
- Delete
Manage Groups
To add, update or delete custom groups, you need to use the JavaScript elements/context-menu/groups filter hook. Please keep in mind that this hook doesn't change any built-in groups added by Elementor, it only allows external developers to add and modify new groups.
Context Menu Types
Elementor has several types of context menus based on the selected location or element. To open a context menu the user needs to right click an element or location. As different elements have different functionalities, each menu lists different action items. When modifying an action, developers must indicate which element the action should be applied to.
Available Types
Elementor has 3 main context menu types:
- Element, consisting of:
- Section elements
- Column elements
- Widget elements
- Empty column elements
- "Add new section / template"
Different Context Menus
Each element has its own set of actions as seen below:
Section
Column
Widget
Add new section / template
Elementor 上下文菜单
上下文菜单是一个弹出菜单,当用户在 Elementor 预览 区域右键单击某个元素时出现。此弹出菜单根据位置或所选元素提供一组可用的操作。这就是它被称为上下文菜单的原因。
上下文菜单结构
Elementor 根据所选元素或其位置有几种 类型 的上下文菜单。开发者可以挂钩到任何元素类型并修改其操作。
每个菜单分为几个 组,每组包含多个项目。上下文菜单组通过分隔符在视觉上分开。
每个菜单项称为一个 操作。操作是应用于所选元素(部分、列、小部件)的 JS 回调函数。
扩展上下文菜单
外部开发者可以注册自己的自定义操作并修改现有操作。
学习管理组:
学习管理操作:
代码示例
查看这些示例以了解上下文菜单的实际创建:
移除操作
要从上下文菜单中移除一个现有的操作,我们需要从某个组中删除该操作。
移除小部件操作
在下面的示例中,我们将从位于 widget 上下文菜单中的 custom-widget-actions 组中移除 widget-action 操作:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'widget' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-widget-actions' === group.name ) {
const actionIndex = group.actions.findIndex( ( action ) => 'widget-action' === action.name );
if ( actionIndex > -1 ) {
group.actions.splice( actionIndex, 1 );
}
}
} );
}
return customGroups;
} );
移除列操作
现在我们将从位于 column 上下文菜单中的 custom-column-actions 组中移除 column-action 操作:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'column' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-column-actions' === group.name ) {
const actionIndex = group.actions.findIndex( ( action ) => 'column-action' === action.name );
if ( actionIndex > -1 ) {
group.actions.splice( actionIndex, 1 );
}
}
} );
}
return customGroups;
} );
移除区块操作
接下来我们将从位于 section 上下文菜单中的 custom-section-actions 组中移除 section-action 操作:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'section' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-section-actions' === group.name ) {
const actionIndex = group.actions.findIndex( ( action ) => 'section-action' === action.name );
if ( actionIndex > -1 ) {
group.actions.splice( actionIndex, 1 );
}
}
} );
}
return customGroups;
} );
移除群组
要从上下文菜单中移除群组,我们需要检查该群组是否存在于相关的菜单类型中,并从上下文菜单中删除该群组。这将删除整个群组以及分配给该群组的所有操作。
移除小部件群组
在下面的示例中,我们将从 widgets 上下文菜单中移除 custom-widget-actions 群组:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'widget' === elementType ) {
const groupIndex = customGroups.findIndex( ( group ) => 'custom-widget-actions' === group.name );
if ( groupIndex > -1 ) {
customGroups.splice( groupIndex, 1 );
}
}
return customGroups;
} );
移除列群组
现在我们将从 columns 上下文菜单中移除 custom-column-actions 群组:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'column' === elementType ) {
const groupIndex = customGroups.findIndex( ( group ) => 'custom-column-actions' === group.name );
if ( groupIndex > -1 ) {
customGroups.splice( groupIndex, 1 );
}
}
return customGroups;
} );
移除区块群组
接下来我们将从 section 上下文菜单中移除 custom-section-actions 群组:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'section' === elementType ) {
const groupIndex = customGroups.findIndex( ( group ) => 'custom-section-actions' === group.name );
if ( groupIndex > -1 ) {
customGroups.splice( groupIndex, 1 );
}
}
return customGroups;
} );
Simple Example
In this example, we'll build a full Elementor addon to modify a context menu.
Folder Structure
The addon will have two files. The main file will register and enqueue a JS file in the editor, and the JS will modify the context menu.
elementor-context-menus/
|
├─ assets/js/
| └─ context-menus.js
|
└─ elementor-context-menus.php
Plugin Files
elementor-context-menus.php
<?php
/**
* Plugin Name: Elementor Context Menus
* Description: Custom context menus for Elementor page builder.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-context-menus
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
function elementor_context_menus_scripts() {
wp_enqueue_script(
'elementor-context-menus',
plugins_url( 'assets/js/context-menus.js', __FILE__ ),
[],
'1.0.0',
false
);
}
add_action( 'elementor/editor/after_enqueue_scripts', 'elementor_context_menus_scripts' );
assets/js/context-menus.js
window.addEventListener( 'elementor/init', () => {
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
const newGroup = {
name: 'elementor-links-group',
actions: [
{
name: 'elementor-link',
icon: 'eicon-link',
title: 'Elementor.com',
isEnabled: () => true,
callback: () => window.open( 'https://elementor.com/', '_blank' ).focus(),
},
{
name: 'elementor-developers-link',
icon: 'eicon-link',
title: 'Developers Docs',
isEnabled: () => true,
callback: () => window.open( 'https://developers.elementor.com/', '_blank' ).focus(),
}
],
}
if ( 'widget' === elementType ) {
customGroups.push( newGroup );
}
return customGroups;
} );
} );
The Result
更新操作
要修改一个现有的操作,我们需要更改特定条目中的操作对象值。
更新小部件操作
在下面的示例中,我们将更新 widget-action 操作的图标:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'widget' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-widget-actions' === group.name ) {
group.actions.forEach( ( action ) => {
if ( 'widget-action' === action.name ) {
action.icon = 'eicon-code';
}
} );
}
} );
}
return customGroups;
} );
更新列操作
现在我们将更新 column-action 操作的标题标签:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'column' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-column-actions' === group.name ) {
group.actions.forEach( ( action ) => {
if ( 'column-action' === action.name ) {
action.title = 'New Label';
}
} );
}
} );
}
return customGroups;
} );
更新区块操作
接下来我们将更新整个 section-action 操作:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'column' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-column-actions' === group.name ) {
group.actions.forEach( ( action ) => {
if ( 'column-action' === action.name ) {
action.icon = 'eicon-alert';
action.title = 'Hellooo';
action.callback = () => alert( 'bla bla' );
}
} );
}
} );
}
return customGroups;
} );
更新群组
要修改一个已存在的群组,我们需要更改群组对象。
更新小部件群组
在下面的示例中,我们将简单地将 widget 上下文菜单中的群组名称从 custom-widget-actions 重命名为 new-name:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'widget' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-widget-actions' === group.name ) {
group.name = 'new-name';
}
} );
}
return customGroups;
} );
更新列群组
接下来,我们将移除 column 上下文菜单中 custom-column-actions 群组内的所有操作:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'column' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-column-actions' === group.name ) {
group.actions = {};
}
} );
}
return customGroups;
} );
更新区块群组
现在我们将更新 section 上下文菜单。在 custom-section-actions 群组内,我们将更改 section-action-1 操作的图标:
elementor.hooks.addFilter( 'elements/context-menu/groups', ( customGroups, elementType ) => {
if ( 'section' === elementType ) {
customGroups.forEach( ( group ) => {
if ( 'custom-section-actions' === group.name ) {
group.actions.forEach( ( action ) => {
if ( 'section-action-1' === action.name ) {
action.icon = 'eicon-code';
}
} );
}
} );
}
return customGroups;
} );
Add New Control
Elementor offers many built-in controls out of the box, but it also allows external developers to register new controls.
Hooks
To do that we simply hook to the elementor/controls/register action which provides access to the controls manager as a parameter. Developers can use the manager to add new controls using the register() method with the controls instance.
Registering Controls
To register new controls use the following code:
function register_new_controls( $controls_manager ) {
require_once( __DIR__ . '/controls/control-1.php' );
require_once( __DIR__ . '/controls/control-2.php' );
$controls_manager->register( new \Elementor_Control_1() );
$controls_manager->register( new \Elementor_Control_2() );
}
add_action( 'elementor/controls/register', 'register_new_controls' );
The manager registers new controls by accepting control instances. For more information about the control class, read about the control class structure.
复杂示例
现在我们将构建一个插件,通过使用外部库为 Elementor 添加新控件。该控件将显示一个文本区域字段,我们将使用 Emoji One Area 库来允许用户向内容中添加表情符号。
文件夹结构
该插件将包含四个文件。主文件将注册控件和 JS 文件。为了测试控件,我们将创建一个简单的测试小部件。
elementor-emojionearea-control/
|
├─ assets/js/
| └─ emojionearea.js
|
├─ controls/
| └─ emojionearea.php
|
├─ widgets/
| └─ test-widget.php
|
└─ elementor-emojionearea-control.php
Plugin Files
elementor-emojionearea-control.php
<?php
/**
* Plugin Name: Elementor Emoji One Area Control
* Description: Add emojis to the content using Elementor Emoji One Area control.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-emojionearea-control
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register Emoji One Area Control.
*
* Include control file and register control class.
*
* @since 1.0.0
* @param \Elementor\Controls_Manager $controls_manager Elementor controls manager.
* @return void
*/
function register_emojionearea_control( $controls_manager ) {
require_once( __DIR__ . '/controls/emojionearea.php' );
$controls_manager->register( new \Elementor_EmojiOneArea_Control() );
}
add_action( 'elementor/controls/register', 'register_emojionearea_control' );
/**
* Register Test Widget.
*
* Include widget file and register widget class.
*
* @since 1.0.0
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
* @return void
*/
function register_test_widget( $widgets_manager ) {
require_once( __DIR__ . '/widgets/test-widget.php' );
$widgets_manager->register( new \Elementor_Test_Widget() );
}
add_action( 'elementor/widgets/register', 'register_test_widget' );
controls/emojionearea.php
<?php
/**
* Elementor emoji one area control.
*
* A control for displaying a textarea with the ability to add emojis.
*
* @since 1.0.0
*/
class Elementor_EmojiOneArea_Control extends \Elementor\Base_Data_Control {
/**
* Get emoji one area control type.
*
* Retrieve the control type, in this case `emojionearea`.
*
* @since 1.0.0
* @access public
* @return string Control type.
*/
public function get_type(): string {
return 'emojionearea';
}
/**
* Enqueue emoji one area control scripts and styles.
*
* Used to register and enqueue custom scripts and styles used by the emoji one
* area control.
*
* @since 1.0.0
* @access public
*/
public function enqueue(): void {
// Styles
wp_register_style( 'emojionearea', 'https://cdnjs.cloudflare.com/ajax/libs/emojionearea/3.4.2/emojionearea.css', [], '3.4.2' );
wp_enqueue_style( 'emojionearea' );
// Scripts
wp_register_script( 'emojionearea', 'https://cdnjs.cloudflare.com/ajax/libs/emojionearea/3.4.2/emojionearea.js', [], '3.4.2' );
wp_register_script( 'emojionearea-control', plugins_url( '/assets/js/emojionearea.js', dirname( __FILE__ ) ), [ 'emojionearea' ], '1.0.0' );
wp_enqueue_script( 'emojionearea-control' );
}
/**
* Get emoji one area control default settings.
*
* Retrieve the default settings of the emoji one area control. Used to return
* the default settings while initializing the emoji one area control.
*
* @since 1.0.0
* @access protected
* @return array Control default settings.
*/
protected function get_default_settings(): array {
return [
'label_block' => true,
'rows' => 3,
'emojionearea_options' => [],
];
}
/**
* Render emoji one area control output in the editor.
*
* Used to generate the control HTML in the editor using Underscore JS
* template. The variables for the class are available using `data` JS
* object.
*
* @since 1.0.0
* @access public
*/
public function content_template(): void {
$control_uid = $this->get_control_uid();
?>
<div class="elementor-control-field">
<# if ( data.label ) {#>
<label for="<?php echo esc_attr( $control_uid ); ?>" class="elementor-control-title">{{{ data.label }}}</label>
<# } #>
<div class="elementor-control-input-wrapper">
<textarea id="<?php echo esc_attr( $control_uid ); ?>" class="elementor-control-tag-area" rows="{{ data.rows }}" data-setting="{{ data.name }}" placeholder="{{ data.placeholder }}"></textarea>
</div>
</div>
<# if ( data.description ) { #>
<div class="elementor-control-field-description">{{{ data.description }}}</div>
<# } #>
<?php
}
}
assets/js/emojionearea.js
window.addEventListener( 'elementor/init', () => {
const emojioneareaItemView = elementor.modules.controls.BaseData.extend({
onReady() {
const self = this,
options = _.extend({
events: {
change: () => self.saveValue(),
emojibtn_click: () => self.saveValue(),
keyup: () => self.saveValue()
},
pickerPosition: 'bottom',
filtersPosition: 'top',
searchPosition: 'bottom',
saveEmojisAs: 'unicode',
inline: false,
}, this.model.get( 'emojionearea_options' ) );
this.ui.textarea.emojioneArea( options );
},
saveValue() {
this.setValue(this.ui.textarea[0].emojioneArea.getText());
},
onBeforeDestroy() {
this.saveValue();
this.ui.textarea[0].emojioneArea.off();
}
});
elementor.addControlView( 'emojionearea', emojioneareaItemView );
} );
widgets/test-widget.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Test Widget.
*
* Elementor widget that uses the emojionearea control.
*
* @since 1.0.0
*/
class Elementor_Test_Widget extends \Elementor\Widget_Base {
/**
* Get widget name.
*
* Retrieve test widget name.
*
* @since 1.0.0
* @access public
* @return string Widget name.
*/
public function get_name(): string {
return 'test';
}
/**
* Get widget title.
*
* Retrieve test widget title.
*
* @since 1.0.0
* @access public
* @return string Widget title.
*/
public function get_title(): string {
return esc_html__( 'Test', 'elementor-emojionearea-control' );
}
/**
* Get widget icon.
*
* Retrieve test widget icon.
*
* @since 1.0.0
* @access public
* @return string Widget icon.
*/
public function get_icon(): string {
return 'eicon-code';
}
/**
* Get widget categories.
*
* Retrieve the list of categories the test widget belongs to.
*
* @since 1.0.0
* @access public
* @return array Widget categories.
*/
public function get_categories(): array {
return [ 'general' ];
}
/**
* Get widget keywords.
*
* Retrieve the list of keywords the test widget belongs to.
*
* @since 1.0.0
* @access public
* @return array Widget keywords.
*/
public function get_keywords(): array {
return [ 'test', 'emoji' ];
}
/**
* Get custom help URL.
*
* Retrieve a URL where the user can get more information about the widget.
*
* @since 1.0.0
* @access public
* @return string Widget help URL.
*/
public function get_custom_help_url(): string {
return 'https://developers.elementor.com/docs/widgets/';
}
/**
* Whether the widget requires inner wrapper.
*
* Determine whether to optimize the DOM size.
*
* @since 1.0.0
* @access public
* @return bool Whether to optimize the DOM size.
*/
public function has_widget_inner_wrapper(): bool {
return false;
}
/**
* Whether the element returns dynamic content.
*
* Determine whether to cache the element output or not.
*
* @since 1.0.0
* @access protected
* @return bool Whether to cache the element output.
*/
protected function is_dynamic_content(): bool {
return false;
}
/**
* Register test widget controls.
*
* Add input fields to allow the user to customize the widget settings.
*
* @since 1.0.0
* @access protected
*/
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'elementor-emojionearea-control' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'content',
[
'label' => esc_html__( 'Content with Emoji', 'elementor-emojionearea-control' ),
'type' => 'emojionearea',
]
);
$this->end_controls_section();
}
/**
* Render test widget output on the frontend.
*
* Written in PHP and used to generate the final HTML.
*
* @since 1.0.0
* @access protected
*/
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['content'] ) ) {
return;
}
echo $settings['content'];
}
}
The Result
The emojis control as it appears in a widget:
The control content as displayed in Elementor preview:
Control Enqueue
Controls can register and enqueue scripts & styles used by the control.
Enqueue Method
If you need to use an external library or some custom JS/CSS, you can do that by registering scripts using the enqueue() method:
class Elementor_Test_Control extends \Elementor\Base_Control {
protected function enqueue(): void {
// Styles
wp_register_style( 'control-style', plugins_url( 'assets/css/control-style.css', __FILE__ ) );
wp_enqueue_style( 'control-style' );
// Scripts
wp_register_script( 'control-script', plugins_url( 'assets/js/control-script.js', __FILE__ ) );
wp_enqueue_script( 'control-script' );
}
}
控件设置
控件设置允许开发者为控件设置默认值,例如标签、描述、是否显示分隔符、隐藏标签等。
可用设置
每个控件都有默认设置,这些设置决定了控件在面板中的结构和设计。这些默认设置在 $_base_settings 属性中定义。以下是所有控件共有的默认设置列表:
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
label |
string |
显示在字段上方的标签 | |
description |
string |
显示在字段下方的描述 | |
show_label |
bool |
true |
是否显示标签 |
label_block |
bool |
false |
是否在单独一行显示标签 |
separator |
string |
default |
设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
每个控件都可以覆盖默认设置并添加新的自定义设置。
设置方法
如果控件使用默认设置,则无需将其添加到类中。如果要更改默认设置或添加新设置,请使用 get_default_settings() 方法。此方法应返回一个数组:
class Elementor_Test_Control extends \Elementor\Base_Control {
protected function get_default_settings(): array {
return [
'label_block' => true,
'separator' => 'after',
'new_settings_value' => '',
'new_multiple_values' => [],
];
}
}
之后,在生成控件模板时,可以利用这些设置。
控制结构
创建自定义控件是专为非常熟悉代码库的高级 Elementor 开发者保留的任务。这个过程从学习 Base_Control 类及其内部方法开始。这将使您能够理解 Elementor 如何创建不同的控件,以及如何自定义这些基础方法。
每个控件必须有两个基本方法——一个唯一的名称和在编辑器中显示字段的 HTML 代码。更高级的控件可以设置自定义设置、定义默认值、加载脚本和样式等等。
扩展控件
要创建您自己的控件,您需要扩展抽象基础控件:
class Elementor_Test_Control extends \Elementor\Base_Control {
}
您也可以扩展特定控件类型之一:
class Elementor_Test_Control extends \Elementor\Base_Data_Control {
}
这样,您的类将继承您所扩展类的所有方法。
控件方法
一个简单的控件只需要两个方法:控件类型和模板:
class Elementor_Test_Control extends \Elementor\Base_Control {
public function get_type(): string {}
public function content_template(): void {}
}
更高级的控件可以使用其他可用方法:
class Elementor_Test_Control extends \Elementor\Base_Control {
public function get_type(): string {}
protected function get_default_settings(): array {}
public function get_default_value(): string {}
public function content_template(): void {}
public function enqueue(): void {}
}
这些方法可以分为以下几组:
控制模板
该模板生成在编辑器中显示的最终 HTML。模板使用 JS 通过 data JS 对象从设置中返回数据。
模板方法
您可以使用相同的 JS 模板来设计用户界面样式。
使用 JS 模板,我们无需通过特殊函数检索数据,Elementor 会为我们处理。来自控件的数据存储在 data 变量中:
<?php
class Elementor_Test_Control extends \Elementor\Base_Control {
public function content_template(): void {
$control_uid = $this->get_control_uid();
?>
<div class="elementor-control-field">
<# if ( data.label ) {#>
<label for="<?php echo $control_uid; ?>" class="elementor-control-title">{{{ data.label }}}</label>
<# } #>
<div class="elementor-control-input-wrapper elementor-control-unit-5 elementor-control-dynamic-switcher-wrapper">
<input id="<?php echo $control_uid; ?>" type="{{ data.input_type }}" class="tooltip-target elementor-control-tag-area" data-tooltip="{{ data.title }}" title="{{ data.title }}" data-setting="{{ data.name }}" placeholder="{{ data.placeholder }}" />
</div>
</div>
<# if ( data.description ) { #>
<div class="elementor-control-field-description">{{{ data.description }}}</div>
<# } #>
<?php
}
}
Control Values
You can set custom default values for your control. For example, if you add a new field, you can define its default value.
Control Default Value
Set the default values to display when initializing the control. Note that some controls return a single value (strings, numbers, bool etc.), while other controls return arrays. Make sure you set a default value with the same data type.
The following will set a default value for a data control, which will return a single value:
class Elementor_Test_Control extends \Elementor\Base_Data_Control {
public function get_type(): string {
return 'continents-control';
}
protected function get_default_settings(): array {
return [
'continents' => [ 'Asia', 'Africa', 'Europe', 'North America', 'South America', 'Australia/Oceania', 'Antarctica', ]
];
}
public function get_default_value(): string {
return 'Europe';
}
}
Overriding Default Values
When controls are used in widgets, you can either use the default value set by the control or override it and set your own default values:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
// Control default value will be used, i.e. 'Europe'
$this->add_control(
'continent_1',
[
'label' => esc_html__( 'Continent 1', 'textdomain' ),
'type' => 'continents-control',
]
);
// Custom default value will be used, i.e. 'North America'
$this->add_control(
'continent_2',
[
'label' => esc_html__( 'Continent 2', 'textdomain' ),
'type' => 'continents-control',
'default' => 'North America',
]
);
$this->end_controls_section();
}
}
Elementor 控件
Elementor 控件是用于构建界面的输入字段和UI 元素。控件允许用户自定义可用面板设置,并在预览中更改设计。
Elementor 包含一系列开箱即用的控件。它们被用于小部件和面板中,以收集访问者数据并根据其选择生成自定义输出。
控件参数
了解更多如何自定义控件:
创建控件
了解更多关于如何创建自定义控件的信息:
代码示例
查看创建新控件是多么简单:
Remove Controls
To remove existing control developers can simply unregister existing control by passing the control name.
Hooks
To do that we need to hook to the elementor/controls/register action which holds the controls manager, and pass the control name to the unregister() method.
Unregistering Controls
To unregister existing controls use the following code:
function unregister_controls( $controls_manager ) {
$controls_manager->unregister( 'control-1' );
$controls_manager->unregister( 'control-2' );
}
add_action( 'elementor/controls/register', 'unregister_controls' );
简单示例
让我们构建一个为 Elementor 添加新控件的插件。该控件将显示一个可选择货币的下拉字段。
文件夹结构
该插件将包含三个文件。主文件将注册控件和 JS 文件。为了测试控件,我们将创建一个简单的测试小部件。
elementor-currency-control/
|
├─ controls/
| └─ currency.php
|
├─ widgets/
| └─ currency-widget.php
|
└─ elementor-currency-control.php
Plugin Files
elementor-currency-control.php
<?php
/**
* Plugin Name: Elementor Currency Control
* Description: Add new Elementor control for currencies selection.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-currency-control
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register Currency Control.
*
* Include control file and register control class.
*
* @since 1.0.0
* @param \Elementor\Controls_Manager $controls_manager Elementor controls manager.
* @return void
*/
function register_currency_control( $controls_manager ) {
require_once( __DIR__ . '/controls/currency.php' );
$controls_manager->register( new \Elementor_Currency_Control() );
}
add_action( 'elementor/controls/register', 'register_currency_control' );
/**
* Register Currency Widget.
*
* Include widget file and register widget class.
*
* @since 1.0.0
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
* @return void
*/
function register_currency_widget( $widgets_manager ) {
require_once( __DIR__ . '/widgets/currency-widget.php' );
$widgets_manager->register( new \Elementor_Currency_Widget() );
}
add_action( 'elementor/widgets/register', 'register_currency_widget' );
controls/currency.php
<?php
/**
* Elementor currency control.
*
* A control for displaying a select field with the ability to choose currencies.
*
* @since 1.0.0
*/
class Elementor_Currency_Control extends \Elementor\Base_Data_Control {
/**
* Get currency control type.
*
* Retrieve the control type, in this case `currency`.
*
* @since 1.0.0
* @access public
* @return string Control type.
*/
public function get_type(): string {
return 'currency';
}
/**
* Get currencies.
*
* Retrieve all the available currencies.
*
* @since 1.0.0
* @access public
* @static
* @return array Available currencies.
*/
public static function get_currencies(): array {
return [
'USD' => 'USD ($)',
'EUR' => 'EUR (€)',
'GBP' => 'GBP (£)',
'JPY' => 'JPY (¥)',
'ILS' => 'ILS (₪)',
];
}
/**
* Get currency control default settings.
*
* Retrieve the default settings of the currency control. Used to return
* the default settings while initializing the currency control.
*
* @since 1.0.0
* @access protected
* @return array Currency control default settings.
*/
protected function get_default_settings(): array {
return [
'currencies' => self::get_currencies()
];
}
/**
* Get currency control default value.
*
* Retrieve the default value of the currency control. Used to return the
* default value while initializing the control.
*
* @since 1.0.0
* @access public
* @return array Currency control default value.
*/
public function get_default_value(): string {
return 'EUR';
}
/**
* Render currency control output in the editor.
*
* Used to generate the control HTML in the editor using Underscore JS
* template. The variables for the class are available using `data` JS
* object.
*
* @since 1.0.0
* @access public
*/
public function content_template(): void {
$control_uid = $this->get_control_uid();
?>
<div class="elementor-control-field">
<# if ( data.label ) {#>
<label for="<?php echo $control_uid; ?>" class="elementor-control-title">{{{ data.label }}}</label>
<# } #>
<div class="elementor-control-input-wrapper">
<select id="<?php echo $control_uid; ?>" data-setting="{{ data.name }}">
<option value=""><?php echo esc_html__( 'Select currency', 'elementor-currency-control' ); ?></option>
<# _.each( data.currencies, function( currency_label, currency_value ) { #>
<option value="{{ currency_value }}">{{{ currency_label }}}</option>
<# } ); #>
</select>
</div>
</div>
<# if ( data.description ) { #>
<div class="elementor-control-field-description">{{{ data.description }}}</div>
<# } #>
<?php
}
}
widgets/currency-widget.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Currency Widget.
*
* Elementor widget that uses the currency control.
*
* @since 1.0.0
*/
class Elementor_Currency_Widget extends \Elementor\Widget_Base {
/**
* Get widget name.
*
* Retrieve currency widget name.
*
* @since 1.0.0
* @access public
* @return string Widget name.
*/
public function get_name(): string {
return 'currency';
}
/**
* Get widget title.
*
* Retrieve currency widget title.
*
* @since 1.0.0
* @access public
* @return string Widget title.
*/
public function get_title(): string {
return esc_html__( 'Currency', 'elementor-currency-control' );
}
/**
* Get widget icon.
*
* Retrieve currency widget icon.
*
* @since 1.0.0
* @access public
* @return string Widget icon.
*/
public function get_icon(): string {
return 'eicon-cart-medium';
}
/**
* Get widget categories.
*
* Retrieve the list of categories the currency widget belongs to.
*
* @since 1.0.0
* @access public
* @return array Widget categories.
*/
public function get_categories(): array {
return [ 'general' ];
}
/**
* Get widget keywords.
*
* Retrieve the list of keywords the currency widget belongs to.
*
* @since 1.0.0
* @access public
* @return array Widget keywords.
*/
public function get_keywords(): array {
return [ 'currency', 'currencies' ];
}
/**
* Get custom help URL.
*
* Retrieve a URL where the user can get more information about the widget.
*
* @since 1.0.0
* @access public
* @return string Widget help URL.
*/
public function get_custom_help_url(): string {
return 'https://developers.elementor.com/docs/widgets/';
}
/**
* Whether the widget requires inner wrapper.
*
* Determine whether to optimize the DOM size.
*
* @since 1.0.0
* @access public
* @return bool Whether to optimize the DOM size.
*/
public function has_widget_inner_wrapper(): bool {
return false;
}
/**
* Whether the element returns dynamic content.
*
* Determine whether to cache the element output or not.
*
* @since 1.0.0
* @access protected
* @return bool Whether to cache the element output.
*/
protected function is_dynamic_content(): bool {
return false;
}
/**
* Register currency widget controls.
*
* Add input fields to allow the user to customize the widget settings.
*
* @since 1.0.0
* @access protected
*/
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'elementor-currency-control' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'price',
[
'label' => esc_html__( 'Price', 'elementor-currency-control' ),
'type' => \Elementor\Controls_Manager::NUMBER,
'default' => 100,
]
);
$this->add_control(
'price_currency',
[
'label' => esc_html__( 'Currency', 'elementor-currency-control' ),
'type' => 'currency',
]
);
$this->end_controls_section();
}
/**
* Render currency widget output on the frontend.
*
* Written in PHP and used to generate the final HTML.
*
* @since 1.0.0
* @access protected
*/
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['price_currency'] ) ) {
return;
}
echo $settings['price_currency'] . ' ' . $settings['price'];
}
}
The Result
Container Element
The container is a layout element with nested capabilities, meaning that it can hold other elements. The container object contains information like the element id, element type, styling settings and all the element inside the container.
JSON Structure
Container element structure:
{
"id": "12345678",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
JSON Values
| Argument | Type | Description |
|---|---|---|
id |
string |
The unique identification key representing the element. |
elType |
string |
The element type. |
isInner |
boolean |
Whether the element is an inner element. |
settings |
array/object |
The element data from the panel, holding the values from the editor controls. It's an empty array if settings are not defined, or an object if the element has settings. |
elements |
array |
An array of objects that holds all the nested elements. |
Nested Elements
By design, containers can hold nested elements. All the inner elements are stored in the elements value, and they can have their own nested elements.
Examples
A Page with Containers
An example of a page that has two empty containers:
{
"title": "Sample Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "6af611eb",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
},
{
"id": "7fb170b9",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
A Page with Nested Container
An example of a page that has a container element with nested containers:
{
"title": "Test Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "458aabdc",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "46ef0576",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "4a59f2e3",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
]
}
]
}
A Page with a Container and Custom Settings
An example of a page that has a container with some custom styling settings:
{
"title": "Test Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "458aabdc",
"elType": "container",
"isInner": false,
"settings": {
"height": "min-height",
"custom_height": {
"unit": "vh",
"size": 70,
"sizes": []
},
"content_position": "middle",
"html_tag": "section"
},
"elements": []
}
]
}
通用元素
每个 Elementor 元素,无论是布局元素(区块、列、容器)还是小部件元素,都拥有一组基本信息。这些数据在创建页面时用于解析元素。
JSON 结构
基本元素结构:
{
"id": "12345678",
"elType": "element",
"isInner": false,
"settings": [],
"elements": []
}
JSON 值
| 参数 | 类型 | 描述 |
|---|---|---|
id |
string |
代表该元素的唯一标识键。 |
elType |
string |
元素类型。 |
isInner |
boolean |
该元素是否为内部元素。 |
settings |
array/object |
来自面板的元素数据,保存着编辑器控件的值。如果未定义设置,则为空 array;如果元素有设置,则为 object。 |
elements |
array |
一个包含所有嵌套元素的对象数组。 |
根据元素类型,可以引入额外的值。例如,当 elType 为 widget 时,会添加一个额外的 widgetType 值来指示部件名称(例如 heading、image、button、social-icons 等)。
布局元素与部件元素
Elementor 支持的两大主要元素类型是布局元素和部件元素。布局元素(区块、列、容器)可能存储关于嵌套 elements 的数据,而部件元素主要存储关于部件 settings 的数据。
Examples
A Page with Containers
An example of a page that has two empty containers:
{
"title": "Sample Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "6af611eb",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
},
{
"id": "7fb170b9",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
A Page with Nested Container
An example of a page that has a container element with nested containers:
{
"title": "Test Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "458aabdc",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "46ef0576",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "4a59f2e3",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
]
}
]
}
A Page with Widgets
An example of a page that has a container element with three nested widgets:
{
"title": "About Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "6af611eb",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "6a637978",
"elType": "widget",
"widgetType": "heading",
"isInner": false,
"settings": {
"title": "Add Your Heading Text Here",
"align": "center"
},
"elements": []
},
{
"id": "687dba89",
"elType": "widget",
"widgetType": "image",
"isInner": false,
"settings": {
"_padding": {
"unit": "px",
"top": "100",
"right": "0",
"bottom": "100",
"left": "0",
"isLinked": false
}
},
"elements": []
},
{
"id": "6f58bb5",
"elType": "widget",
"widgetType": "button",
"isInner": false,
"settings": {
"text": "Click Me",
"button_text_color": "#000000",
"background_color": "#E7DFF5"
},
"elements": []
}
]
}
]
}
通用结构
JSON 结构包含一个对象,其中存储了页面相关信息。这些信息包括文档类型、标题和版本。此外,它还包含实际数据,例如文档设置和文档内容。
JSON Structure
Basic structure:
{
"title": "Template Title",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": []
}
JSON Values
| Argument | Type | Description |
|---|---|---|
title |
string |
The title displayed to the user in the WordPress dashboard and the Elementor Editor. |
type |
string |
The document type. Available values are: header, footer, error-404, popup, page, post, etc. |
version |
string |
The data structure version. The latest version is 0.4. |
page_settings |
array/object |
Data from the "Page Setting" panel. An empty array if settings are not defined, an object if the page has settings. |
content |
array |
An array of objects that holds all the page elements. |
Examples
Header JSON Example
A "header" template with custom page settings and a single element.
{
"title": "Site Header",
"type": "header",
"version": "0.4",
"page_settings": {
"content_wrapper_html_tag": "header",
"background_background": "classic",
"background_color": "#000000"
},
"content": [
{
"id": "3130e2cf",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
Footer JSON Example
{
"title": "Site Footer",
"type": "footer",
"version": "0.4",
"page_settings": {
"content_wrapper_html_tag": "footer"
},
"content": [
{
"id": "1aebaeaa",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
404 页面 JSON 示例
一个带有自定义背景色的 "404 页面":
{
"title": "404 Page",
"type": "error-404",
"version": "0.4",
"page_settings": {
"content_wrapper_html_tag": "main",
"background_background": "classic",
"background_color": "#333333"
},
"content": []
}
弹窗 JSON 示例
一个用于移动导航的弹窗,包含一些与弹窗相关的设置:
{
"title": "Mobile Navigation Popup",
"type": "popup",
"version": "0.4",
"page_settings": {
"width": {
"unit": "px",
"size": 600,
"sizes": []
},
"entrance_animation": "fadeIn",
"exit_animation": "fadeIn",
"overlay_background_color": "#000000AA",
"prevent_scroll": "yes"
},
"content": [
{
"id": "c647ac2",
"elType": "container",
"isInner": false,
"settings": {
"padding": {
"unit": "px",
"top": "20",
"right": "20",
"bottom": "20",
"left": "20",
"isLinked": true
}
},
"elements": []
}
]
}
全局样式
开发中
数据结构
Elementor 依赖特定的数据结构来运行。该结构在平台的流程中扮演着重要角色,对其操作至关重要。开发者应熟悉 Elementor 数据结构的关键方面,包括其格式和应用。
Elementor 引擎
整个 Elementor 引擎由多个与 Elementor 数据层交互的组件组成。它是 Elementor 功能不可或缺的一部分,并贯穿其所有操作。
引擎功能有两个不同的方面:
- 编辑器负责通过可视化的拖放界面创建结构化数据。
- 前端负责解析页面数据以创建页面布局。
数据格式
在数据格式方面,Elementor 使用 JSON 来构建数据,因为它易于人类读写,也易于机器解析和生成。JSON 文件广泛用于以结构化方式交换数据,这使其成为 Elementor 的实用选择。
保存的数据
Elementor JSON 数据结构用于存储使用 Elementor 创建的页面的配置和内容。它是页面布局及其设置的序列化表示。
JSON 数据是标准化的,因此可以导出和导入,以便在不同的页面和不同的 WordPress 安装中复制页面设计。
数据存储
当用户在编辑器中点击保存按钮时,Elementor 将页面数据和布局以 JSON 格式存储为 WordPress 文章元数据,这本质上是一个 WordPress 自定义字段。WordPress 将自定义字段存储在数据库的 wp_postmeta 表中。
Elementor 数据被保存为私有自定义字段,在 WordPress 仪表板中不可见。访问数据的一个简单方法是下载 Elementor "模板" 文件。此操作会创建一个包含页面数据的 *.json 文件。
Elementor 数据结构
要了解 JSON 文件的结构,请阅读以下内容:
有关不同元素类型的信息:
特殊情况:
页面内容
页面内容是一个 array 类型的对象数组,它保存了页面上的所有元素。此字段是递归的,意味着它可以包含嵌套元素,即元素内部可以包含其他元素。容器元素可以包含其他容器和小部件,而嵌套的小部件也可以包含其他小部件。
JSON 结构
如果页面没有内容,content 是一个空 array:
{
"title": "Template Title",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": []
}
如果页面有内容,content 包含一个对象列表:
{
"title": "Template Title",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "6af611eb",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
Page Elements
Elements are simple objects containing element data. Some elements can have nested elements inside of them, others don't.
This is important as in the past Elementor had a strict data structure - the traditional structure. The page had "section" elements, sections had nested "column" elements, and the columns had "widget" elements.
With the introduction of containers, Elementor replaced the traditional data structure with a modern structure, allowing the user to nest multiple elements one inside the other.
Traditional structure:
Modern structure:
With the adoption of nested layout elements, Elementor introduced widgets with nested capabilities. Widgets like the nested "Tabs", nested "Accordion", nested "Carousel", and nested "Menu" (mega menu).
Examples
A Page with a Section and a Column
An example of a page that uses the traditional section-column-widget structure:
{
"title": "Sample Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "123ab956",
"elType": "section",
"isInner": false,
"settings": [],
"elements": [
{
"id": "1d4a679a",
"elType": "column",
"isInner": false,
"settings": [],
"elements": [
{
"id": "1d4a679a",
"elType": "widget",
"widgetType": "image",
"isInner": false,
"settings": [],
"elements": []
}
]
}
]
}
]
}
A Page with a Container
An example of a page that has two empty containers:
{
"title": "Sample Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "6af611eb",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
},
{
"id": "7fb170b9",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
A Page with Nested Containers
An example of a page that has a container element with several nested containers:
{
"title": "Test Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "458aabdc",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "46ef0576",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "4a59f2e3",
"elType": "container",
"isInner": false,
"settings": [],
"elements": []
}
]
}
]
}
]
}
A Page with a few Widgets
An example of a page that has a container element with three nested widgets:
{
"title": "About Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "6af611eb",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "6a637978",
"elType": "widget",
"widgetType": "heading",
"isInner": false,
"settings": {
"title": "Add Your Heading Text Here",
"align": "center"
},
"elements": []
},
{
"id": "687dba89",
"elType": "widget",
"widgetType": "image",
"isInner": false,
"settings": {
"_padding": {
"unit": "px",
"top": "100",
"right": "0",
"bottom": "100",
"left": "0",
"isLinked": false
}
},
"elements": []
},
{
"id": "6f58bb5",
"elType": "widget",
"widgetType": "button",
"isInner": false,
"settings": {
"text": "Click Me",
"button_text_color": "#000000",
"background_color": "#E7DFF5"
},
"elements": []
}
]
}
]
}
Page Settings
Data from the Page Settings panel is saved as a separate page_settings value. When the page has no settings, the value is an empty array, when the page has settings it's an object of key-value pairs containing the settings.
JSON Structure
If the page has no settings, page_settings is an empty array:
{
"title": "Template Title",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": []
}
If the page has settings, page_settings is an object of key-value pairs:
{
"title": "Template Title",
"type": "page",
"version": "0.4",
"page_settings": {
"key": "value",
"key": "value"
},
"content": []
}
Saved Data
The Page Settings panel displays several editor controls that allow the user to change WordPress-related data and Elementor-related data.
The WordPress-related data includes the page title, excerpt, feature image, post status, etc. This data is saved in the "wp_posts" table in the database.
Furthermore, different Elementor documents may have different page settings. A good example is popups, which add additional controls to the page settings screen. Addon developers may also add additional controls to the page settings panel, controls that may apply page-wide styles. The data from all those controls is stored in page_settings.
Examples
Empty Page Example
An empty page that has no settings:
{
"title": "About Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": []
}
Styled Page Example
A page that has some basic styling settings:
{
"title": "Template Title",
"type": "page",
"version": "0.4",
"page_settings": {
"background_background": "classic",
"background_color": "#FFFFFF",
"margin": {
"unit": "px",
"top": "0",
"right": "0",
"bottom": "0",
"left": "0",
"isLinked": true
},
"padding": {
"unit": "px",
"top": "0",
"right": "10",
"bottom": "0",
"left": "10",
"isLinked": false
},
"scroll_snap": "yes"
},
"content": []
}
中继器
开发中
响应式数据
开发中
小部件元素
Elementor 小部件是一个拥有自定义属性的元素。小部件对象包含元素 ID、元素类型、小部件类型以及基于小部件控件的所有元素设置等信息。
JSON 结构
Widget 元素结构:
{
"id": "12345678",
"elType": "widget",
"widgetType": "heading",
"isInner": false,
"settings": [],
"elements": []
}
JSON 值
| 参数 | 类型 | 描述 |
|---|---|---|
id |
string |
代表该元素的唯一标识键。 |
elType |
string |
元素类型。 |
widgetType |
string |
Widget 类型。 |
isInner |
boolean |
该元素是否为内部元素。 |
settings |
array/object |
来自面板的元素数据,保存了编辑器控件的值。如果未定义设置,则为空 array;如果元素有设置,则为 object。 |
elements |
array |
一个包含所有嵌套元素的对象数组。 |
嵌套元素
最初,Elementor 小部件不支持嵌套功能。最近,Elementor 开始探索允许嵌套功能的新方法。新的“菜单”小部件已支持嵌套功能,我们计划发布支持嵌套功能的“手风琴”、“选项卡”、“轮播”及其他小部件。
控件数据
每个控件都有一组自定义设置项。当用户将控件拖入页面并设置自定义值时,这些信息会以键值对形式保存在 settings 对象中。控件 ID 作为键名,数据作为键值。
Examples
A Page with Widgets
An example of a page that has a container element with three nested containers:
{
"title": "About Page",
"type": "page",
"version": "0.4",
"page_settings": [],
"content": [
{
"id": "6af611eb",
"elType": "container",
"isInner": false,
"settings": [],
"elements": [
{
"id": "6a637978",
"elType": "widget",
"widgetType": "heading",
"isInner": false,
"settings": {
"title": "Add Your Heading Text Here",
"align": "center"
},
"elements": []
},
{
"id": "687dba89",
"elType": "widget",
"widgetType": "image",
"isInner": false,
"settings": {
"_padding": {
"unit": "px",
"top": "100",
"right": "0",
"bottom": "100",
"left": "0",
"isLinked": false
}
},
"elements": []
},
{
"id": "6f58bb5",
"elType": "widget",
"widgetType": "button",
"isInner": false,
"settings": {
"text": "Click Me",
"button_text_color": "#000000",
"background_color": "#E7DFF5"
},
"elements": []
}
]
}
]
}
Advanced Example
A common example of deprecation is the managers registration process in Elementor 3.5. In this instance, many registration methods and hooks have been standardized and simplified using intuitive naming conventions.
Widgets
When registering new widgets, we renamed the action hook name and the registration method:
function register_new_widgets( $widgets_manager ) {
require_once( __DIR__ . '/widgets/widget-1.php' );
require_once( __DIR__ . '/widgets/widget-2.php' );
- $widgets_manager->register_widget_type( new \Elementor_Widget_1() );
- $widgets_manager->register_widget_type( new \Elementor_Widget_2() );
+ $widgets_manager->register( new \Elementor_Widget_1() );
+ $widgets_manager->register( new \Elementor_Widget_2() );
}
- add_action( 'elementor/widgets/widgets_registered', 'register_new_widgets' );
+ add_action( 'elementor/widgets/register', 'register_new_widgets' );
Controls
When registering new controls, we renamed the action hook and the registration method. We also removed the control name argument:
function register_new_controls( $controls_manager ) {
require_once( __DIR__ . '/controls/control-1.php' );
require_once( __DIR__ . '/controls/control-2.php' );
- $controls_manager->register_control( 'control-name', new \Elementor_Control_1() );
- $controls_manager->register_control( 'control-name', new \Elementor_Control_2() );
+ $controls_manager->register( new \Elementor_Control_1() );
+ $controls_manager->register( new \Elementor_Control_2() );
}
- add_action( 'elementor/controls/controls_registered', 'register_new_controls' );
+ add_action( 'elementor/controls/register', 'register_new_controls' );
Complex Example
In Elementor 3.0, the limited Schemes mechanism had been replaced with Globals which allows users to define limitless colors and typographies. Addons using schemes in their widgets controls should update their code.
从 Schemes 迁移到 Globals
为了从已弃用的 Schemes 迁移到新的 Globals,开发者应查找颜色和排版组控件,并进行更改。
排版
替换以下内容:
\Elementor\Core\Schemes\Typography::TYPOGRAPHY_1\Elementor\Core\Schemes\Typography::TYPOGRAPHY_2\Elementor\Core\Schemes\Typography::TYPOGRAPHY_3\Elementor\Core\Schemes\Typography::TYPOGRAPHY_4
为:
\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_SECONDARY\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_TEXT\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_ACCENT
示例如下:
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'heading_typography',
- 'scheme' => \Elementor\Core\Schemes\Typography::TYPOGRAPHY_1,
+ 'global' => [
+ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY,
+ ],
'selector' => '{{WRAPPER}} .heading-class',
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'subheading_typography',
- 'scheme' => \Elementor\Core\Schemes\Typography::TYPOGRAPHY_2,
+ 'global' => [
+ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_SECONDARY,
+ ],
'selector' => '{{WRAPPER}} .subheading-class',
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'text_typography',
- 'scheme' => \Elementor\Core\Schemes\Typography::TYPOGRAPHY_3,
+ 'global' => [
+ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_TEXT,
+ ],
'selector' => '{{WRAPPER}} .text-class',
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'accent_typography',
- 'scheme' => \Elementor\Core\Schemes\Typography::TYPOGRAPHY_4,
+ 'global' => [
+ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_ACCENT,
+ ],
'selector' => '{{WRAPPER}} .accent-class',
]
);
颜色
替换以下内容:
\Elementor\Core\Schemes\Color::COLOR_1\Elementor\Core\Schemes\Color::COLOR_2\Elementor\Core\Schemes\Color::COLOR_3\Elementor\Core\Schemes\Color::COLOR_4
为:
\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_SECONDARY\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_TEXT\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_ACCENT
示例如下:
$this->add_control(
'heading_color',
[
'label' => esc_html__( 'Heading Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
- 'scheme' => [
- 'type' => \Elementor\Core\Schemes\Color::get_type(),
- 'value' => \Elementor\Core\Schemes\Color::COLOR_1,
- ],
+ 'global' => [
+ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY,
+ ],
'selectors' => [
'{{WRAPPER}} .heading-class' => 'color: {{VALUE}};',
],
]
);
$this->add_control(
'subheading_color',
[
'label' => esc_html__( 'Subheading Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
- 'scheme' => [
- 'type' => \Elementor\Core\Schemes\Color::get_type(),
- 'value' => \Elementor\Core\Schemes\Color::COLOR_2,
- ],
+ 'global' => [
+ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_SECONDARY,
+ ],
'selectors' => [
'{{WRAPPER}} .subheading-class' => 'color: {{VALUE}};',
],
]
);
$this->add_control(
'text_color',
[
'label' => esc_html__( 'Text Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
- 'scheme' => [
- 'type' => \Elementor\Core\Schemes\Color::get_type(),
- 'value' => \Elementor\Core\Schemes\Color::COLOR_3,
- ],
+ 'global' => [
+ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_TEXT,
+ ],
'selectors' => [
'{{WRAPPER}} .text-class' => 'color: {{VALUE}};',
],
]
);
$this->add_control(
'accent_color',
[
'label' => esc_html__( 'Accent Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
- 'scheme' => [
- 'type' => \Elementor\Core\Schemes\Color::get_type(),
- 'value' => \Elementor\Core\Schemes\Color::COLOR_4,
- ],
+ 'global' => [
+ 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_ACCENT,
+ ],
'selectors' => [
'{{WRAPPER}} .accent-class' => 'color: {{VALUE}};',
],
]
);
Deprecated Action Hooks
Elementor offers the Deprecation::do_deprecated_action() method to handle the deprecation process for actions hooks inside Elementor code.
Use Cases
When considering naming conventions, the old naming conventions should work alongside the new ones.
An example of renaming occured when Elementor unified the registration process for several components in versions 3.5. Many action hooks across different managers were renamed.
How To Deprecate Action Hooks
We have an action hook called elementor/old/action, and want to rename it elementor/new/action.
For example, take the following code:
class Name {
function init( $args ): void {
do_action( 'elementor/old/action', $args );
}
}
The new code, with the deprecation handler, will look like this:
use Elementor\Plugin;
class Name {
function init( $args ): void {
// Deprecation handler
Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->do_deprecated_action(
'elementor/old/action',
[ $args ],
'3.5.0',
'elementor/new/action'
);
// Run the new hook
do_action( 'elementor/new/action', $args );
}
}
The new elementor/new/action hook will run as expected. In addition, the deprecation handler will run the old hook (for backwards compatibility) while sending some notifications to developers.
After eight major versions, the code will look like this:
class Name {
function init( $args ): void {
do_action( 'elementor/new/action', $args );
}
}
Updating Deprecated Action Hooks
Addon developers who use the old hook should simply rename it, as follows:
function hook_callback() {
/* ... */
}
- add_action( 'elementor/old/action', 'hook_callback' );
+ add_action( 'elementor/new/action', 'hook_callback' );
Deprecated Arguments
Elementor offers the Deprecation::deprecated_argument() method to handle the deprecation process for arguments inside the Elementor code.
Use Cases
As our code improves, some arguments become redundant. The same functionality can be processed by retrieving the data internally, without the need of external arguments.
For example, when registering controls, you no longer need to pass the ID argument as the data comes from the class itself, not from a separate method.
How To Deprecate Arguments
Our class has a register() method. This method used to accept an $id, but now the ID is part of the class and the $id argument will eventually not be supported in the registration process.
For example, take the following code:
class Items_Manager {
private $items;
function register( $instance, $id = null ): void {
$this->items[ $id ] = $instance;
}
}
The original method above required the $id argument - the new method should work with or without this argument.
The new code, with the deprecation handler, will look like this:
use Elementor\Plugin;
class Items_Manager {
private $items;
function register( $instance, $id = null ): void {
if ( $id ) {
// TODO: Remove this in the future.
Plugin::instance()->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_argument(
'$id',
'3.5.0'
);
} else {
// TODO: Leave this in the future.
$id = $instance->get_id();
}
$this->items[ $id ] = $instance;
}
}
The register() method will work with or without the $id argument. In addition, the deprecation handler will sending some notifications to developers still using the deprecated argument.
After eight major versions, the code will look like this:
class Items_Manager {
private $items;
function register( $instance ): void {
$id = $instance->get_id();
$this->items[ $id ] = $instance;
}
}
Updating Deprecated Arguments
Addon developers who use the register() method with the $id argument should simply remove the argument, as follows:
function register_new_items( $items_manager ) {
require_once( __DIR__ . '/items/item-1.php' );
require_once( __DIR__ . '/items/item-2.php' );
- $items_manager->register( new \My_Item_1(), 'item-1' );
- $items_manager->register( new \My_Item_1(), 'item-2' );
+ $items_manager->register( new \My_Item_1() );
+ $items_manager->register( new \My_Item_2() );
}
add_action( 'items/register', 'register_new_items' );
Deprecated Filter Hooks
Elementor offers the Deprecation::apply_deprecated_filter() method to handle the deprecation process for filter hooks inside Elementor code.
Use Cases
When considering naming conventions, the old naming conventions should work alongside the new ones.
How To Deprecate Filter Hooks
We have a filter hook called elementor/old/filter, and we want to rename it to elementor/new/filter.
For example, take the following code:
class Name {
function init( $args ): void {
$value = apply_filters( 'elementor/old/filter', $value, $args );
}
}
The new code, with the deprecation handler, will look like this:
use Elementor\Plugin;
class Name {
function init( $args ): void {
// Deprecation handler
Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->apply_deprecated_filter(
'elementor/old/filter',
[ $args ],
'3.5.0',
'elementor/new/filter'
);
// Run the new filter
$value = apply_filters( 'elementor/new/filter', $value, $args );
}
}
The new elementor/new/filter hook will run as expected. In addition, the deprecation handler will run the old hook (for backwards compatibility) while sending some notifications to developers.
After eight major versions, the code will look like this:
class Name {
function init( $args ): void {
$value = apply_filters( 'elementor/new/filter', $value, $args );
}
}
Updating Deprecated Filter Hooks
Addon developers who use the old hook should simply rename it, as follows:
function hook_callback() {
/* ... */
}
- add_filter( 'elementor/old/filter', 'hook_callback' );
+ add_filter( 'elementor/new/filter', 'hook_callback' );
Deprecated Function
Elementor offers the Deprecation::deprecated_function() method to handle the deprecation process for functions and methods inside Elementor code.
Use Cases
Previously, Elementor protected methods by using the _ prefix. However, this convention is outdated. For instance, _register_controls() would now just be register_controls().
Unifying components is another example of this change. Elementor 3.5 renamed many methods in order to unify the registration process. This entailed using managers, renaming register_widget_type(), register_control(), register_tag(), add_category(), and others to simply register().
How To Deprecate Functions
In the following example we need to rename the add_item() method and replace it with register().
For example, take the following code:
class Items {
function add_item( $item_instance ): void {
/* ... */
}
}
The new code, with the deprecation handler, will look like this:
use Elementor\Plugin;
class Items {
function register( $item_instance ): void {
/* ... */
}
function add_item( $item_instance ): void {
// Deprecation handler
Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function(
'add_item()',
'3.5.0',
'register()'
);
// Backwards compatibility
$this->register( $item_instance );
}
}
The original method was renamed to register(). But, we didn't remove the add_item() method, we simply added a deprecation handler to inform developers still using this method to replace it with the new name.
After eight major versions, the code will look like this:
class Items {
function register( $item_instance ): void {
/* ... */
}
}
Updating Deprecated Functions
Addon developers who use the old add_item() method should simply rename the method to register(), as follows:
class MyItem extends Items {
- protected function add_item(): void {
+ protected function register(): void {
/* ... */
}
}
Elementor 弃用功能
Elementor 是一个不断发展的产品。随着时间的推移,代码会被移除或替换。这些弃用信息会通过各种渠道发布。弃用过程是渐进的,弃用的代码至少经过 8 个主要版本后才会被移除。
Deprecation Process
The reason for this gradual process is to avoid regression errors caused by external addon developers still using deprecated code.
Developers are informed of the code change in the developers blog and an updated list can be found on the recent deprecations page.
Elementor's deprecation process consists of the following steps:
软弃用
此阶段持续四个主要 Elementor 版本。在此宽限期内,已弃用的代码不会破坏网站,因为弃用代码和新代码都将按预期工作。但在此阶段使用已弃用代码将显示浏览器控制台通知。
硬弃用
此阶段将持续四个额外的 Elementor 主要版本。此宽限期不会破坏网站,因为弃用代码和新代码都将按预期工作。然而,在此阶段使用弃用代码将引发 PHP 错误。
删除
经过八个主要版本后,已弃用的代码将从代码库中删除。此时,使用已不存在的代码将引发致命的 PHP 错误,导致网站崩溃。在某些情况下,删除过程可能会推迟到下一个主要版本发布。
Deprecation Period Example
As an example, if code is deprecated in Elementor 3.1.0, it will start throwing PHP errors in Elementor 3.5.0, and will likely be deleted in Elementor 3.9.0.
The old deprecated code will be available until its final deletion. The new replacement code will be available from the deprecation point. Between the deprecated and the deletion, the old code and the new code are both available for use.
调试已弃用代码
插件开发者应在 wp-config.php 文件中将 WP_DEBUG 或 ELEMENTOR_DEBUG 常量设为 true 来测试代码。
启用 WordPress 调试后,软弃用代码会在日志中生成 PHP 通知/警告,硬弃用代码则会在日志中生成 PHP 错误。
Elementor 如何弃用代码
Elementor 3.1 引入了 Deprecation PHP 类来处理上述弃用过程。该类负责处理所有面向开发者的通知,以及(如果需要)所有向后兼容性要求。
Elementor 用于弃用 PHP 代码的主要方法:
deprecated_function()- 处理函数和方法的弃用过程。deprecated_argument()- 处理参数的弃用过程。do_deprecated_action()- 处理动作钩子的弃用过程。apply_deprecated_filter()- 处理过滤器钩子的弃用过程。
Simple Example
One example of commonly used deprecated conventions is when addon developers create widgets using methods with deprecated _ prefix. Previously, Elementor protected methods prefixed with _ but that naming convention was deprecated.
Widgets
Addon developers should update their code, replacing deprecated methods. The fix is very simple, just remove the _ prefixes:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_name(): string {}
public function get_title(): string {}
public function get_icon(): string {}
public function get_categories(): array {}
- protected function _register_controls(): void {}
+ protected function register_controls(): void {}
- protected function _render(): void {}
+ protected function render(): void {}
- protected function _content_template(): void {}
+ protected function content_template(): void {}
}
添加新的动态标签
Elementor 提供了许多开箱即用的内置动态标签,同时也允许外部开发者注册新的标签。
钩子
为此,我们只需挂载到 elementor/dynamic_tags/register 动作,该动作将动态标签管理器作为参数提供。开发者可以使用管理器的 register() 方法,通过动态标签实例来添加新标签。
注册动态标签
使用以下代码注册新的动态标签:
function register_new_dynamic_tags( $dynamic_tags_manager ) {
require_once( __DIR__ . '/dynamic-tags/dynamic-tag-1.php' );
require_once( __DIR__ . '/dynamic-tags/dynamic-tag-2.php' );
$dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_1() );
$dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_2() );
}
add_action( 'elementor/dynamic_tags/register', 'register_new_dynamic_tags' );
管理器通过接受动态标签实例来注册新标签。有关动态标签类的更多信息,请阅读动态标签类结构。
高级示例
这个更高级的示例将包含自定义字段的使用,以及用户可设置字段的控件。该标签将计算这些字段的平均值,并包含一个用户可设置 ACF 字段 ID 的逗号分隔列表的控件。
文件夹结构
该插件将包含两个文件。动态标签及其功能文件。主文件将负责注册标签和标签组。
elementor-acf-average-dynamic-tag/
|
├─ dynamic-tags/
| └─ acf-average-dynamic-tag.php
|
└─ elementor-acf-average-dynamic-tag.php
Plugin Files
elementor-acf-average-dynamic-tag.php
<?php
/**
* Plugin Name: Elementor ACF Average Dynamic Tag
* Description: Add dynamic tag that returns an ACF average.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-acf-average-dynamic-tag
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register New Dynamic Tag Group.
*
* Register new site group for site-related tags.
*
* @since 1.0.0
* @param \Elementor\Core\DynamicTags\Manager $dynamic_tags_manager Elementor dynamic tags manager.
* @return void
*/
function register_site_dynamic_tag_group( $dynamic_tags_manager ) {
$dynamic_tags_manager->register_group(
'site',
[
'title' => esc_html__( 'Site', 'elementor-acf-average-dynamic-tag' )
]
);
}
add_action( 'elementor/dynamic_tags/register', 'register_site_dynamic_tag_group' );
/**
* Register ACF Average Dynamic Tag.
*
* Include dynamic tag file and register tag class.
*
* @since 1.0.0
* @param \Elementor\Core\DynamicTags\Manager $dynamic_tags_manager Elementor dynamic tags manager.
* @return void
*/
function register_acf_average_dynamic_tag( $dynamic_tags_manager ) {
require_once( __DIR__ . '/dynamic-tags/acf-average-dynamic-tag.php' );
$dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_ACF_Average );
}
add_action( 'elementor/dynamic_tags/register', 'register_acf_average_dynamic_tag' );
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Dynamic Tag - ACF Average
*
* Elementor dynamic tag that returns an ACF average.
*
* @since 1.0.0
*/
class Elementor_Dynamic_Tag_ACF_Average extends \Elementor\Core\DynamicTags\Tag {
/**
* Get dynamic tag name.
*
* Retrieve the name of the ACF average tag.
*
* @since 1.0.0
* @access public
* @return string Dynamic tag name.
*/
public function get_name(): string {
return 'acf-average';
}
/**
* Get dynamic tag title.
*
* Returns the title of the ACF average tag.
*
* @since 1.0.0
* @access public
* @return string Dynamic tag title.
*/
public function get_title(): string {
return esc_html__( 'ACF Average', 'elementor-acf-average-dynamic-tag' );
}
/**
* Get dynamic tag groups.
*
* Retrieve the list of groups the ACF average tag belongs to.
*
* @since 1.0.0
* @access public
* @return array Dynamic tag groups.
*/
public function get_group(): array {
return [ 'site' ];
}
/**
* Get dynamic tag categories.
*
* Retrieve the list of categories the ACF average tag belongs to.
*
* @since 1.0.0
* @access public
* @return array Dynamic tag categories.
*/
public function get_categories(): array {
return [ \Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY ];
}
/**
* Register dynamic tag controls.
*
* Add input fields to allow the user to customize the ACF average tag settings.
*
* @since 1.0.0
* @access protected
* @return void
*/
protected function register_controls(): void {
$this->add_control(
'fields',
[
'label' => esc_html__( 'Fields', 'elementor-acf-average-dynamic-tag' ),
'type' => 'text',
]
);
}
/**
* Render tag output on the frontend.
*
* Written in PHP and used to generate the final HTML.
*
* @since 1.0.0
* @access public
* @return void
*/
public function render(): void {
$fields = $this->get_settings( 'fields' );
$sum = 0;
$count = 0;
$value = 0;
// Make sure that ACF if installed and activated
if ( ! function_exists( 'get_field' ) ) {
echo 0;
return;
}
foreach ( explode( ',', $fields ) as $index => $field_name ) {
$field = get_field( $field_name );
if ( (int) $field > 0 ) {
$sum += (int) $field;
$count++;
}
}
if ( 0 !== $count ) {
$value = $sum / $count;
}
echo $value;
}
}
The Result
The dynamic tag in a group view:
The dynamic tag controls:
复杂示例
为展示复杂动态标签,我们将允许用户从可用服务器变量列表中显示服务器变量。它将包含一个自定义的动态标签组,并提供一个包含所有可用服务器变量的选择框控件。渲染函数将返回用户选择的变量及其值。
文件夹结构
该插件将包含两个文件。动态标签及其功能文件。主文件将注册标签和标签组。
elementor-server-variable-dynamic-tag/
|
├─ dynamic-tags/
| └─ server-variable-dynamic-tag.php
|
└─ elementor-server-variable-dynamic-tag.php
Plugin Files
elementor-server-variable-dynamic-tag.php
<?php
/**
* Plugin Name: Elementor Server Variable Dynamic Tag
* Description: Add dynamic tag that returns an server variable.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-server-variable-dynamic-tag
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register Request Variables Dynamic Tag Group.
*
* Register new dynamic tag group for Request Variables.
*
* @since 1.0.0
* @param \Elementor\Core\DynamicTags\Manager $dynamic_tags_manager Elementor dynamic tags manager.
* @return void
*/
function register_request_variables_dynamic_tag_group( $dynamic_tags_manager ) {
$dynamic_tags_manager->register_group(
'request-variables',
[
'title' => esc_html__( 'Request Variables', 'textdomain' )
]
);
}
add_action( 'elementor/dynamic_tags/register', 'register_request_variables_dynamic_tag_group' );
/**
* Register Server Variable Dynamic Tag.
*
* Include dynamic tag file and register tag class.
*
* @since 1.0.0
* @param \Elementor\Core\DynamicTags\Manager $dynamic_tags_manager Elementor dynamic tags manager.
* @return void
*/
function register_server_variable_dynamic_tag( $dynamic_tags_manager ) {
require_once( __DIR__ . '/dynamic-tags/server-variable-dynamic-tag.php' );
$dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_Server_Variable );
}
add_action( 'elementor/dynamic_tags/register', 'register_server_variable_dynamic_tag' );
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Dynamic Tag - Server Variable
*
* Elementor dynamic tag that returns a server variable.
*
* @since 1.0.0
*/
class Elementor_Dynamic_Tag_Server_Variable extends \Elementor\Core\DynamicTags\Tag {
/**
* Get dynamic tag name.
*
* Retrieve the name of the server variable tag.
*
* @since 1.0.0
* @access public
* @return string Dynamic tag name.
*/
public function get_name(): string {
return 'server-variable';
}
/**
* Get dynamic tag title.
*
* Returns the title of the server variable tag.
*
* @since 1.0.0
* @access public
* @return string Dynamic tag title.
*/
public function get_title(): string {
return esc_html__( 'Server Variable', 'textdomain' );
}
/**
* Get dynamic tag groups.
*
* Retrieve the list of groups the server variable tag belongs to.
*
* @since 1.0.0
* @access public
* @return array Dynamic tag groups.
*/
public function get_group(): array {
return [ 'request-variables' ];
}
/**
* 获取动态标签分类。
*
* 检索服务器变量标签所属的分类列表。
*
* @since 1.0.0
* @access public
* @return array 动态标签分类。
*/
public function get_categories(): array {
return [ \Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY ];
}
/**
* 注册动态标签控件。
*
* 添加输入字段,允许用户自定义服务器变量标签设置。
*
* @since 1.0.0
* @access protected
* @return void
*/
protected function register_controls(): void {
$variables = [];
foreach ( array_keys( $_SERVER ) as $variable ) {
$variables[ $variable ] = ucwords( str_replace( '_', ' ', $variable ) );
}
$this->add_control(
'user_selected_variable',
[
'type' => \Elementor\Controls_Manager::SELECT,
'label' => esc_html__( '变量', 'textdomain' ),
'options' => $variables,
]
);
}
/**
* 在前端渲染标签输出。
*
* 用 PHP 编写,用于生成最终的 HTML。
*
* @since 1.0.0
* @access public
* @return void
*/
public function render(): void {
$user_selected_variable = $this->get_settings( 'user_selected_variable' );
if ( ! $user_selected_variable ) {
return;
}
if ( ! isset( $_SERVER[ $user_selected_variable ] ) ) {
return;
}
$value = $_SERVER[ $user_selected_variable ];
echo wp_kses_post( $value );
}
}
The Result
The dynamic tag in a group view:
The dynamic tag controls:
动态标签分类
创建控件时,开发者可以定义控件是否接受动态数据。若控件接受动态数据,则必须设置数据类型(如文本值、颜色、图像)。而动态标签需要定义其向控件返回的数据类型。
这正是分类发挥作用之处。Elementor Pro 提供按数据类型排列的分类列表,动态标签通过这些分类向控件返回数据。
可用分类常量
Elementor Pro 提供以下预定义的动态标签分类常量:
| 常量 | 值 | 说明 |
|---|---|---|
NUMBER_CATEGORY |
number |
用于数字控件的动态标签 |
TEXT_CATEGORY |
text |
用于文本控件的动态标签 |
URL_CATEGORY |
url |
用于 URL 控件的动态标签 |
COLOR_CATEGORY |
color |
用于颜色控件的动态标签 |
IMAGE_CATEGORY |
image |
用于图像控件的动态标签 |
MEDIA_CATEGORY |
media |
用于媒体控件的动态标签 |
GALLERY_CATEGORY |
gallery |
用于图库控件的动态标签 |
POST_META_CATEGORY |
post_meta |
用于文章元数据控件的动态标签 |
::: warning 请注意
在旧版 Elementor 中,您可以将返回值定义为简单文本,如 url、number、text、media 等。随着 Elementor 的发展,它已将这些基于文本的值替换为预定义的大写常量。我们强烈建议您将旧的文本基值替换为新的分类常量。
:::
在动态标签上应用分类
创建新的动态标签时,您需要定义该标签将返回的数据类型。这通过 get_categories() 方法实现:
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
public function get_categories(): array {
return [ \Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY ];
}
}
该方法返回一个数组,意味着动态标签可以向控件返回多种数据类型:
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
public function get_categories(): array {
return [
\Elementor\Modules\DynamicTags\Module::URL_CATEGORY,
\Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY,
\Elementor\Modules\DynamicTags\Module::NUMBER_CATEGORY
];
}
}
在控件中使用动态分类
另一方面,当您创建控件时,需要通过 get_default_settings() 方法在定义控件设置时支持动态标签,并选择要显示的分类:
class Elementor_Test_Control extends \Elementor\Base_Control {
public function get_type(): string {}
public function content_template(): void {}
protected function get_default_settings(): array {
return [
'show_label' => true,
'label_block' => true,
'separator' => 'after',
'dynamic' => [
'active' => true,
'categories' => [
\Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY,
\Elementor\Modules\DynamicTags\Module::NUMBER_CATEGORY
],
],
];
}
}
动态标签控件
简单标签返回没有依赖关系的动态数据,例如随机数。更复杂的标签可能包含可选字段,用户可以在其中配置自定义数据,例如用户可以设置最小值和最大值的随机数。随后,渲染方法将使用这些自定义字段来生成最终输出。
注册控件
要为动态标签设置自定义控件,请使用 register_controls() 方法,如下所示:
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
protected function register_controls(): void {
$this->add_control(
'text_param',
[
'type' => \Elementor\Controls_Manager::TEXT,
'label' => esc_html__( 'Text Param', 'textdomain' ),
'placeholder' => esc_html__( 'Enter your title', 'textdomain' ),
]
);
$this->add_control(
'number_param',
[
'type' => \Elementor\Controls_Manager::NUMBER,
'label' => esc_html__( 'Number Param', 'textdomain' ),
'min' => 0,
'max' => 100,
'step' => 1,
'default' => 50,
]
);
$this->add_control(
'select_param',
[
'type' => \Elementor\Controls_Manager::SELECT,
'label' => esc_html__( 'Select Param', 'textdomain' ),
'options' => [
'default' => esc_html__( 'Default', 'textdomain' ),
'yes' => esc_html__( 'Yes', 'textdomain' ),
'no' => esc_html__( 'No', 'textdomain' ),
],
'default' => 'no',
]
);
}
}
相同的控件机制也用于小部件控件。
动态标签数据
每个动态标签都需要基本信息,例如唯一 ID、标题、组别和类别。
数据方法
动态标签数据通过这些方法"返回":
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
public function get_name(): string {
return 'tag-name';
}
public function get_title(): string {
return esc_html__( 'Dynamic Tag Name', 'textdomain' );
}
public function get_group(): array {
return [ 'group-name' ];
}
public function get_categories(): array {
return [ \Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY ];
}
}
-
动态标签名称 -
get_name()方法返回一个在代码中使用的唯一 ID。 -
动态标签标题 –
get_title()方法返回向用户显示的标签标签。 -
动态标签组别 –
get_group()方法返回标签将出现在其下的组别数组。 -
动态标签类别 –
get_categories()方法返回标签所属的控制类别数组。
Dynamic Tags Groups
Available Groups
Elementor Pro adds the following groups:
If you would like to use the groups added by Elementor Pro, your addons must make sure Elementor Pro was loaded.
Applying Groups
When creating new dynamic tags, you can set the tag group by returning group names with the get_group() method:
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
public function get_group(): array {
return [ 'action' ];
}
}
Creating New Groups
Elementor Pro’s dynamic tags manager lets external developers create custom groups using the elementor/dynamic_tags/register_tags action hook:
/**
* Register new dynamic tag group
*
* @since 1.0.0
* @param \Elementor\Core\DynamicTags\Manager $dynamic_tags_manager Elementor dynamic tags manager.
* @return void
*/
function register_new_dynamic_tag_group( $dynamic_tags_manager ) {
$dynamic_tags_manager->register_group(
'group-name',
[
'title' => esc_html__( 'Group Label', 'textdomain' )
]
);
}
add_action( 'elementor/dynamic_tags/register', 'register_new_dynamic_tag_group' );
动态标签渲染
render 方法生成最终输出并将数据回显到控件。如果动态标签有控件,渲染函数应在生成输出时使用这些数据。
渲染方法
要渲染动态标签输出并回显数据,我们使用 render() 方法,如下所示:
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
public function render(): void {
echo rand();
}
}
要从动态标签控件中提取数据,我们可以使用 get_settings() 方法:
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
public function render(): void {
$param1 = $this->get_settings( 'text_param' );
$param2 = $this->get_settings( 'number_param' );
$param3 = $this->get_settings( 'select_param' );
echo "{$param1} {$param2} {$param3}";
}
}
动态标签结构
每个动态标签都需要具备一些基本设置,例如唯一的名称。除此之外,还有一些高级设置,如动态标签控件,这些基本上是可选字段,用户可以在其中配置自定义数据。还有一个渲染方法,它根据从动态标签控件获取的用户设置生成最终输出。
扩展动态标签
要创建自己的控件,您需要扩展动态标签控件以继承其方法:
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
}
动态标签方法
一个简单的动态标签骨架如下所示:
class Elementor_Test_Tag extends \Elementor\Core\DynamicTags\Tag {
public function get_name(): string {}
public function get_title(): string {}
public function get_group(): array {}
public function get_categories(): array {}
protected function register_controls(): void {}
public function render(): void {}
}
动态标签方法可以分为以下几组:
请注意,\Elementor\Core\DynamicTags\Tag 类还有许多其他方法,但上述方法将满足您的绝大部分需求。
Dynamic Tags
For example, Elementor Pro allows you to add dynamic data based on the page and site parameters, this includes data such as; Post Title, Post Excerpt, Author Info, Site Name, Site Logo, and much more.
Addon developers can create a wide range of dynamic tags, and can even use external APIs to pull data to Elementor.
How it Works
You could say that dynamic tags are like functions, the user can define custom parameters to change the output based on different factors.
Elementor Pro
Managing Dynamic Tags
External developers can register new dynamic tags and unregister existing ones. Learn more how to do that:
Creating Dynamic Tags
Learn more about the anatomy of dynamic tags and how to create your own:
Code Examples
Check out how easy it is to create new dynamic tags:
移除动态标签
要移除现有的动态标签,开发者只需通过传递动态标签名称来注销现有标签。
钩子
为此,我们需要挂载到包含动态标签管理器的 elementor/dynamic_tags/register 动作,并将动态标签名称传递给 unregister() 方法。
注销动态标签
要注销现有的动态标签,请使用以下代码:
function unregister_dynamic_tags( $dynamic_tags_manager ) {
$dynamic_tags_manager->unregister( 'dynamic-tag-1' );
$dynamic_tags_manager->unregister( 'dynamic-tag-2' );
}
add_action( 'elementor/dynamic_tags/register', 'unregister_dynamic_tags' );
简单示例
总而言之,我们将创建一个返回随机数的简单动态标签。为简化示例,此动态标签不包含控件。但您可以扩展代码,添加最小值和最大值的限制控件。
文件夹结构
该插件将包含两个文件。动态标签及其功能文件,主文件将用于注册标签。
elementor-random-number-dynamic-tag/
|
├─ dynamic-tags/
| └─ random-number-dynamic-tag.php
|
└─ elementor-random-number-dynamic-tag.php
Plugin Files
elementor-random-number-dynamic-tag.php
<?php
/**
* Plugin Name: Elementor Random Number Dynamic Tag
* Description: Add dynamic tag that returns a random number.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-random-number-dynamic-tag
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register Random Number Dynamic Tag.
*
* Include dynamic tag file and register tag class.
*
* @since 1.0.0
* @param \Elementor\Core\DynamicTags\Manager $dynamic_tags_manager Elementor dynamic tags manager.
* @return void
*/
function register_random_number_dynamic_tag( $dynamic_tags_manager ) {
require_once( __DIR__ . '/dynamic-tags/random-number-dynamic-tag.php' );
$dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_Random_Number );
}
add_action( 'elementor/dynamic_tags/register', 'register_random_number_dynamic_tag' );
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Dynamic Tag - Random Number
*
* Elementor dynamic tag that returns a random number.
*
* @since 1.0.0
*/
class Elementor_Dynamic_Tag_Random_Number extends \Elementor\Core\DynamicTags\Tag {
/**
* Get dynamic tag name.
*
* Retrieve the name of the random number tag.
*
* @since 1.0.0
* @access public
* @return string Dynamic tag name.
*/
public function get_name(): string {
return 'random-number';
}
/**
* Get dynamic tag title.
*
* Returns the title of the random number tag.
*
* @since 1.0.0
* @access public
* @return string Dynamic tag title.
*/
public function get_title(): string {
return esc_html__( 'Random Number', 'elementor-random-number-dynamic-tag' );
}
/**
* Get dynamic tag groups.
*
* Retrieve the list of groups the random number tag belongs to.
*
* @since 1.0.0
* @access public
* @return array Dynamic tag groups.
*/
public function get_group(): array {
return [ 'actions' ];
}
/**
* Get dynamic tag categories.
*
* Retrieve the list of categories the random number tag belongs to.
*
* @since 1.0.0
* @access public
* @return array Dynamic tag categories.
*/
public function get_categories(): array {
return [ \Elementor\Modules\DynamicTags\Module::NUMBER_CATEGORY ];
}
/**
* Render tag output on the frontend.
*
* Written in PHP and used to generate the final HTML.
*
* @since 1.0.0
* @access public
* @return void
*/
public function render(): void {
echo rand();
}
}
默认面板
默认情况下,当编辑器首次加载时,Elementor 会显示小部件面板。您可以更改此设置。
更改默认面板
使用以下代码将页面设置面板设为默认面板:
function change_default_elementor_panel( $config ) {
$config = array_replace_recursive(
$config,
[
'panel' => [
'default_route' => 'panel/page-settings/settings'
]
]
);
return $config;
}
add_filter( 'elementor/document/config', 'change_default_elementor_panel' );
可用面板
以下是您可以用作默认面板的内置面板的部分列表:
Elementor 面板
面板就像一个编辑仪表盘。这是用户可以控制页面所有方面的区域。它包括全局设置、页面设置、小部件面板等。
Elementor 面板
面板区域由多个面板组成:
扩展面板
其中一些面板是可扩展的。开发者可以向现有面板添加新元素,并且我们正在开发一种创建新面板的官方方法,以替代目前一些插件作者使用的变通方案。
Elementor 预览
预览区域用于显示当前正在编辑页面的实时预览。它由 JavaScript 引擎渲染,通常无需从服务器端加载。换句话说,这是您可以看到网站最终呈现效果的区域。
扩展预览功能
预览区域是编辑器的一部分。这意味着它继承了部分编辑功能,允许用户控制外观样式。开发者可以利用这些功能来扩展预览区域。例如:
- 内联编辑 - 开发 Elementor 小部件 时,可使元素在预览中直接编辑
- 上下文菜单 - 在预览中右键点击元素时,可在上下文弹出窗口中添加操作链接
- 编辑按钮 - 在预览中悬停元素时,可添加新的编辑按钮
Elementor 选项卡
在某些面板中,Elementor 使用选项卡导航来显示控件。扩展 Elementor 时,您可以使用任何所需的选项卡,或创建新的选项卡。
Built-in Tabs
Elementor has 6 pre-defined tabs used in different panels:
| Name/ID | Label | Constant |
|---|---|---|
content |
Content | \Elementor\Controls_Manager::TAB_CONTENT |
style |
Style | \Elementor\Controls_Manager::TAB_STYLE |
advanced |
Advanced | \Elementor\Controls_Manager::TAB_ADVANCED |
responsive |
Responsive | \Elementor\Controls_Manager::TAB_RESPONSIVE |
layout |
Layout | \Elementor\Controls_Manager::TAB_LAYOUT |
settings |
Settings | \Elementor\Controls_Manager::TAB_SETTINGS |
The tabs are set in the \Elementor\Controls_Manager class. They are defined as constants and registered using the init_tabs() method; each constant contains the tab name and label.
使用示例
例如,小部件面板在内容选项卡中显示控件,允许用户设置小部件内容,并在样式选项卡中设计内容。此外,Elementor 为所有小部件添加了一个高级选项卡。
另一方面,页面设置面板根据具体设置,在设置选项卡、样式选项卡、布局选项卡等中显示控件。
使用选项卡
当我们在元素面板中添加新控件时,会使用继承的 add_control() 方法。在添加新控件之前,我们需要使用 start_controls_section() 方法创建一个新部分。我们使用此方法来定义选项卡:
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( '样式部分', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
添加新标签页
要创建自定义标签页,请使用 add_tab() 方法:
function add_panel_tab() {
\Elementor\Controls_Manager::add_tab(
'new-tab',
esc_html__( 'New Tab', 'textdomain' )
);
}
add_action( 'elementor/init', 'add_panel_tab' );
若要在标签页标签上方添加自定义图标,您需要添加自定义 CSS:
.elementor-panel .elementor-tab-control-new-tab a:before,
.elementor-panel .elementor-tab-control-new-tab span:before {
font-family: eicons;
content: '\e942';
}
最佳实践
::: warning 官方指南 Elementor 官方指南强烈建议使用默认标签页之一。 :::
尽管如此,此功能仍被记录在案,因为部分插件作者会使用代码变通方案,这些方案会降低编辑器速度,并在某些极端情况下导致其崩溃。
历史面板
历史是编辑器中的一个面板,允许用户查看其最新操作和修订版本。此面板让用户可以撤销/重做操作,并恢复页面的先前版本。
结构与功能
该面板包含两个选项卡:
- 修订版本 - 保存在数据库中的页面版本。
- 操作 - 自上次保存页面以来所做的页面更改。
修订版本是 WordPress 的功能,Elementor 只是让恢复 WordPress 数据库中已保存的不同修订版本变得更加容易。
另一方面,操作是用户在 Elementor 内部所做的更改。该面板可以轻松显示更改并撤销/重做这些更改。
Elementor 编辑器
编辑器是用户创建页面和控制网站设置的环境。编辑器是一个通用术语,包含两个主要区域——预览区和面板区。每个区域都包含可由第三方开发者扩展的内部区域。
结构
编辑器指整个编辑屏幕,由两个主要区域组成:
编辑器面板
面板区域显示各种控件和设置。显示的控件和功能取决于当前显示的具体面板:
菜单面板
菜单面板是编辑器中的主面板。用户可由此导航至其他面板。换言之,它充当着其他 Elementor 面板的仪表板。
结构与功能
该面板包含两个部分:
- 设置 - 链接至控制设置的其他面板。
- 页面导航 - 链接至外部链接和工具。
扩展菜单面板
开发者可以向菜单面板添加新链接。为保持一致性,这些链接应打开其他 Elementor 面板。
页面设置面板
页面设置是编辑器中的一个面板,用户可以在其中更改文章/页面的字段,例如标题、摘要(如果文章类型支持摘要)、特色图像、文章状态等。
页面设置基于文章/页面,这意味着网站上的每个文章/页面都有其独特的设置,这些设置保存在数据库的 wp_posts 表中。
结构与功能
该面板包含三个标签页:
- 设置 - 管理常规页面设置。
- 样式 - 管理页面样式。
- 高级 - 管理其他页面设置。
设置面板相当于 Elementor 中的 WordPress 文章/页面编辑界面。您可以在此设置页面标题、摘要、特色图像等。
样式设置用于在页面级别添加新样式,这与控制全站样式的站点设置不同。例如,用户可以更改页面背景颜色/图像,覆盖站点背景样式。
在高级标签页中,用户可以添加仅在此页面加载的自定义 CSS。
检索已保存的数据
设置选项卡中的数据是常规的 WordPress 页面/文章数据,可以使用常规的主题函数进行检索。
// 检索页面数据
$page_id = get_the_ID();
$page_title = get_the_title();
$page_excerpt = get_the_excerpt();
$page_author = get_the_author();
$page_permalink = get_permalink();
$page_thumbnail = get_the_post_thumbnail();
样式选项卡中的数据保存在页面的 post meta 中。这个 post meta 包含了与文档设置相关的大部分设置(不包括一些需要特殊处理的设置)。
// 检索页面设置管理器
$page_settings_manager = \Elementor\Core\Settings\Manager::get_settings_managers( 'page' );
// 检索当前页面的设置模型
$page_settings_model = $page_settings_manager->get_model( $page_id );
// 从自定义控件检索数据
$test_color = $page_settings_model->get_settings( 'test_color' );
echo $test_color; // 可能的输出: '#9b0a46'
Adding New Settings
Developers can add new controls to this panel. This is done by injecting controls into page settings.
Below is an example how we can add color control to the style tab:
/**
* Register additional document controls.
*
* @param \Elementor\Core\DocumentTypes\PageBase $document The PageBase document instance.
*/
function register_document_controls( $document ) {
if ( ! $document instanceof \Elementor\Core\DocumentTypes\PageBase || ! $document::get_property( 'has_elements' ) ) {
return;
}
$document->start_controls_section(
'test_section',
[
'label' => esc_html__( 'Test Section', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$document->add_control(
'test_color',
[
'label' => esc_html__( 'Test Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}}' => 'background-color: {{VALUE}}',
],
]
);
$document->end_controls_section();
}
add_action( 'elementor/documents/register_controls', 'register_document_controls' );
In the page settings scope, the { { WRAPPER } } placeholder represents a unique class of the <body> element.
站点设置面板
站点设置是编辑器中的一个面板,用户可以在其中全局定义站点设置。这包括全局颜色、排版、站点标识等。
结构与功能
该面板包含三个部分:
- 设计系统 - 定义全局颜色和字体,以确保设计一致性。
- 主题样式 - 由主题处理的全局设计层。
- 设置
设计系统允许用户创建自定义配色方案和排版,以便在不同的部件中使用。它使用户能够创建统一的设计,并轻松更改整个站点的方案。
主题样式是常规的主题设置,为各种 HTML 元素创建预设的回退样式。如果未为特定部件设置定义,则使用主题样式。
设置部分允许您设置站点标识、布局、断点、自定义 CSS 等。
User Preferences Panel
User Preferences is a panel in the editor where the user can control the editor's look and feel. Users can choose whether to display a light or a dark theme, set the default panel width, decide to show/hide editing buttons, etc.
These preferences are user-based, meaning that different users can set different preferences for themselves. This data is saved in the wp_users table in the database.
Structure and Functionality
Currently, the panel has only section:
- Preferences - manages the look and feel of the editor.
Extending the Panel
Developers can extend the user preferences panel by injecting new controls to the panel. Make sure to only add controls that manage how your addon is displayed in the Editor.
Adding New Preferences
Developers can add new controls to this panel. This is done by injecting controls.
In the example below, we'll add a new control:
/**
* @param \Elementor\Core\Settings\EditorPreferences\Model $preferences The editor preferences model.
*/
function add_preferences_controls( \Elementor\PageSettings\Page $page ) {
$this->add_control(
'something',
[
'label' => esc_html__( 'Enable Something', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SWITCHER,
'default' => 'yes',
]
);
}
add_action( 'elementor/element/editor-preferences/preferences/before_section_end', 'add_preferences_controls' );
Retrieving Saved Data
The data in the preferences panel is saved in the user's metadata. The user's metadata contains all the settings related to their editor preferences.
Below is an example of how we can retrieve this data:
$something = get_user_meta( get_current_user_id(), 'something', true );
小部件面板
小部件 是 编辑器 中的入口面板(用户看到的第一个面板)。用户可以从此处将小部件拖放到 预览 区域。
结构与功能
该面板有两个选项卡:
- 元素 - 已注册小部件的列表。
- 全局 - 用户保存的全局小部件列表。
元素选项卡按类别分组显示网站的小部件。它还有一个搜索栏,可用于筛选小部件。
全局选项卡显示所有已保存的小部件及其设置和设计。全局小部件可在多个区域和多个页面上使用。更改全局小部件会影响所有页面上该小部件的所有实例。
扩展小部件面板
Elementor 开箱即用提供了数十个小部件。尽管如此,外部开发者可以 创建新的小部件,甚至可以将它们组织到自己的品牌 小部件类别 中。
AI
Elementor 已在众多控件中集成了 AI 功能,旨在赋能用户通过生成原创或增强的文本以及自定义代码(HTML 和 CSS)来提升其网站品质,从而帮助网页创作者提高工作效率。插件开发者可以选择启用或禁用 AI 按钮。若启用,他们可以控制 AI 功能。
AI 功能
Elementor 的 AI 解决方案允许用户在编辑体验中生成新内容或更新现有内容。点击 AI 按钮将显示一个新对话框,用户可输入提示词来创建 AI 生成的内容。随后,用户可选择将内容添加到应用了 AI 的控件中,或对其进行调整,例如加长、缩短、改变语气等。
支持的控件
并非所有编辑器控件都支持 AI 功能,例如切换器控件和选择控件就没有 AI 按钮。但基于文本的控件、代码控件和媒体控件都新增了 AI 按钮。
以下控件默认带有 AI 按钮:
在某些情况下,您可能不希望支持的控件上显示 AI 按钮,可以选择禁用 AI 按钮。例如,在允许用户设置元素 ID 的文本控件上添加 AI 按钮就没有意义。您可以禁用 AI 按钮。
也可能存在相反的情况:控件默认没有 AI 按钮,但您希望添加一个。例如,当创建新的 Elementor 控件时,如果自定义功能包含文本区域,并且您希望允许网站创建者插入 AI 生成的内容,您可以添加 AI 按钮。
此外,每种控件类型会触发不同的提示选项和建议。文本控件主要用于生成短标题或较长段落,代码建议用于生成 HTML 和 CSS 代码,而媒体控件则用于生成图像。
AI Argument
To manage AI capabilities for Elementor controls, use the ai argument. It’s an array that accepts the following options:
| Name | Description |
|---|---|
active |
(boolean) Whether to display the AI button to the control, or not. |
type |
(string) The type of the control and the AI prompt options. Available values are: text, textarea, code and media. |
language |
(string) Override code control language. Available values are: html and css. |
使用方法
让我们通过几个实际示例,了解如何使用 Elementor AI 按钮来增强编辑器控件。
使用 AI 撰写
基于文本控件的 AI 功能:
// 带有 AI 按钮的文本控件,用于生成短文本
$this->add_control(
'title',
[
'label' => esc_html__( '标题', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
]
);
// 带有 AI 按钮的文本区域控件,用于生成段落
$this->add_control(
'description',
[
'label' => esc_html__( '描述', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXTAREA,
]
);
// 带有 AI 按钮的 WYSIWYG 控件,用于生成段落
$this->add_control(
'content',
[
'label' => esc_html__( '内容', 'textdomain' ),
'type' => \Elementor\Controls_Manager::WYSIWYG,
]
);
// 带有 AI 按钮的文本区域控件,用于生成短文本
$this->add_control(
'subheading',
[
'label' => esc_html__( '副标题', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXTAREA,
'ai' => [
'type' => 'text',
],
]
);
// 不带 AI 按钮的文本控件
$this->add_control(
'title-id',
[
'label' => esc_html__( '标题 ID', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'ai' => [
'active' => false,
],
]
);
// 为自定义控件添加 AI 按钮
$this->add_control(
'unique-control-name',
[
'label' => esc_html__( '自定义元素', 'textdomain' ),
'type' => \My_Addon::CUSTUM_TEXT_CONTROL,
'ai' => [
'active' => true,
'type' => 'text',
],
]
);
Code with AI
AI capabilities that generates custom code:
// Code control with an AI button that generates CSS
$this->add_control(
'custom-css',
[
'label' => esc_html__( 'Custom CSS', 'textdomain' ),
'type' => \Elementor\Controls_Manager::CODE,
'language' => 'css',
]
);
// Code control with an AI button that generates HTML
$this->add_control(
'custom-html',
[
'label' => esc_html__( 'Custom HTML', 'textdomain' ),
'type' => \Elementor\Controls_Manager::CODE,
'language' => 'html',
]
);
// Code control without an AI button
$this->add_control(
'css',
[
'label' => esc_html__( 'CSS', 'textdomain' ),
'type' => \Elementor\Controls_Manager::CODE,
'language' => 'css',
'ai' => [
'active' => false,
],
]
);
// Override control language for AI
$this->add_control(
'html',
[
'label' => esc_html__( 'HTML', 'textdomain' ),
'type' => \Elementor\Controls_Manager::CODE,
'language' => 'html',
'ai' => [
'language' => 'css',
],
]
);
Create with AI
AI capabilities on media controls:
// Media control without an AI button
$this->add_control(
'background-image',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'ai' => [
'active' => true,
],
]
);
// Media control with an AI button that generates background images
$this->add_control(
'background-image',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'dynamic' => [
'active' => true,
],
'ai' => [
'category' => 'background',
],
]
);
// Media control with an AI button that generates 3D images
$this->add_control(
'3d-cover-image',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'dynamic' => [
'active' => true,
],
'ai' => [
'category' => '3d',
],
]
);
// Media control with an AI button that generates photographic images
$this->add_control(
'photo',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'dynamic' => [
'active' => true,
],
'ai' => [
'category' => 'photographic',
],
]
);
// Media control with an AI button that generates handmade images
$this->add_control(
'drawings',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'dynamic' => [
'active' => true,
],
'ai' => [
'category' => 'handmade',
],
]
);
// Media control with an AI button that generates digital art
$this->add_control(
'art-image',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'dynamic' => [
'active' => true,
],
'ai' => [
'category' => 'digital-art',
],
]
);
Note: Non-image media types won't display the AI button as they are not supported.
条件显示
在某些情况下,您可能需要根据用户在依赖控件中的选择来显示控件。例如,开启切换控件可能会触发其他控件的显示。编辑器中的控件机制具有特殊的条件显示功能。让我们看看如何使用它。
条件参数
要为 Elementor 控件设置条件显示,可在任何控件中使用 condition 参数。
单值条件
显示条件可能依赖于一个精确值:
$this->add_control(
'unique-control-name',
[
'label' => esc_html__( 'Control Label', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'condition' => [
'dependent-control-name' => 'exact-value',
],
]
);
多值条件
显示条件可能依赖于一组值:
$this->add_control(
'unique-control-name',
[
'label' => esc_html__( 'Control Label', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'condition' => [
'dependent-control-name' => [ 'value-1', 'value-2' ],
],
]
);
当传递一个值数组时,Elementor 使用逻辑 OR (||) 运算符。
多条件控制
显示条件可能依赖于多个控件。这就是为什么 condition 参数接受一个 array。它使用逻辑 AND (&&) 运算符,检查是否满足所有条件,以决定是否显示该控件。
要设置多个条件,请传递多个值:
$this->add_control(
'unique-control-name',
[
'label' => esc_html__( 'Control Label', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'condition' => [
'dependent-control-1-name' => 'dependent-control-1-value',
'dependent-control-2-name' => 'dependent-control-2-value',
'dependent-control-3-name' => 'dependent-control-3-value',
],
]
);
相等运算符
条件语句包含两个相等运算符,可用于检查控制值是否等于或不等于某个值。
相等检查
仅当依赖控件等于特定值时显示控件:
'condition' => [
'control-name' => 'control-value',
],
不等条件检查
仅当依赖控件不等于特定值时显示控件:
'condition' => [
'control-name!' => 'control-value',
],
我们只需在控件名称后添加 ! 后缀。
条件示例
让我们从一个示例开始,在这个示例中,我们希望允许用户设置边框并为其设置样式。为了简化用户体验,我们最初隐藏所有边框控件,只保留一个切换器。如果用户打开切换器,他们将看到所有边框控件。
$this->add_control(
'border',
[
'label' => esc_html__( 'Border', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SWITCHER,
]
);
$this->add_control(
'border_style',
[
'label' => esc_html__( 'Border Style', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'' => esc_html__( 'None', 'textdomain' ),
'solid' => esc_html__( 'Solid', 'textdomain' ),
'double' => esc_html__( 'Double', 'textdomain' ),
'dotted' => esc_html__( 'Dotted', 'textdomain' ),
'dashed' => esc_html__( 'Dashed', 'textdomain' ),
'groove' => esc_html__( 'Groove', 'textdomain' ),
],
'selectors' => [
'{{WRAPPER}} .inner_class' => 'border-style: {{VALUE}}',
],
'condition' => [
'border' => 'yes',
],
]
);
$this->add_control(
'border_color',
[
'label' => esc_html__( 'Border Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'default' => '',
'selectors' => [
'{{WRAPPER}} .inner_class' => 'border-color: {{VALUE}}',
],
'condition' => [
'border' => 'yes',
],
]
);
$this->add_responsive_control(
'border_width',
[
'label' => esc_html__( 'Border Width', 'textdomain' ),
'type' => \Elementor\Controls_Manager::DIMENSIONS,
'selectors' => [
'{{WRAPPER}} .inner_class' => 'border-width: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
],
'condition' => [
'border' => 'yes',
],
]
);
在上面的示例中,所有边框控件都依赖于单个边框控件。要设置多个依赖控件,我们可以设置更多条件,允许用户添加更多输入。
在下面的示例中,用户需要先打开切换器并设置边框样式。只有这样,颜色和宽度控件才会出现。为此,我们需要使用相等和不相等检查来设置多个条件。
$this->add_control(
'border',
[
'label' => esc_html__( 'Border', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SWITCHER,
]
);
$this->add_control(
'border_style',
[
'label' => esc_html__( 'Border Style', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'' => esc_html__( 'None', 'textdomain' ),
'solid' => esc_html__( 'Solid', 'textdomain' ),
'double' => esc_html__( 'Double', 'textdomain' ),
'dotted' => esc_html__( 'Dotted', 'textdomain' ),
'dashed' => esc_html__( 'Dashed', 'textdomain' ),
'groove' => esc_html__( 'Groove', 'textdomain' ),
],
'selectors' => [
'{{WRAPPER}} .inner_class' => 'border-style: {{VALUE}}',
],
'condition' => [
'border' => 'yes',
],
]
);
$this->add_control(
'border_color',
[
'label' => esc_html__( '边框颜色', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'default' => '',
'selectors' => [
'{{WRAPPER}} .inner_class' => 'border-color: {{VALUE}}',
],
'condition' => [
'border' => 'yes',
'border_style!' => '',
],
]
);
$this->add_responsive_control(
'border_width',
[
'label' => esc_html__( '边框宽度', 'textdomain' ),
'type' => \Elementor\Controls_Manager::DIMENSIONS,
'selectors' => [
'{{WRAPPER}} .inner_class' => 'border-width: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
],
'condition' => [
'border' => 'yes',
'border_style!' => '',
],
]
);
## 高级条件
Elementor 为编辑器中的控件提供了高级条件显示功能。请使用带 **s** 的 `conditions` 参数(而非 `condition` 参数)。
### 可用值
`conditions` 参数接受一个包含以下值的数组:
<table>
<thead>
<tr>
<th>名称</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<th><code>relation</code></th>
<td>(<code>string</code>) 使用 <code>and</code> / <code>or</code> 逻辑运算符进行关系检查。<br> 默认值为 <code>and</code>。</td>
</tr>
<tr>
<th><code>terms</code></th>
<td>(<code>array</code>) 一个包含规则的数组的数组。
<ul>
<li><code>name</code> - 依赖控件的名称。</li>
<li><code>value</code> - 依赖控件的值。</li>
<li><code>operator</code> - 相等运算符,包括 <code>==</code>, <code>!=</code>, <code>!==</code>, <code>in</code>, <code>!in</code>, <code>contains</code>, <code>!contains</code>, <code><</code>, <code><=</code>, <code>></code>, <code>>=</code>, <code>===</code>。默认值为 <code>===</code>。</li>
</ul>
</td>
</tr>
</tbody>
</table>
### More Operators
Before implementing the 'conditions' argument, you could only use equality and inequality checks. Now you have many more operators at your disposal: `==`, `!=`, `!==`, `in`, `!in`, `contains`, `!contains`, `<`, `<=`, `>`, `>=` and `===`.
We can replace the simple `condition` argument:
```php
'condition' => [
'control-name!' => 'control-value',
],
with the advanced conditions argument, and include the operator rule inside the term array:
'conditions' => [
'terms' => [
[
'name' => 'control-name',
'operator' => '!==',
'value' => 'control-value',
],
],
],
This also makes it easier to use equality operators for numeric values (<, <=, >, >=, ==, ===, != and !==):
'conditions' => [
'terms' => [
[
'name' => 'spacing',
'operator' => '>=',
'value' => 0,
],
],
],
Below is an example of checking against multiple values:
'conditions' => [
'terms' => [
[
'name' => 'background_type',
'operator' => 'in',
'value' => [ 'classic', 'gradient', 'video', 'slideshow' ],
],
],
],
Below is an example of checking if the term contains a value:
'conditions' => [
'terms' => [
[
'name' => 'heading',
'operator' => 'contains',
'value' => 'elementor',
],
],
],
多条件设置
如上所述,简单的 condition 参数允许开发者组合多个条件:
'condition' => [
'border' => 'yes',
'border_style!' => '',
],
高级的 conditions 参数也具备相同能力:
'conditions' => [
'terms' => [
[
'name' => 'border',
'operator' => '===',
'value' => 'yes',
],
[
'name' => 'border_style',
'operator' => '!==',
'value' => '',
],
],
],
但使用 condition 参数时,必须满足所有条件才会显示控件;而高级的 conditions 参数则允许您通过新增的 relation 值来添加更多逻辑运算符。
条件关系
现在我们可以使用 and 逻辑运算符以及 or 运算符来检查条件之间的关系:
'conditions' => [
'relation' => 'or',
'terms' => [
[
'name' => 'background',
'operator' => '!==',
'value' => '',
],
[
'name' => 'border',
'operator' => '!==',
'value' => '',
],
],
],
嵌套条件
我们还可以嵌套条件:
'conditions' => [
'relation' => 'or',
'terms' => [
[
'name' => 'video_type',
'operator' => '===',
'value' => 'youtube',
],
[
'relation' => 'and',
'terms' => [
[
'name' => 'show_image_overlay',
'operator' => '===',
'value' => 'yes',
],
[
'name' => 'video_type',
'operator' => '!==',
'value' => 'hosted',
],
],
],
],
],
这一切使开发者能够创建具有许多嵌套级别的非常严格的规则,用于条件控制显示。
重复器与条件显示
条件控制显示和重复器属于特殊情况。有些操作可以实现,有些则不能。我们来探讨三种使用场景。
整个重复器控件
您可以有条件地隐藏/显示整个重复器:
$this->add_control(
'display_list',
[
'label' => esc_html__( 'Display List', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SWITCHER,
'label_on' => esc_html__( 'Yes', 'textdomain' ),
'label_off' => esc_html__( 'No', 'textdomain' ),
'return_value' => 'yes',
'default' => 'yes',
]
);
$this->add_control(
'list',
[
'label' => esc_html__( 'Repeater List', 'textdomain' ),
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => [
[
'name' => 'list_title',
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
],
[
'name' => 'list_content',
'label' => esc_html__( 'Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::WYSIWYG,
],
],
'condition' => [
'display_list' => 'yes',
],
]
);
在这种情况下有两个控件,第一个控件的值会影响第二个控件的显示。
中继器内部字段
您可以根据条件隐藏/显示中继器内部的字段:
$this->add_control(
'list',
[
'label' => esc_html__( 'Repeater List', 'textdomain' ),
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => [
[
'name' => 'display_content',
'label' => esc_html__( 'Display Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SWITCHER,
'label_on' => esc_html__( 'Yes', 'textdomain' ),
'label_off' => esc_html__( 'No', 'textdomain' ),
'return_value' => 'yes',
'default' => 'yes',
],
[
'name' => 'list_title',
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
],
[
'name' => 'list_content',
'label' => esc_html__( 'Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::WYSIWYG,
'condition' => [
'display_content' => 'yes',
],
],
],
]
);
在此示例中,我们有一个包含三个内部控件的中继器,其中一个内部控件的值会影响另一个内部控件的显示。
不同层级的依赖关系
但是你不能混合不同的层级。内部控件不能依赖于主控件的值。
$this->add_control(
'display_content',
[
'label' => esc_html__( 'Display Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SWITCHER,
'label_on' => esc_html__( 'Yes', 'textdomain' ),
'label_off' => esc_html__( 'No', 'textdomain' ),
'return_value' => 'yes',
'default' => 'yes',
]
);
$this->add_control(
'list',
[
'label' => esc_html__( 'Repeater List', 'textdomain' ),
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => [
[
'name' => 'list_title',
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
],
[
'name' => 'list_content',
'label' => esc_html__( 'Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::WYSIWYG,
'condition' => [
'display_content' => 'yes',
],
],
],
]
);
这是不允许的。它不会生效。
警告控制
Elementor 警告控制根据消息的严重程度,在面板中显示四种类型的警告:信息、成功、警告和危险。
该控件在继承 Base_UI_Control 类的 Control_Alert 类中定义。
使用此控件时,type 应设置为 \Elementor\Controls_Manager::ALERT 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
alert | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
alert_type |
string |
info | 警告的类型。可用值为 info、success、warning 和 danger。 |
heading |
string |
显示在警告上方的标题。 | |
content |
string |
警告的内容。 |
返回值
此控件不返回任何值。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'custom_panel_alert',
[
'type' => \Elementor\Controls_Manager::ALERT,
'alert_type' => 'warning',
'heading' => esc_html__( 'Custom Alert', 'textdomain' ),
'content' => esc_html__( 'Lorem ipsum dolor sit amet consectetur adipisicing elit.', 'textdomain' ) . ' <a href="">' . esc_html__( 'Learn more', 'textdomain' ) . '</a>',
]
);
$this->end_controls_section();
}
}
入场动画控制
Elementor 入场动画控制基于 Animate.css 库显示一个选择框字段。该控件允许为项目设置入场动画效果。
此控件在继承 Base_Data_Control 类的 Control_Animation 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::ANIMATION 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
animation | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
default |
string |
字段的默认值。 |
Return Value
(string) The selected entrance animation class.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'entrance_animation',
[
'label' => esc_html__( 'Entrance Animation', 'textdomain' ),
'type' => \Elementor\Controls_Manager::ANIMATION,
'prefix_class' => 'animated ',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="<?php echo esc_attr( $settings['entrance_animation'] ); ?>">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="{{ settings.entrance_animation }}">
...
</div>
<?php
}
}
盒阴影控制
Elementor 盒阴影控制显示用于水平阴影、垂直阴影、阴影模糊、阴影扩散和阴影颜色的输入字段。
该控件在继承 Control_Base_Multiple 类的 Control_Box_Shadow 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::BOX_SHADOW 常量。
参数
返回值
[
'horizontal' => 0,
'vertical' => 0,
'blur' => 10,
'spread' => 0,
'color' => 'rgba(0,0,0,0.5)',
]
(array) 包含盒阴影数据的数组:
- $horizontal (
int) 盒阴影水平尺寸。 - $vertical (
int) 盒阴影垂直尺寸。 - $blur (
int) 盒阴影模糊度。 - $spread (
int) 盒阴影扩散度。 - $color (
string) 盒阴影颜色。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'custom_box_shadow',
[
'label' => esc_html__( 'Box Shadow', 'textdomain' ),
'type' => \Elementor\Controls_Manager::BOX_SHADOW,
'selectors' => [
'{{SELECTOR}}' => 'box-shadow: {{HORIZONTAL}}px {{VERTICAL}}px {{BLUR}}px {{SPREAD}}px {{COLOR}};',
],
]
);
$this->end_controls_section();
}
}
注意事项
请注意,开发者不应使用此控件,而应使用盒阴影组控制。
按钮控件
Elementor 按钮控件可在面板中显示一个能够触发事件的按钮。
该控件定义在继承 Base_UI_Control 类的 Control_Button 类中。
使用此控件时,应将 type 参数设置为 \Elementor\Controls_Manager::BUTTON 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
button | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
text |
string |
按钮文本。 | |
button_type |
string |
default | 按钮类型。可用值为 default、info、success、warning 和 danger。 |
event |
string |
按钮将触发的事件。该事件将通过 elementor.channels.editor.on( event ) 触发。 |
Return Value
This control does not return any value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'delete_content',
[
'label' => esc_html__( 'Delete Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::BUTTON,
'separator' => 'before',
'button_type' => 'success',
'text' => esc_html__( 'Delete', 'textdomain' ),
'event' => 'namespace:editor:delete',
]
);
$this->end_controls_section();
}
}
选择控件
Elementor 选择控件将单选按钮显示为带有图标选项的按钮组。
该控件在继承 Base_Data_Control 类的 Control_Choose 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::CHOOSE 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
choose | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
options |
array |
[] | 一个多维数组,包含每个单选按钮的 title 和 icon。 |
toggle |
bool |
true | 是否允许切换/取消选择。 |
default |
string |
字段的默认值。 |
Return Value
(string) The selected option value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'text_align',
[
'label' => esc_html__( 'Alignment', 'textdomain' ),
'type' => \Elementor\Controls_Manager::CHOOSE,
'options' => [
'left' => [
'title' => esc_html__( 'Left', 'textdomain' ),
'icon' => 'eicon-text-align-left',
],
'center' => [
'title' => esc_html__( 'Center', 'textdomain' ),
'icon' => 'eicon-text-align-center',
],
'right' => [
'title' => esc_html__( 'Right', 'textdomain' ),
'icon' => 'eicon-text-align-right',
],
],
'default' => 'center',
'toggle' => true,
'selectors' => [
'{{WRAPPER}} .your-class' => 'text-align: {{VALUE}};',
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
代码控制
Elementor 代码控制基于 Ace 编辑器 显示一个代码编辑器文本区域。它接受一个语言参数来定义编程 language,并包含语法高亮器以突出显示代码。
该控件在继承 Base_Data_Control 类的 Control_Code 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::CODE 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
code | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
language |
string |
html | 任何 Ace 编辑器支持的语言。 |
rows |
int |
10 | 行数。 |
default |
string |
字段的默认值。 |
Return Value
(string) The code field value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'custom_html',
[
'label' => esc_html__( 'Custom HTML', 'textdomain' ),
'type' => \Elementor\Controls_Manager::CODE,
'language' => 'html',
'rows' => 20,
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['custom_html'] ) ) {
return;
}
?>
<div class="your-class">
<?php echo $settings['custom_html']; ?>
</div>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.custom_html ) {
return;
}
#>
<div class="your-class">
{{{ settings.custom_html }}}
</div>
<?php
}
}
颜色控制
Elementor 颜色控件显示一个带有 Alpha 通道滑块的颜色选择器字段。它包含一个可由用户预设的自定义调色板。
该控件在继承 Base_Data_Control 类的 Control_Color 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::COLOR 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
color | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 将分隔符定位在控件之前/之后。 |
alpha |
bool |
true | 是否允许 Alpha 通道。 |
default |
string |
默认颜色,格式为 RGB、RGBA 或 HEX。 |
Return Value
(string) The color value in RGB, RGBA, or HEX format.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'text_color',
[
'label' => esc_html__( 'Text Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .your-class' => 'color: {{VALUE}}',
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
说明
日期时间控件
Elementor 日期时间控件基于 Flatpickr 库显示一个日期/时间选择器字段。
该控件定义在继承 Base_Data_Control 类的 Control_Date_Time 类中。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::DATE_TIME 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
date_time | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
picker_options |
array |
enableTime:true, minuteIncrement:1 |
选择器的配置。 |
default |
string |
默认日期/时间,使用 MySQL 格式 (YYYY-mm-dd HH:ii)。 |
Return Value
(string) The chosen date/time in MySQL format (YYYY-mm-dd HH:ii).
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'due_date',
[
'label' => esc_html__( 'Due Date', 'textdomain' ),
'type' => \Elementor\Controls_Manager::DATE_TIME,
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['due_date'] ) ) {
return;
}
$due_date = strtotime( $settings['due_date'] );
$due_date_in_days = $due_date / DAY_IN_SECONDS;
?>
<p><?php printf( esc_html__( 'Something will happen in %s days.', 'textdomain' ), $due_date_in_days ); ?></p>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.due_date ) {
return;
}
const due_date = new Date( settings.due_date );
const now_date = new Date();
const due_date_in_days = Math.floor( ( due_date - now_date ) / 86400000 ); // 86400000 milliseconds in one Day.
#>
<p> Something will happen in {{{ due_date_in_days }}} days. </p>
<?php
}
}
弃用通知控件
Elementor 弃用通知控件在面板中显示一个预格式化的通知,警告该小部件已弃用并应被替换。
该控件在 Control_Deprecated_Notice 类中定义,该类继承自 Base_UI_Control 类。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::DEPRECATED_NOTICE 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
raw_html | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
widget |
string |
小部件名称。 | |
since |
string |
小部件被弃用的插件版本。 | |
last |
string |
小部件将被移除的插件版本。 | |
plugin |
string |
插件的标题。 | |
replacement |
string |
小部件的替代品。 |
返回值
此控件不返回任何值。
用法
有两种方式可以为小部件添加弃用通知:
Using the Regular Add Control
Add a notice warning that the widget is deprecated using the regular add_control() method.
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'deprecated_notice',
[
'type' => \Elementor\Controls_Manager::DEPRECATED_NOTICE,
'widget' => 'your-old-widget',
'since' => '3.10.0',
'last' => '3.20.0',
'plugin' => 'Your Great Plugin',
'replacement' => 'your-new-widget',
'content_classes' => 'your-class',
]
);
// Register the rest of the controls as usual.
$this->end_controls_section();
}
}
Using a Deprecated Notice Method
Add a notice warning that the widget is deprecated using the deprecated_notice() method.
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->deprecated_notice(
'Your Great Plugin',
'3.10.0',
'3.20.0',
'your-new-widget'
);
// Register the rest of the controls as usual.
$this->end_controls_section();
}
}
尺寸控制
Elementor 尺寸控制显示上、右、下、左的输入字段,并提供将它们链接在一起的选项。该控件可选择包含多种单位类型 (size_units) 供用户选择。它还接受 range 参数,允许您为每种单位类型设置 min、max 和 step 值。
该控件在继承 Control_Base_Units 类的 Control_Dimensions 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::DIMENSIONS 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
dimensions | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
size_units |
array |
[ 'px' ] | 可用 CSS 单位的数组,例如 px、em、rem、%、deg、vh 或 custom。 |
default |
array |
滑块默认值。
|
|
placeholder |
array |
当字段没有值时显示的占位符。
|
返回值
[
'top' => '',
'right' => '',
'bottom' => '',
'left' => '',
'unit' => '',
'isLinked' => '',
]
(array) 包含尺寸值的数组:
- $top (
int) 顶部尺寸。 - $right (
int) 右侧尺寸。 - $bottom (
int) 底部尺寸。 - $left (
int) 左侧尺寸。 - $unit (
string) CSS 单位类型。 - $isLinked (
bool) 是否将所有值链接在一起。
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'margin',
[
'label' => esc_html__( 'Margin', 'textdomain' ),
'type' => \Elementor\Controls_Manager::DIMENSIONS,
'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
'default' => [
'top' => 2,
'right' => 0,
'bottom' => 2,
'left' => 0,
'unit' => 'em',
'isLinked' => false,
],
'selectors' => [
'{{WRAPPER}} .your-class' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
分隔线控件
Elementor 分隔线控件用于在控件之间显示分隔符。
该控件定义在继承 Base_UI_Control 类的 Control_Divider 类中。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::DIVIDER 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
divider | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
返回值
此控件不返回任何值。
用法示例
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'hr',
[
'type' => \Elementor\Controls_Manager::DIVIDER,
]
);
$this->end_controls_section();
}
}
退出动画控制
Elementor 退出动画控制基于 Animate.css 库显示一个选择框字段。该控制允许为项目设置退出动画效果。
该控件在 Control_Exit_Animation 类中定义,该类继承自 Control_Animation 类,而 Control_Animation 类又继承自 Base_Data_Control 类。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::EXIT_ANIMATION 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
exit_animation | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
default |
string |
字段的默认值。 |
Return Value
(string) The selected exit animation class.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'exit_animation',
[
'label' => esc_html__( 'Exit Animation', 'textdomain' ),
'type' => \Elementor\Controls_Manager::EXIT_ANIMATION,
'prefix_class' => 'animated ',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="<?php echo esc_attr( $settings['exit_animation'] ); ?>">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="{{ settings.exit_animation }}">
...
</div>
<?php
}
}
字体控制
Elementor 字体控制基于 Google Fonts 库显示一个字体选择框。该控件允许您设置字体列表。
此控件在继承 Base_Data_Control 类的 Control_Font 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::FONT 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
font | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
options |
array |
可用字体的关联数组。[ '字体名称' => 'family-name', ... ] |
|
groups |
array |
可用字体分组的关联数组。 | |
default |
string |
默认字体名称。 |
Return Value
(string) The selected font-family name.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'font_family',
[
'label' => esc_html__( 'Font Family', 'textdomain' ),
'type' => \Elementor\Controls_Manager::FONT,
'default' => "'Open Sans', sans-serif",
'selectors' => [
'{{WRAPPER}} .your-class' => 'font-family: {{VALUE}}',
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<h2 class="your-class">
...
</h2>
<?php
}
protected function content_template(): void {
?>
<h2 class="your-class">
...
</h2>
<?php
}
}
画廊控件
Elementor 画廊控件基于 WordPress 画廊显示一个媒体选择区域。该控件允许从 WordPress 媒体库中选择多张图片。
该控件在继承 Base_Data_Control 类的 Control_Gallery 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::GALLERY 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
gallery | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
default |
array |
默认图库图片。包含图片 ID 和 URL 的图片数组。 |
返回值
[
[
'id' => 0,
'url' => ''
],
[
'id' => 0,
'url' => ''
],
]
(array) 一个由单个图片数组组成的数组,包含每个图片的 ID 和 URL:
- $id (
int) 媒体 ID。 - $url (
string) 媒体 URL。
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'gallery',
[
'label' => esc_html__( 'Add Images', 'textdomain' ),
'type' => \Elementor\Controls_Manager::GALLERY,
'show_label' => false,
'default' => [],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
foreach ( $settings['gallery'] as $image ) {
echo '<img src="' . esc_attr( $image['url'] ) . '">';
}
}
protected function content_template(): void {
?>
<# _.each( settings.gallery, function( image ) { #>
<img src="{{ image.url }}">
<# }); #>
<?php
}
}
标题控件
Elementor 标题控件用于在面板中的控件之间显示文本标题。
该控件定义在继承 Base_UI_Control 类的 Control_Heading 类中。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::HEADING 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
heading | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
返回值
此控件不返回任何值。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'more_options',
[
'label' => esc_html__( 'Additional Options', 'textdomain' ),
'type' => \Elementor\Controls_Manager::HEADING,
'separator' => 'before',
]
);
$this->end_controls_section();
}
}
隐藏控件
Elementor 隐藏控件在面板中添加一个隐藏的输入字段。它可用于添加数据,而无需在面板中进行可视化呈现。这意味着 Elementor 用户无法访问此控件。
该控件在继承 Base_Data_Control 类的 Control_Hidden 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::HIDDEN 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
hidden | 控件的类型。 |
label |
string |
显示在字段上方的标签。但在这种情况下不会显示。 | |
default |
string |
字段的默认值。 |
返回值
(string) 隐藏字段的值。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'view',
[
'label' => esc_html__( 'View', 'textdomain' ),
'type' => \Elementor\Controls_Manager::HIDDEN,
'default' => 'traditional',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<!-- <?php echo $settings['view']; ?> -->
<?php
}
protected function content_template(): void {
?>
<!-- {{{ settings.view }}} -->
<?php
}
}
Hover Animation Control
Elementor hover animation control displays a select box field based on the Hover.css library. The control allows to set an hover animation effect for an item.
The control is defined in Control_Hover_Animation class which extends Base_Data_Control class.
When using this control, the type should be set to \Elementor\Controls_Manager::HOVER_ANIMATION constant.
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
hover_animation | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
default |
string |
字段的默认值。 |
Return Value
(string) The selected hover animation class.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'hover_animation',
[
'label' => esc_html__( 'Hover Animation', 'textdomain' ),
'type' => \Elementor\Controls_Manager::HOVER_ANIMATION,
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
$elementClass = 'container';
if ( $settings['hover_animation'] ) {
$elementClass .= ' elementor-animation-' . $settings['hover_animation'];
}
$this->add_render_attribute( 'wrapper', 'class', $elementClass );
?>
<div <?php $this->print_render_attribute_string( 'wrapper' ); ?>>
...
</div>
<?php
}
protected function content_template(): void {
?>
<#
const elementClass = 'container';
if ( '' !== settings.hover_animation ) {
elementClass += ' elementor-animation-' + settings.hover_animation;
}
view.addRenderAttribute( 'wrapper', { 'class': elementClass } );
#>
<div {{{ view.getRenderAttributeString( 'wrapper' ) }}}>
...
</div>
<?php
}
}
图标控件
::: danger 已弃用 此控件已被弃用,推荐使用新的图标控件。 :::
Elementor 图标控件显示一个基于 Font Awesome 字体的图标选择框。该控件接受 include 或 exclude 参数来设置部分图标列表。
该控件定义在继承 Base_Data_Control 类的 Control_Icon 类中。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::ICON 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
icon | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
options |
array |
get_icons() |
可用图标的关联数组。 |
include |
array |
要包含在选项列表中的图标类名数组。 | |
exclude |
array |
要从选项列表中排除的图标类名数组。 | |
default |
string |
默认图标名称。 |
Return Value
(string) The selected icon CSS class.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'icon',
[
'label' => esc_html__( 'Social Icons', 'textdomain' ),
'type' => \Elementor\Controls_Manager::ICON,
'include' => [
'fa fa-facebook',
'fa fa-flickr',
'fa fa-google-plus',
'fa fa-instagram',
'fa fa-linkedin',
'fa fa-pinterest',
'fa fa-reddit',
'fa fa-twitch',
'fa fa-twitter',
'fa fa-vimeo',
'fa fa-youtube',
],
'default' => 'fa fa-facebook',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<i class="<?php echo esc_attr( $settings['icon'] ); ?>" aria-hidden="true"></i>
<?php
}
protected function content_template(): void {
?>
<i class="{{ settings.icon }}" aria-hidden="true"></i>
<?php
}
}
图标控件
Elementor 图标控件显示图标选择器。此外,它能够从 Elementor 的“图标库”中选择现有图标,或“上传 SVG”到 WordPress 媒体库。
该控件在继承 Control_Base_Multiple 类的 Control_Icons 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::ICONS 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
type |
string |
icons | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | |
default |
array |
默认值设置为一个包含值和库的数组。 | |
fa4compatibility |
string |
用于从旧的 图标控件 迁移数据,应设置为旧控件的名称。 | |
recommended |
array |
用于设置此控件实例的推荐图标。 | |
skin |
string |
media | 用于更改控件的外观。有两个选项:media 或 inline。inline 皮肤的设计基于选择控件。 |
exclude_inline_options |
array |
仅与 inline 皮肤一起使用,用于从内联图标控件的按钮中隐藏一个选项(图标库/SVG)。 |
Return Value
[
'value' => '',
'library' => '',
]
(array) An array containing icon data:
- $value (
string) Icon value. - $library (
string) Icon library name.
Usage
<?php
class Icons_Elementor_Test_Control_Widget extends \Elementor\Widget_Base {
public function get_name(): string {
return 'icons_test_widget';
}
public function get_title(): string {
return esc_html__( 'Icons Test Widget', 'textdomain' );
}
protected function register_controls(): void {
$this->start_controls_section(
'section_icon',
[
'label' => esc_html__( 'Icon', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'icon',
[
'label' => esc_html__( 'Icon', 'textdomain' ),
'type' => \Elementor\Controls_Manager::ICONS,
'default' => [
'value' => 'fas fa-circle',
'library' => 'fa-solid',
],
'recommended' => [
'fa-solid' => [
'circle',
'dot-circle',
'square-full',
],
'fa-regular' => [
'circle',
'dot-circle',
'square-full',
],
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="my-icon-wrapper">
<?php \Elementor\Icons_Manager::render_icon( $settings['icon'], [ 'aria-hidden' => 'true' ] ); ?>
</div>
<?php
}
protected function content_template(): void {
?>
<#
const iconHTML = elementor.helpers.renderIcon( view, settings.selected_icon, { 'aria-hidden': true }, 'i' , 'object' );
#>
<div class="my-icon-wrapper">
{{{ iconHTML.value }}}
</div>
<?php
}
}
Image Dimensions Control
Elementor image dimensions control displays a width input, a height input and an apply button. It is used by the Image Size group control to allow the user to set custom width or height for an image.
The control is defined in Control_Image_Dimensions class which extends Control_Base_Multiple class.
When using this control, the type should be set to \Elementor\Controls_Manager::IMAGE_DIMENSIONS constant.
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
image_dimensions | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
false | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
default |
array |
默认的图像尺寸值。
|
返回值
[
'width' => '',
'height' => '',
]
(array) 一个包含图像尺寸值的数组:
- $width (
int) 图像宽度。 - $height (
int) 图像高度。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'custom_dimension',
[
'label' => esc_html__( 'Image Dimension', 'textdomain' ),
'type' => \Elementor\Controls_Manager::IMAGE_DIMENSIONS,
'description' => esc_html__( 'Crop the original image size to any custom size. Set custom width or height to keep the original size ratio.', 'textdomain' ),
'default' => [
'width' => '',
'height' => '',
],
]
);
$this->end_controls_section();
}
}
媒体控件
Elementor 媒体控件基于 WordPress 媒体库显示媒体选择器部分,允许用户从媒体库中选择图像。
该控件在继承 Control_Base_Multiple 类的 Control_Media 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::MEDIA 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
media | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
media_types |
array |
['image'] | 支持的媒体类型。可用值为 image、video、svg、application/pdf 等。 |
default |
array |
默认媒体值。
|
Return Value
[
'id' => '',
'url' => '',
]
(array) An array containing image data:
- $id (
int) Media id. - $url (
string) Media url.
Usage
Add an image:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'image',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'default' => [
'url' => \Elementor\Utils::get_placeholder_image_src(),
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['image']['url'] ) ) {
return;
}
// Get image URL
echo '<img src="' . $settings['image']['url'] . '">';
// Get image 'thumbnail' by ID
echo wp_get_attachment_image( $settings['image']['id'], 'thumbnail' );
// Get image HTML
$this->add_render_attribute( 'image', 'src', $settings['image']['url'] );
$this->add_render_attribute( 'image', 'alt', \Elementor\Control_Media::get_image_alt( $settings['image'] ) );
$this->add_render_attribute( 'image', 'title', \Elementor\Control_Media::get_image_title( $settings['image'] ) );
$this->add_render_attribute( 'image', 'class', 'my-custom-class' );
echo \Elementor\Group_Control_Image_Size::get_attachment_image_html( $settings, 'thumbnail', 'image' );
}
protected function content_template(): void {
?>
<#
if ( '' === settings.image.url ) {
return;
}
const image = {
id: settings.image.id,
url: settings.image.url,
size: settings.image_size,
dimension: settings.image_custom_dimension,
model: view.getEditModel()
};
const image_url = elementor.imagesManager.getImageUrl( image );
if ( '' === image_url ) {
return;
}
#>
<img src="{{ image_url }}">
<?php
}
}
Add a video media type to display a self hosted video:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'video',
[
'label' => esc_html__( 'Choose Video File', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'media_types' => [ 'video' ],
'default' => [
'url' => \Elementor\Utils::get_placeholder_image_src(),
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
$video_url = $settings['video']['url'];
if ( empty( $video_url ) ) {
return;
}
?>
<video src="<?php echo esc_attr( $video_url ); ?>" class="elementor-video"></video>
<?php
}
protected function content_template(): void {
?>
<#
const video_url = settings.video.url;
if ( '' === video_url ) {
return;
}
#>
<video src="{{ video_url }}" class="elementor-video"></video>
<?php
}
}
Add a PDF file:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'pdf',
[
'label' => esc_html__( 'Choose PDF', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'media_types' => [ 'application/pdf' ],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
$pdf_url = $settings['pdf']['url'];
if ( ! empty( $pdf_url ) ) {
return;
}
?>
<a download href="<?php echo esc_attr( $pdf_url ); ?>">
<?php echo esc_html__( 'Download PDF', 'textdomain' ); ?>
</a>
<?php
}
protected function content_template(): void {
?>
<#
const pdf_url = settings.pdf.url;
if ( '' === pdf_url ) {
return;
}
#>
<a download src="{{ pdf_url }}">
<?php echo esc_html__( 'Download PDF', 'textdomain' ); ?>
</a>
<?php
}
}
通知控件
Elementor 通知控件根据消息的严重程度,在面板中显示四种类型的通知:信息、成功、警告和危险。
与警告控件不同,通知控件可以选择设置为可关闭,允许用户关闭消息并且不再显示。
该控件在继承 Base_UI_Control 类的 Control_Notice 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::NOTICE 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
notice | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 将分隔符定位在控件之前/之后。 |
notice_type |
string |
info | 通知的类型。可用值为 info、success、warning 和 danger。 |
dismissible |
bool |
false | 允许用户关闭通知。 |
heading |
string |
显示在通知上方的标题。 | |
content |
string |
通知的内容。 |
返回值
此控件不返回任何值。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'custom_panel_notice',
[
'type' => \Elementor\Controls_Manager::NOTICE,
'notice_type' => 'warning',
'dismissible' => true,
'heading' => esc_html__( 'Custom Notice', 'textdomain' ),
'content' => esc_html__( 'Lorem ipsum dolor sit amet consectetur adipisicing elit.', 'textdomain' ),
]
);
$this->end_controls_section();
}
}
数值控制
Elementor 数值控件显示一个简单的数字输入字段,可选择限制最小值和最大值,并定义数值变化时的步长。
该控件在继承 Base_Data_Control 类的 Control_Number 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::NUMBER 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
number | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 将分隔符定位在控件之前/之后。 |
min |
string |
最小值(仅影响微调器,用户仍可输入更低的值)。 | |
max |
string |
最大值(仅影响微调器,用户仍可输入更高的值)。 | |
step |
string |
使用控件微调器时递增或递减的间隔值。默认为空,值将递增 1。 | |
placeholder |
string |
字段无值时显示的占位符。 | |
title |
string |
鼠标悬停时显示的字段标题。 | |
default |
string |
字段的默认值。 |
Return Value
(string) The number field value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'price',
[
'label' => esc_html__( 'Price', 'textdomain' ),
'type' => \Elementor\Controls_Manager::NUMBER,
'min' => 5,
'max' => 100,
'step' => 5,
'default' => 10,
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['price'] ) ) {
return;
}
?>
<span class="price">
<?php echo $settings['price']; ?>
</span>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.price ) {
return;
}
#>
<span class="price">
{{{ settings.price }}}
</span>
<?php
}
}
Popover Toggle Control
Elementor popover toggle control displays a toggle button to open and close a popover. The control allow you to open a popover with custom controls.
The control is defined in Control_Popover_Toggle class which extends Base_Data_Control class.
When using this control, the type should be set to \Elementor\Controls_Manager::POPOVER_TOGGLE constant.
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
popover_toggle | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
label_on |
string |
Custom | “未选中”状态的标签。 |
label_off |
string |
Default | “选中”状态的标签。 |
return_value |
string |
yes | 选中时返回的值。 |
default |
string |
字段的默认值。 |
Return Value
(string) The popover toggle field value, based on return_value argument.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'border_popover_toggle',
[
'label' => esc_html__( 'Border', 'textdomain' ),
'type' => \Elementor\Controls_Manager::POPOVER_TOGGLE,
'label_off' => esc_html__( 'Default', 'textdomain' ),
'label_on' => esc_html__( 'Custom', 'textdomain' ),
'return_value' => 'yes',
'default' => 'yes',
]
);
$this->start_popover();
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_popover();
$this->end_controls_section();
}
}
控制项弹出框
控制项弹出框是用于分组控制项并将其显示在面板上方弹出窗口中的 UI 包装器。使用弹出框可以帮助您通过将控制项移至弹出框来简化面板,仅当用户选择查看它们时才显示。一个很好的例子是排版控制项。它包含一个切换开关,只有当用户选择更改默认排版设置时,额外的控制项才会出现在弹出框中。弹出框使用两种方法创建:start_popover() 创建新弹出框,end_popover() 关闭弹出框。
控制项弹出框结构
使用以下代码添加新的控制项弹出框:
$this->add_control(
'popover-toggle',
[
'type' => \Elementor\Controls_Manager::POPOVER_TOGGLE,
'label' => esc_html__( 'Box', 'textdomain' ),
'label_off' => esc_html__( 'Default', 'textdomain' ),
'label_on' => esc_html__( 'Custom', 'textdomain' ),
'return_value' => 'yes',
]
);
$this->start_popover();
$this->end_popover();
控制项参数
每个控制项具有以下关键参数:
- 弹出框名称
(string)– 代码中使用的唯一标识符。 - 弹出框设置
(array)– 额外的弹出框参数。- 标签
(string)– 在面板中向用户显示的标签。 - 类型
(string)– 控制项类型。 - 关闭标签
(string)– 设置默认设置时显示的标签。 - 开启标签
(string)– 设置自定义设置时显示的标签。 - 返回值
(string)– 设置自定义设置时返回的字符串。 - 条件
(array)– 控制项显示条件。
- 标签
示例
控制项弹出框
在下面的示例中,我们将控制项分组到两个弹出框中 - "正常" 选项卡和 "悬停" 选项卡:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style Section', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'popover-toggle',
[
'label' => esc_html__( 'Box', 'textdomain' ),
'type' => \Elementor\Controls_Manager::POPOVER_TOGGLE,
'label_off' => esc_html__( 'Default', 'textdomain' ),
'label_on' => esc_html__( 'Custom', 'textdomain' ),
'return_value' => 'yes',
]
);
$this->start_popover();
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_popover();
$this->end_controls_section();
}
}
原始 HTML 控件
Elementor 原始 HTML 控件在面板中显示 HTML 内容。
该控件在继承 Base_UI_Control 类的 Control_Raw_Html 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::RAW_HTML 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
raw_html | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 将分隔符定位在控件之前/之后。 |
raw |
string |
HTML 标记。 | |
content_classes |
string |
要添加到控件包装器的 CSS 类。 |
返回值
此控件不返回任何值。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'important_note',
[
'label' => esc_html__( 'Important Note', 'textdomain' ),
'type' => \Elementor\Controls_Manager::RAW_HTML,
'raw' => esc_html__( 'A very important message to show in the panel.', 'textdomain' ),
'content_classes' => 'your-class',
]
);
$this->end_controls_section();
}
}
重复器控件
Elementor 重复器控件允许您构建可重复的字段块。例如,您可以创建一组包含标题和 WYSIWYG 文本的字段——用户随后将能够添加“行”,每行都包含一个标题和一段文本。这些数据可以包装在自定义 HTML 标签中,使用 CSS 进行设计,并通过 JS 或外部库实现交互。
该控件在继承 Base_Data_Control 类的 Control_Repeater 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::REPEATER 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
repeater | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 将分隔符定位在控件之前/之后。 |
fields |
array |
一个包含重复器字段的多维数组。 | |
title_field |
string |
当项目被最小化时,将在字段列表中用作重复器标题的字段。 | |
prevent_empty |
bool |
true | 是否防止删除第一个重复器字段。以保持至少一个重复器字段。 |
default |
array |
默认的重复器值。一个多维数组,包含字段作为键,每个键的默认值作为值:[ [ 'title' => '', 'content' => '' ], [ 'title' => '', 'content' => '' ], ... ] |
Return Value
(array) A multi dimensional array containing inner fields values.
Usage
Usage example with fields array:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'list',
[
'label' => esc_html__( 'Repeater List', 'textdomain' ),
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => [
[
'name' => 'list_title',
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'default' => esc_html__( 'List Title' , 'textdomain' ),
'label_block' => true,
],
[
'name' => 'list_content',
'label' => esc_html__( 'Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::WYSIWYG,
'default' => esc_html__( 'List Content' , 'textdomain' ),
'show_label' => false,
],
[
'name' => 'list_color',
'label' => esc_html__( 'Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} {{CURRENT_ITEM}}' => 'color: {{VALUE}}'
],
]
],
'default' => [
[
'list_title' => esc_html__( 'Title #1', 'textdomain' ),
'list_content' => esc_html__( 'Item content. Click the edit button to change this text.', 'textdomain' ),
],
[
'list_title' => esc_html__( 'Title #2', 'textdomain' ),
'list_content' => esc_html__( 'Item content. Click the edit button to change this text.', 'textdomain' ),
],
],
'title_field' => '{{{ list_title }}}',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( $settings['list'] ) {
echo '<dl>';
foreach ( $settings['list'] as $item ) {
echo '<dt class="elementor-repeater-item-' . esc_attr( $item['_id'] ) . '">' . $item['list_title'] . '</dt>';
echo '<dd>' . $item['list_content'] . '</dd>';
}
echo '</dl>';
}
}
protected function content_template(): void {
?>
<# if ( settings.list.length ) { #>
<dl>
<# _.each( settings.list, function( item ) { #>
<dt class="elementor-repeater-item-{{ item._id }}">{{{ item.list_title }}}</dt>
<dd>{{{ item.list_content }}}</dd>
<# }); #>
</dl>
<# } #>
<?php
}
}
Usage example with Repeater() class:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$repeater = new \Elementor\Repeater();
$repeater->add_control(
'list_title',
[
'label' => esc_html__( '标题', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'default' => esc_html__( '列表标题' , 'textdomain' ),
'label_block' => true,
]
);
$repeater->add_control(
'list_content',
[
'label' => esc_html__( '内容', 'textdomain' ),
'type' => \Elementor\Controls_Manager::WYSIWYG,
'default' => esc_html__( '列表内容' , 'textdomain' ),
'show_label' => false,
]
);
$repeater->add_control(
'list_color',
[
'label' => esc_html__( '颜色', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} {{CURRENT_ITEM}}' => 'color: {{VALUE}}'
],
]
);
$this->add_control(
'list',
[
'label' => esc_html__( '重复列表', 'textdomain' ),
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => $repeater->get_controls(),
'default' => [
[
'list_title' => esc_html__( '标题 #1', 'textdomain' ),
'list_content' => esc_html__( '项目内容。点击编辑按钮修改此文本。', 'textdomain' ),
],
[
'list_title' => esc_html__( '标题 #2', 'textdomain' ),
'list_content' => esc_html__( '项目内容。点击编辑按钮修改此文本。', 'textdomain' ),
],
],
'title_field' => '{{{ list_title }}}',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( $settings['list'] ) {
echo '<dl>';
foreach ( $settings['list'] as $item ) {
echo '<dt class="elementor-repeater-item-' . esc_attr( $item['_id'] ) . '">' . $item['list_title'] . '</dt>';
echo '<dd>' . $item['list_content'] . '</dd>';
}
echo '</dl>';
}
}
protected function content_template(): void {
?>
<# if ( settings.list.length ) { #>
<dl>
<# _.each( settings.list, function( item ) { #>
<dt class="elementor-repeater-item-{{ item._id }}">{{{ item.list_title }}}</dt>
<dd>{{{ item.list_content }}}</dd>
<# }); #>
</dl>
<# } #>
<?php
}
}
注意事项
中继器可以有条件地显示。但必须明确了解有条件显示中继器字段时,哪些操作可行,哪些不可行。
控制项分组
控制项分组是用于在面板标签页下排列控制项的 UI 包装器。这些控制项被划分为多个分组,每个控制项必须属于一个分组。这些分组通过两种方法创建:start_controls_section() 用于创建新分组,而 end_controls_section() 用于关闭分组。
控制面板结构
按照以下步骤添加新的控制面板:
$this->start_controls_section(
'my_section',
[
'label' => esc_html__( '我的面板', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->end_controls_section();
控制参数
每个控件都包含以下关键参数:
- 区块名称
(string)– 在代码中使用的唯一标识符。 - 区块设置
(array)– 额外的区块参数。- 标签
(string)– 在面板中向用户显示的标签。 - 标签页
(string)– 区块所在的标签页。默认为content。 - 条件
(array)– 控件的显示条件。
- 标签
示例
单一部分
下面的示例创建了一个单独的部分,它将属于"内容"选项卡。我们需要提供部分名称以及额外参数,例如部分标签:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_section();
}
}
这将在"内容"选项卡下创建一个新的"内容"部分。
多个控制区域
现在让我们为"内容"选项卡创建多个控制区域:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_section();
$this->start_controls_section(
'info_section',
[
'label' => esc_html__( 'Info', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_section();
}
}
这将在"内容"选项卡下为我们的控件创建两个区域。
多标签页中的区块
下一步是在"内容"标签页和"样式"标签页下创建新区块。这可以通过在额外参数数组中指定标签页名称来实现。
Elementor 提供了一个预定义的标签页列表供您使用,但对于小部件,惯例是仅使用"内容"标签页和"样式"标签页。
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_section();
$this->start_controls_section(
'info_section',
[
'label' => esc_html__( 'Info', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_section();
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_section();
}
}
在此示例中,我们在"内容"标签页下创建了两个区块,并在"样式"标签页下创建了另一个区块。
从代码中可以看出,除非我们定义了"tab"参数,否则区块将默认添加到"内容"标签页。
选择控件
Elementor 选择控件显示一个简单的下拉选择框。它接受一个数组,其中 key 是选项的 value,而值则是选项名称。
该控件定义在继承 Base_Data_Control 类的 Control_Select 类中。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::SELECT 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
select | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 将分隔符定位在控件之前/之后。 |
options |
array |
一个 键 => 值 对的数组:[ '键' => '值', ... ] |
|
groups |
array |
分组选项的数组。 | |
default |
string |
字段的默认值。 |
Return Value
(string) The selected option value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'border_style',
[
'label' => esc_html__( 'Border Style', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SELECT,
'default' => 'solid',
'options' => [
'' => esc_html__( 'Default', 'textdomain' ),
'none' => esc_html__( 'None', 'textdomain' ),
'solid' => esc_html__( 'Solid', 'textdomain' ),
'dashed' => esc_html__( 'Dashed', 'textdomain' ),
'dotted' => esc_html__( 'Dotted', 'textdomain' ),
'double' => esc_html__( 'Double', 'textdomain' ),
],
'selectors' => [
'{{WRAPPER}} .your-class' => 'border-style: {{VALUE}};',
],
]
);
$this->add_control(
'custom_animation',
[
'label' => esc_html__( 'Animation', 'textdomain' ),
'type' => Controls_Manager::SELECT,
'groups' => [
[
'label' => esc_html__( 'None', 'textdomain' ),
'options' => [
'' => esc_html__( 'None', 'textdomain' ),
],
],
[
'label' => esc_html__( 'Slide', 'textdomain' ),
'options' => [
'slide-from-right' => esc_html__( 'Slide In Right', 'textdomain' ),
'slide-from-left' => esc_html__( 'Slide In Left', 'textdomain' ),
'slide-from-top' => esc_html__( 'Slide In Up', 'textdomain' ),
'slide-from-bottom' => esc_html__( 'Slide In Down', 'textdomain' ),
],
],
[
'label' => esc_html__( 'Zoom', 'textdomain' ),
'options' => [
'grow' => esc_html__( 'Grow', 'textdomain' ),
'shrink' => esc_html__( 'Shrink', 'textdomain' ),
'zoom-in' => esc_html__( 'Zoom In', 'textdomain' ),
'zoom-out' => esc_html__( 'Zoom Out', 'textdomain' ),
],
],
],
'prefix_class' => 'custom-animation-',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
Select2 控件
Elementor select2 控件基于 Select2 库显示一个选择框控件。它接受一个数组,其中 key 是值,value 是选项名称。将 multiple 设置为 true 以允许多值选择。
该控件在继承 Base_Data_Control 类的 Control_Select2 类中定义。
使用此控件时,type 应设置为 \Elementor\Controls_Manager::SELECT2 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
select2 | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
options |
array |
一个 键 => 值 对的数组:[ '键' => '值', ... ] |
|
multiple |
bool |
false | 是否允许多值选择。 |
default |
string|array |
选中的选项键,或者如果 multiple 设置为 true,则为选中值的数组。 |
Return Value
(string|array) The selected option key, or an array of selected keys if multiple is set to true.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'list',
[
'label' => esc_html__( 'Show Elements', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SELECT2,
'label_block' => true,
'multiple' => true,
'options' => [
'title' => esc_html__( 'Title', 'textdomain' ),
'description' => esc_html__( 'Description', 'textdomain' ),
'button' => esc_html__( 'Button', 'textdomain' ),
],
'default' => [ 'title', 'description' ],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( $settings['list'] ) {
echo '<ul>';
foreach ( $settings['list'] as $item ) {
echo '<li>' . $item . '</li>';
}
echo '</ul>';
}
}
protected function content_template(): void {
?>
<# if ( settings.list.length ) { #>
<ul>
<# _.each( settings.list, function( item ) { #>
<li>{{{ item }}}</li>
<# } ) #>
</ul>
<# } #>
<?php
}
}
滑块控件
Elementor 滑块控件显示一个可拖动的范围滑块。该控件可选择性地包含多种单位类型 (size_units) 供用户选择。控件还接受一个 range 参数,允许您为每种单位类型设置 min、max 和 step 值。
此控件在继承 Control_Base_Units 类的 Control_Slider 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::SLIDER 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
slider | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
size_units |
array |
[ 'px' ] | 可用 CSS 单位的数组,例如 px、em、rem、%、deg、vh 或 custom。 |
range |
array |
每个注册尺寸的范围数组。
|
|
default |
array |
滑块默认值。
|
返回值
[
'unit' => '',
'size' => '',
]
(array) 一个包含尺寸值的数组:
- $unit (
string) 选定的单位。 - $size (
int) 选定的尺寸。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'width',
[
'label' => esc_html__( 'Width', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SLIDER,
'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
'range' => [
'px' => [
'min' => 0,
'max' => 1000,
'step' => 5,
],
'%' => [
'min' => 0,
'max' => 100,
],
],
'default' => [
'unit' => '%',
'size' => 50,
],
'selectors' => [
'{{WRAPPER}} .your-class' => 'width: {{SIZE}}{{UNIT}};',
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
开关控件
Elementor 开关控件显示一个开/关切换器。它本质上是复选框的一种精美表现形式。
该控件定义在继承 Base_Data_Control 类的 Control_Switcher 类中。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::SWITCHER 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
switcher | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
label_on |
string |
Yes | “未选中”状态的标签。 |
label_off |
string |
No | “已选中”状态的标签。 |
return_value |
string |
yes | 选中时返回的值。 |
default |
string |
字段的默认值。 |
Return Value
(string) The switcher field value, based on return_value argument.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'show_title',
[
'label' => esc_html__( 'Show Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SWITCHER,
'label_on' => esc_html__( 'Show', 'textdomain' ),
'label_off' => esc_html__( 'Hide', 'textdomain' ),
'return_value' => 'yes',
'default' => 'yes',
]
);
$this->add_control(
'title',
[
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'default' => esc_html__( 'Default title', 'textdomain' ),
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( 'yes' === $settings['show_title'] ) {
echo '<h2>' . $settings['title'] . '</h2>';
}
}
protected function content_template(): void {
?>
<# if ( 'yes' === settings.show_title ) { #>
<h2>{{{ settings.title }}}</h2>
<# } #>
<?php
}
}
控制选项卡
控制选项卡是用于在面板中排列区域和控件的 UI 包装器。控件必须添加到区域中,而区域是选项卡的一部分。选项卡使用两个方法创建:start_controls_tabs() 创建新选项卡,而 end_controls_tabs() 关闭选项卡。每个选项卡区域都有内部选项卡元素,这些内部选项卡也使用两个方法创建:start_controls_tab() 创建新的内部选项卡,而 end_controls_tab() 关闭内部选项卡。
控制选项卡结构
使用以下代码添加新的控制选项卡:
$this->start_controls_tabs(
'style_tabs'
);
$this->start_controls_tab(
'style_normal_tab',
[
'label' => esc_html__( 'Normal', 'textdomain' ),
]
);
$this->end_controls_tab();
$this->end_controls_tabs();
控制参数
每个选项卡控制具有以下关键参数:
- 选项卡名称
(string)– 代码中使用的唯一 ID。
每个内部选项卡控制具有以下关键参数:
- 选项卡名称
(string)– 代码中使用的唯一 ID。 - 选项卡设置
(array)– 额外的选项卡参数。- 标签
(string)– 在面板中向用户显示的标签。
- 标签
示例
控制选项卡
让我们将控件分组到两个选项卡中 - "正常" 和 "悬停":
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style Section', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->start_controls_tabs(
'style_tabs'
);
$this->start_controls_tab(
'style_normal_tab',
[
'label' => esc_html__( 'Normal', 'textdomain' ),
]
);
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_tab();
$this->start_controls_tab(
'style_hover_tab',
[
'label' => esc_html__( 'Hover', 'textdomain' ),
]
);
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_tab();
$this->end_controls_tabs();
$this->end_controls_section();
}
}
文本阴影控制
Elementor 文本阴影控件显示用于水平阴影、垂直阴影、阴影模糊和阴影颜色的输入字段。
该控件在继承 Control_Base_Multiple 类的 Control_Text_Shadow 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::TEXT_SHADOW 常量。
参数
返回值
[
'horizontal' => 0,
'vertical' => 0,
'blur' => 10,
'color' => 'rgba(0,0,0,0.3)',
];
(array) 包含文本阴影数据的数组:
- $horizontal (
int) 文本阴影水平大小。 - $vertical (
int) 文本阴影垂直大小。 - $blur (
int) 文本阴影模糊度。 - $color (
string) 文本阴影颜色。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'custom_text_shadow',
[
'label' => esc_html__( 'Text Shadow', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT_SHADOW,
'selectors' => [
'{{SELECTOR}}' => 'text-shadow: {{HORIZONTAL}}px {{VERTICAL}}px {{BLUR}}px {{COLOR}};',
],
]
);
$this->end_controls_section();
}
}
注意事项
请注意,开发者不应使用此控件,而应使用文本阴影组控件。
文本控件
Elementor 文本控件显示一个简单的文本输入框。
该控件在继承 Base_Data_Control 类的 Control_Text 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::TEXT 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
text | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
false | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
input_type |
string |
text | 输入字段类型。可用值为所有 HTML5 支持的类型。 |
placeholder |
string |
当字段没有值时显示的占位符。 | |
title |
string |
鼠标悬停时显示的字段标题。 | |
classes |
string |
在面板中向控件包装器添加自定义类。 | |
default |
string |
字段的默认值。 |
Return Value
(string) The text field value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'widget_title',
[
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'default' => esc_html__( 'Default title', 'textdomain' ),
'placeholder' => esc_html__( 'Type your title here', 'textdomain' ),
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['widget_title'] ) ) {
return;
}
?>
<h2 class="title">
<?php echo $settings['widget_title']; ?>
</h2>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.widget_title ) {
return;
}
#>
<h2 class="title">
{{{ settings.widget_title }}}
</h2>
<?php
}
}
文本域控件
Elementor 文本域控件显示一个经典的多行文本输入框,并支持设置 rows(行数)属性。
该控件定义在继承 Base_Data_Control 类的 Control_Textarea 类中。
使用此控件时,应将 type 参数设置为 \Elementor\Controls_Manager::TEXTAREA 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
textarea | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
rows |
int |
5 | 行数。 |
placeholder |
string |
当字段没有值时显示的占位符。 | |
default |
string |
字段的默认值。 |
Return Value
(string) The textarea field value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'item_description',
[
'label' => esc_html__( 'Description', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXTAREA,
'rows' => 10,
'default' => esc_html__( 'Default description', 'textdomain' ),
'placeholder' => esc_html__( 'Type your description here', 'textdomain' ),
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['item_description'] ) ) {
return;
}
?>
<p class="description">
<?php echo $settings['item_description']; ?>
</p>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.item_description ) {
return;
}
#>
<p class="description">
{{{ settings.item_description }}}
</p>
<?php
}
}
控件类型
Elementor 开箱即用,包含了种类繁多的控件。每个控件都有一个自定义模板以及可选的默认设置、默认值和其他影响控件在面板中输出的方法。
基础控件
Elementor 有几个扩展自抽象基类的基础控件,每个都用于不同的目的:
- 数据控件 – 返回单个值的控件。
- 多值控件 – 返回多个值的控件。
- 单位控件 – 返回基于单位的值的控件。
- UI 控件 – 仅在面板中可见且不返回值的 UI 元素。
- 组控件 – 将多个控件组合在一起。
继承关系
在底层,上述抽象基类是通过扩展 \Elementor\Base_Control 抽象类创建的,并继承了其属性和方法。您在编辑器中看到的所有其他控件都扩展自这些基础控件。
Base_Control
|
├─ Base_Data_Control
| ├─ ...
| └─ ...
|
├─ Control_Base_Multiple
| ├─ ...
| └─ ...
|
├─ Control_Base_Units
| ├─ ...
| └─ ...
|
├─ Base_UI_Control
| ├─ ...
| └─ ...
|
└─ Group_Control_Base
├─ ...
└─ ...
扩展控件
扩展数据控件
要创建您自己的数据控件,您需要扩展 \Elementor\Base_Data_Control 抽象类:
class Elementor_Test_Control extends \Elementor\Base_Data_Control {
}
扩展多值控件
要创建您自己的多值控件,您需要扩展 \Elementor\Control_Base_Multiple 抽象类:
class Elementor_Test_Control extends \Elementor\Control_Base_Multiple {
}
扩展单位控件
要创建您自己的单位控件,您需要扩展 \Elementor\Control_Base_Units 抽象类:
class Elementor_Test_Control extends \Elementor\Control_Base_Units {
}
扩展 UI 控件
要创建您自己的 UI 控件,您需要扩展 \Elementor\Base_UI_Control 抽象类:
class Elementor_Test_Control extends \Elementor\Base_UI_Control {
}
扩展组控件
要创建您自己的组控件,您需要扩展 \Elementor\Group_Control_Base 抽象类:
class Elementor_Test_Control extends \Elementor\Group_Control_Base {
}
URL 控件
Elementor URL 控件显示一个 URL 输入字段。该控件还能够显示更多控制选项,例如在新窗口中打开链接、添加 nofollow 属性以及定义额外属性(以逗号分隔的键值对列表)。
该控件在继承 Control_Base_Multiple 类的 Control_URL 类中定义。
使用此控件时,应将 type 设置为 \Elementor\Controls_Manager::URL 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
url | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 将分隔符定位在控件之前/之后。 |
placeholder |
string |
Paste URL or type | 当字段没有值时显示的占位符。 |
autocomplete |
bool |
true | 是否允许搜索功能。 |
options |
array|false |
[ 'url', 'is_external', 'nofollow', 'custom_attributes' ] |
要显示的 URL 选项数组。默认显示所有选项。但您可以选择显示哪些 URL 元素。将选项设置为 false 将禁用所有选项。 |
default |
array |
字段的默认值。
|
返回值
[
'url' => 'https://your-link.com',
'is_external' => true,
'nofollow' => true,
'custom_attributes' => '',
]
(array) 包含链接数据的数组:
- $url (
string) URL 地址。 - $is_external (
bool) 是否在新标签页中打开链接。 - $nofollow (
bool) 是否添加 nofollow 属性。 - $custom_attributes (
string) 自定义属性字符串,格式为逗号分隔的key|value键值对。
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'website_link',
[
'label' => esc_html__( 'Link', 'textdomain' ),
'type' => \Elementor\Controls_Manager::URL,
'options' => [ 'url', 'is_external', 'nofollow' ],
'default' => [
'url' => '',
'is_external' => true,
'nofollow' => true,
// 'custom_attributes' => '',
],
'label_block' => true,
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( ! empty( $settings['website_link']['url'] ) ) {
$this->add_link_attributes( 'website_link', $settings['website_link'] );
}
?>
<a <?php $this->print_render_attribute_string( 'website_link' ); ?>>
...
</a>
<?php
}
protected function content_template(): void {
?>
<a href="{{ settings.website_link.url }}">
...
</a>
<?php
}
}
视觉选择控件
Elementor 视觉选择控件将单选按钮显示为带图像的按钮组。
该控件定义在继承 Base_Data_Control 类的 Control_Visual_Choice 类中。
使用此控件时,type 应设置为 \Elementor\Controls_Manager::VISUAL_CHOICE 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
visual_choice | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
options |
array |
[] | 一个多维数组,包含每个单选按钮的 title 和 image。
|
columns |
number |
1 | 网格布局中的列数。 |
toggle |
bool |
true | 是否允许切换/取消选择。 |
default |
string |
字段的默认值。 |
Return Value
(string) The selected option value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'structure',
[
'label' => esc_html__( 'Structure', 'textdomain' ),
'type' => \Elementor\Controls_Manager::VISUAL_CHOICE,
'label_block' => true,
'options' => [
'grid-3' => [
'title' => esc_attr__( 'Grid: 3 columns.', 'textdomain' ),
'image' => plugins_url( 'assets/img/grid-3.svg', __FILE__ ),
],
'masonry' => [
'title' => esc_attr__( 'Masonry: arbitrary order', 'textdomain' ),
'image' => plugins_url( 'assets/img/masonry.svg', __FILE__ ),
],
'stacked' => [
'title' => esc_attr__( 'Stacked: Single column.', 'textdomain' ),
'image' => plugins_url( 'assets/img/stacked.svg', __FILE__ ),
],
'focus' => [
'title' => esc_attr__( 'Focus: Text only.', 'textdomain' ),
'image' => plugins_url( 'assets/img/focus.svg', __FILE__ ),
],
'grid-2' => [
'title' => esc_attr__( 'Grid: 2 columns.', 'textdomain' ),
'image' => plugins_url( 'assets/img/grid2.svg', __FILE__ ),
],
'stretch' => [
'title' => esc_attr__( 'Stretch: fit available width.', 'textdomain' ),
'image' => plugins_url( 'assets/img/stretch.svg', __FILE__ ),
]
],
'default' => 'masonry',
'columns' => 2,
'prefix_class' => 'some-layout-',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
WYSIWYG 控件
Elementor WYSIWYG 控件显示一个基于 TinyMCE 库的 WordPress 富文本编辑器。
该控件在继承 Base_Data_Control 类的 Control_Wysiwyg 类中定义。
使用此控件时,type 应设置为 \Elementor\Controls_Manager::WYSIWYG 常量。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
wysiwyg | 控件的类型。 |
label |
string |
显示在字段上方的标签。 | |
description |
string |
显示在字段下方的描述。 | |
show_label |
bool |
true | 是否显示标签。 |
label_block |
bool |
true | 是否在单独一行显示标签。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
default |
string |
字段的默认值。 |
Return Value
(string) The WYSIWYG field value.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'item_description',
[
'label' => esc_html__( 'Description', 'textdomain' ),
'type' => \Elementor\Controls_Manager::WYSIWYG,
'default' => esc_html__( 'Default description', 'textdomain' ),
'placeholder' => esc_html__( 'Type your description here', 'textdomain' ),
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['item_description'] ) ) {
return;
}
?>
<div class="description">
<?php echo $settings['item_description']; ?>
</div>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.item_description ) {
return;
}
#>
<div class="description">
{{{ settings.item_description }}}
</div>
<?php
}
}
动态内容
Elementor 可以使用动态标签替换控件输出,以编程方式生成内容。动态功能将静态控件转变为智能组件。这有助于用户将来自各种来源的定制化数据添加到他们的网站。让我们看看如何设置。
动态参数
使用 dynamic 参数通过 Elementor 控件设置动态标签:
$this->add_control(
'unique-control-name',
[
'label' => esc_html__( 'Control Label', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'dynamic' => [
'active' => true,
],
]
);
当控件支持动态标签时,会添加一个额外的图标,向用户表明他们可以用任何动态标签替换内容。
动态示例
让我们看看一个简单的控件如何变为动态:
$this->add_control(
'heading',
[
'label' => esc_html__( 'Heading', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => esc_html__( 'Enter your heading', 'textdomain' ),
'label_block' => true,
'dynamic' => [
'active' => true,
],
]
);
$this->add_control(
'content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXTAREA,
'placeholder' => esc_html__( 'Enter your content', 'textdomain' ),
'dynamic' => [
'active' => true,
],
]
);
$this->add_control(
'count',
[
'label' => esc_html__( 'Count', 'textdomain' ),
'type' => \Elementor\Controls_Manager::NUMBER,
'default' => 0,
'min' => 0,
'max' => 100,
'step' => 1,
'dynamic' => [
'active' => true,
],
]
);
$this->add_control(
'url',
[
'label' => esc_html__( 'Link', 'textdomain' ),
'type' => \Elementor\Controls_Manager::URL,
'placeholder' => esc_html__( 'https://your-link.com', 'textdomain' ),
'dynamic' => [
'active' => true,
],
]
);
$this->add_control(
'image',
[
'label' => esc_html__( 'Choose Image', 'elementor' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'default' => [
'url' => \Elementor\Utils::get_placeholder_image_src(),
],
'dynamic' => [
'active' => true,
],
]
);
前端可用
在某些情况下,开发者需要在前端加载的小部件 JS 中使用控件值。例如,一个使用外部滑块库的 Elementor 小部件需要获取要显示的幻灯片数量,并将数据传递给前端库脚本。Elementor 允许开发者公开控件值以供前端使用。
前端可用参数
编辑器拥有数百个控件。在前端暴露所有控件可能导致性能问题。因此默认情况下,所有控件值在前端都不可用。开发者可以通过明确选择哪些控件数据将在前端可用,来覆盖此设置。这通过使用 frontend_available 参数实现。
$this->add_control(
'unique-control-name',
[
'label' => esc_html__( 'Control Label', 'textdomain' ),
'type' => \Elementor\Controls_Manager::NUMBER,
'default' => 100,
'frontend_available' => true,
]
);
默认情况下,frontend_available 设置为 false。开发者可以通过将其设置为 true 来覆盖此设置。
Fetch Control Data
Each widget can load custom script handlers which are loaded dynamically if the widget is used in the page.
<?php
/**
* Register Elementor test widget.
*
* Include widget file and register widget class.
*
* @since 1.0.0
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
* @return void
*/
function elementor_test_widget_registration( $widgets_manager ) {
require_once( __DIR__ . '/widgets/test-widget.php' );
$widgets_manager->register( new \Elementor_Test_Widget() );
}
add_action( 'elementor/widgets/register', 'elementor_test_widget_registration' );
/**
* Register Elementor test widget dependencies.
*
* Registers all the scripts and styles to be enqueued later.
*
* @since 1.0.0
* @return void
*/
function elementor_test_widget_dependencies() {
wp_register_script(
'test-widget-handler',
plugins_url( 'js/test-widget.js', __FILE__ ),
[ 'elementor-frontend' ] // Dependent on 'elementor-frontend' script.
);
}
add_action( 'wp_enqueue_scripts', 'elementor_test_widget_dependencies' );
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
/**
* Get widget name.
*
* Retrieve test widget name.
*
* @since 1.0.0
* @access public
* @return string Widget name.
*/
public function get_name(): string {
return 'test_widget';
}
/**
* Get widget title.
*
* Retrieve test widget title.
*
* @since 1.0.0
* @access public
* @return string Widget title.
*/
public function get_title(): string {
return esc_html__( 'Test Widget', 'textdomain' );
}
/**
* Get script dependencies.
*
* Retrieve the list of script dependencies the element requires.
*
* @since 1.9.0
* @access public
* @return array Element scripts dependencies.
*/
public function get_script_depends(): array {
return [ 'test-widget-handler' ];
}
/**
* Register widget controls.
*
* Add input fields to allow the user to customize the widget settings.
*
* @since 1.0.0
* @access protected
*/
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'some_number',
[
'label' => esc_html__( 'Some Number', 'textdomain' ),
'type' => \Elementor\Controls_Manager::NUMBER,
'default' => 100,
'frontend_available' => true,
]
);
$this->end_controls_section();
}
/**
* Render widget output on the frontend.
*
* Written in PHP and used to generate the final HTML.
*
* @since 1.0.0
* @access protected
*/
protected function render(): void {
?>
<div class="test-widget"></div>
<?php
}
/**
* Render widget output in the editor.
*
* Written as a Backbone JavaScript template and used to generate the live preview.
*
* @since 1.0.0
* @access protected
*/
protected function content_template(): void {
?>
<div class="test-widget"></div>
<?php
}
}
Please note that the widget's render() method does not display any output. We want to insert the data from the control using JS. To do that, we registered a JS script located in js/test-widget.js, using the get_style_depends() method.
Now, the widget JS handler class should extend the elementorModules.frontend.handlers.Base class. This base class acts as an "abstract" class, defining basic methods like onInit() and providing access to the exposed control data using getElementSettings().
/**
* Test Widget JS Handler Class
*/
class TestWidgetHandler extends elementorModules.frontend.handlers.Base {
/**
* Update Test Widget Content
*
* Custom method used by test-widget that inserts the control value using JS.
*/
updateTestWidgetContent() {
if ( ! this.contentWrapper ) {
const widgetUniqueSelector = `div[data-id="${this.getID()}"] .test-widget`;
this.contentWrapper = document.querySelector( widgetUniqueSelector );
}
this.contentWrapper.innerText = this.getElementSettings( 'some_number' );
}
/**
* On Init
*
* Runs when the widget is loaded and initialized in the frontend.
*/
onInit() {
this.updateTestWidgetContent();
}
/**
* On Element Change
*
* Runs every time a control value is changed by the user in the editor.
*
* @param {string} propertyName - The ID of the control that was changed.
*/
onElementChange( propertyName ) {
if ( 'some_number' === propertyName ) {
this.updateTestWidgetContent();
}
}
}
/**
* Register JS Handler for the Test Widget
*
* When Elementor frontend was initiated, and the widget is ready, register the widet
* JS handler.
*/
window.addEventListener( 'elementor/frontend/init', () => {
const addHandler = ( $element ) => {
elementorFrontend.elementsHandler.addHandler( TestWidgetHandler, { $element } );
};
elementorFrontend.hooks.addAction( 'frontend/element_ready/test_widget.default', addHandler );
} );
全局样式
Elementor 终端用户可通过站点设置面板设置全局样式。编辑器中的控制机制具备特殊功能,允许用户设置自定义样式或继承全局样式。下面我们来看看如何设置。
Global Argument
To set global styles with Elementor controls, use the global argument in any color or typography control:
$this->add_control(
'unique-control-name',
[
'label' => esc_html__( 'Control Label', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'global' => [
// ...
],
]
);
When setting a global argument for controls, the control has an additional globe icon which indicates to the end-user that they can either use one of the defined global styles or set a custom style.
可用全局样式
最终用户可在站点设置面板中定义网站的设计系统。Elementor 设计系统目前支持:
- 全局颜色
- 全局字体
Elementor 提供 4 种默认颜色和 4 套默认字体样式,用户可在此基础上添加自己的颜色和字体样式。
全局颜色
\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_SECONDARY\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_TEXT\Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_ACCENT
全局字体
\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_SECONDARY\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_TEXT\Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_ACCENT
全局示例
让我们看看控件如何从站点设计系统继承全局样式,这些样式在站点设置面板中定义:
$this->add_control(
'heading_color',
[
'label' => esc_html__( 'Heading Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .heading-class' => 'color: {{VALUE}};',
],
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY,
],
]
);
$this->add_control(
'sub_heading_color',
[
'label' => esc_html__( 'Sub Heading Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .sub-heading-class' => 'color: {{VALUE}};',
],
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_SECONDARY,
],
]
);
$this->add_control(
'content_color',
[
'label' => esc_html__( 'Content Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .content-class' => 'color: {{VALUE}};',
],
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_TEXT,
],
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'heading_typography',
'selector' => '{{WRAPPER}} .heading-class',
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY,
],
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'sub_heading_typography',
'selector' => '{{WRAPPER}} .sub_heading-class',
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_SECONDARY,
],
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'content_typography',
'selector' => '{{WRAPPER}} .content-class',
'global' => [
'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_TEXT,
],
]
);
总之,您可以设置控件是否可以从站点设计系统继承全局样式,如果可以,它将继承哪种类型的样式(主要、次要、文本或强调色)。
背景组控件
Elementor 背景组控件显示用于定义背景的输入字段,包括背景颜色、背景图像、背景渐变或背景视频。
该控件在继承 Group_Control_Base 类的 Group_Control_Background 类中定义。
使用此组控件时,type 应设置为 Group_Control_Background::get_type() 方法。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
background | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
types |
array |
要使用的特定背景类型。可用类型包括 classic、gradient、video 和 slideshow。默认为空数组,包含所有类型。 |
|
include |
array |
从组控件中包含特定的控件。示例:['image'] |
|
exclude |
array |
从组控件中排除某些控件。示例:['image'] |
|
fields_options |
array |
一个多维数组,包含覆盖控件设置的数据。 |
Return Value
(array) An array containing the background values.
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_group_control(
\Elementor\Group_Control_Background::get_type(),
[
'name' => 'background',
'types' => [ 'classic', 'gradient', 'video' ],
'selector' => '{{WRAPPER}} .your-class',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
注意事项
视频和幻灯片类型仅支持在分区/容器级别使用,不支持在小部件级别使用。
边框组控件
Elementor 边框组控件显示用于定义边框的输入字段,包括边框类型、边框宽度和边框颜色。
该控件在继承 Group_Control_Base 类的 Group_Control_Border 类中定义。
使用此组控件时,应将 type 设置为 Group_Control_Border::get_type() 方法。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
border | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
exclude |
array |
从组控件中排除某些控件。示例:[ 'color' ] |
返回值
(array) 包含边框值的数组。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_group_control(
\Elementor\Group_Control_Border::get_type(),
[
'name' => 'border',
'selector' => '{{WRAPPER}} .your-class',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
盒阴影分组控件
Elementor 盒阴影分组控件显示用于定义盒阴影的输入字段,包括水平阴影、垂直阴影、阴影模糊、阴影扩散、阴影颜色和阴影位置。
该控件在继承 Group_Control_Base 类的 Group_Control_Box_Shadow 类中定义。
使用此分组控件时,应将 type 设置为 Group_Control_Box_Shadow::get_type() 方法。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
box-shadow | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
exclude |
array |
从分组控件中排除某些控件。例如:['box_shadow_position'] |
返回值
(array) 包含盒阴影值的数组。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_group_control(
\Elementor\Group_Control_Box_Shadow::get_type(),
[
'name' => 'box_shadow',
'selector' => '{{WRAPPER}} .your-class',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
CSS 滤镜组控件
Elementor CSS 滤镜组控件显示滑块字段,用于定义不同 CSS 滤镜的值,包括模糊、亮度、对比度、饱和度或色调。
该控件在 Group_Control_Css_Filter 类中定义,该类继承自 Group_Control_Base 类。
使用此组控件时,type 应设置为 Group_Control_Typography::get_type() 方法。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
typography | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
exclude |
array |
从组控件中排除某些控件。示例:['saturate'] |
返回值
(array) 包含 CSS 滤镜值的数组。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_group_control(
\Elementor\Group_Control_Css_Filter::get_type(),
[
'name' => 'custom_css_filters',
'selector' => '{{WRAPPER}} .your-class',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
图像尺寸组控件
Elementor 图像尺寸组控件显示输入字段,用于定义默认图像尺寸(缩略图、中等、中等大、大)或自定义图像尺寸。
该控件在 Group_Control_Image_Size 类中定义,该类继承自 Group_Control_Base 类。
使用此组控件时,type 应设置为 Group_Control_Image_Size::get_type() 方法。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
image-size | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
include |
array |
要包含的图像尺寸。 | |
exclude |
array |
要排除的图像尺寸。 | |
default |
string |
默认的图像尺寸。 |
返回值
[
'{name}_size' => '',
'{name}_custom_dimension' => '',
]
(array) 包含图像尺寸值的数组。
- ${name}_size (
string) 图像尺寸。 - ${name}_custom_dimension (
string) 图像维度。
Usage
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'image',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'default' => [
'url' => \Elementor\Utils::get_placeholder_image_src(),
],
]
);
$this->add_group_control(
\Elementor\Group_Control_Image_Size::get_type(),
[
'name' => 'thumbnail', // Usage: `{name}_size` and `{name}_custom_dimension`, in this case `thumbnail_size` and `thumbnail_custom_dimension`.
'exclude' => [ 'custom' ],
'include' => [],
'default' => 'large',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
echo \Elementor\Group_Control_Image_Size::get_attachment_image_html( $settings, 'thumbnail', 'image' );
}
protected function content_template(): void {
?>
<#
const image = {
id: settings.image.id,
url: settings.image.url,
size: settings.thumbnail_size,
dimension: settings.thumbnail_custom_dimension,
model: view.getEditModel()
};
const image_url = elementor.imagesManager.getImageUrl( image );
#>
<img src="{{{ image_url }}}" />
<?php
}
}
文本阴影组控件
Elementor 文本阴影组控件显示用于定义文本阴影的输入字段,包括水平阴影、垂直阴影、阴影模糊和阴影颜色。
该控件在继承 Group_Control_Base 类的 Group_Control_Text_Shadow 类中定义。
使用此组控件时,type 应设置为 Group_Control_Text_Shadow::get_type() 方法。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
text-shadow | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
exclude |
array |
从组控件中排除某些控件。示例:['text_shadow'] |
返回值
(array) 包含文本阴影值的数组。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_group_control(
\Elementor\Group_Control_Text_Shadow::get_type(),
[
'name' => 'text_shadow',
'selector' => '{{WRAPPER}} .your-class',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
文本描边组控件
Elementor 文本描边组控件显示用于定义文本描边的输入字段,包括水平描边、垂直描边、描边模糊和描边颜色。
该控件在继承 Group_Control_Base 类的 Group_Control_Text_Stroke 类中定义。
使用此组控件时,应将 type 设置为 Group_Control_Text_Stroke::get_type() 方法。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
text-stroke | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 会将分隔符定位在控件之前/之后。 |
exclude |
array |
从组控件中排除某些控件。示例:['text_stroke'] |
返回值
(array) 包含文本描边值的数组。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_group_control(
\Elementor\Group_Control_Text_Stroke::get_type(),
[
'name' => 'text_stroke',
'selector' => '{{WRAPPER}} .your-class',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
排版组控件
Elementor 排版组控件显示用于定义内容排版的输入字段,包括字体大小、字体系列、字体粗细、文本转换、字体样式、行高和字母间距。
该控件在继承 Group_Control_Base 类的 Group_Control_Typography 类中定义。
使用此组控件时,type 应设置为 Group_Control_Typography::get_type() 方法。
参数
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type |
string |
typography | 控件的类型。 |
separator |
string |
default | 设置控件分隔符的位置。可用值为 default、before 和 after。default 将隐藏分隔符,除非控件类型有特定的分隔符设置。before / after 将分隔符定位在控件之前/之后。 |
exclude |
array |
从组控件中排除某些控件。例如:['font_style'] |
返回值
(array) 包含排版值的数组。
用法
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'content_typography',
'selector' => '{{WRAPPER}} .your-class',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<div class="your-class">
...
</div>
<?php
}
protected function content_template(): void {
?>
<div class="your-class">
...
</div>
<?php
}
}
说明
了解如何在您的排版控件上使用在站点设置面板中设置的全局字体。
组合控制
组合控制是一组具有相似功能的常规控件和响应式控件,它们被组合成一个单一控件(例如:排版控制、文本阴影控制、盒阴影控制)。要添加组合控件,我们使用 add_group_control() 方法。
分组控件结构
使用以下代码添加分组控件:
$this->add_group_control(
Group_Control_Class::get_type(),
[
'name' => 'control_name',
'label' => esc_html__( '内容', 'textdomain' ),
]
);
控制参数
每个控件包含以下关键参数:
- 组控件类型
(string)– 组控件的唯一名称。 - 组控件设置
(array)– 额外的控制参数。除基于控件类型的默认设置外,每个控件还有其专属的自定义设置。例如,"exclude" 设置可用于从组中排除某些内部控件。
示例
版式控制
当向 Elementor 小部件添加标题和自定义内容时,我们需要允许用户设计文本样式。我们可以使用 Group_Control_Typography 类中定义的版式控制来设置字体大小、字体系列、字体粗细、文本转换、字体样式、行高和字母间距。
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'title_typography',
'selector' => '{{WRAPPER}} .title',
]
);
$this->end_controls_section();
}
}
边框控制
边框控制与排版控制略有不同。它通过 Group_Control_Border 类来定义,用于设置边框类型、边框宽度和边框颜色:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_group_control(
\Elementor\Group_Control_Border::get_type(),
[
'name' => 'border',
'selector' => '{{WRAPPER}} .wrapper',
]
);
$this->end_controls_section();
}
}
Group Control Fields Options
Here's an advanced setup for changing inner controls inside the group control using fields_options:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls() {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_group_control(
\Elementor\Group_Control_Border::get_type(),
[
'name' => 'box_border',
'label' => esc_html__( 'Box Border', 'textdomain' ),
'fields_options' => [
'border' => [
'label' => esc_html__( 'Box Border Type', 'textdomain' ),
'default' => 'solid',
],
'width' => [
'label' => esc_html__( 'Box Border Width', 'textdomain' ),
'default' => [
'top' => '1',
'right' => '2',
'bottom' => '3',
'left' => '4',
'isLinked' => false,
],
],
'color' => [
'label' => esc_html__( 'Box Border Color', 'textdomain' ),
'default' => '#D4D4D4',
],
],
'selector' => '{{WRAPPER}} .some-box',
]
);
$this->end_controls_section();
}
}
Elementor 编辑器控件
Elementor 编辑器控件是用于构建界面的输入字段和UI 元素。控件允许用户自定义可用面板设置,并在预览中更改设计。
Elementor 开箱即用,提供了广泛的控件。它们被用于小部件和编辑器面板中,以收集用户数据并根据用户选择生成自定义输出。
我需要了解什么?
要掌握 Elementor 控件,你需要学习三个主要主题:
使用控件
了解更多可用的控件:
了解更多用于重新排列控件的包装器:
控件参数
了解更多如何自定义控件:
标签与描述
控件本质上是供用户填写数据的输入字段。每个控件可包含显示在字段上方的标签,以及显示在字段下方的简短描述。编辑器中的控件机制提供特殊参数,帮助开发者设置这些字段并为其定义样式。
基本参数
编辑器中的每个控件都接受以下参数:
$this->add_control(
'unique-control-name',
[
'type' => \Elementor\Controls_Manager::TEXT,
'label' => esc_html__( 'Control Label', 'textdomain' ),
'description' => esc_html__( 'Short control description.', 'textdomain' ),
'show_label' => false,
'label_block' => false,
'separator' => 'after'
]
);
| 名称 | 描述 |
|---|---|
type |
(string) 控件的类型。 |
label |
(string) 显示在字段前/上方的标签。 |
description |
(string) 显示在字段下方的描述。 |
show_label |
(bool) 是否显示标签。默认值为 true。 |
label_block |
(bool) 是否将标签显示在单独一行。默认值为 false。 |
separator |
(string) 设置控件分隔符的位置。可用值有:
default。 |
标签
控件标签代表编辑器中的字段标题。它是一个字符串,帮助用户理解控件代表什么。它也有助于使用屏幕阅读器或其他辅助技术的人。
$this->add_control(
'unique-control-name',
[
'type' => \Elementor\Controls_Manager::TEXT,
'label' => esc_html__( 'Control Label', 'textdomain' ),
]
);
标签块
控件的标签和输入字段并排显示在同一行。开发者可以选择以不同的方式设置控件样式,将它们上下堆叠,而不是并排显示。
$this->add_control(
'unique-control-name',
[
'type' => \Elementor\Controls_Manager::TEXT,
'label' => esc_html__( 'Control Label', 'textdomain' ),
'label_block' => true,
]
);
Show Label
By default all control labels are displayed in the editor. Developers can choose to hide label, leaving only the input field. Please note, for accessibility reasons, the label is not removed, it's only visually hidden.
$this->add_control(
'unique-control-name',
[
'type' => \Elementor\Controls_Manager::TEXT,
'label' => esc_html__( 'Control Label', 'textdomain' ),
'show_label' => false,
]
);
描述
控件描述是显示在字段下方的简单文本,为用户提供关于该控件的更多信息。无论标签和字段是显示在同一行还是上下堆叠,描述都会显示在单独的一行。
$this->add_control(
'unique-control-name',
[
'type' => \Elementor\Controls_Manager::TEXT,
'label' => esc_html__( 'Control Label', 'textdomain' ),
'description' => esc_html__( 'Short control description.', 'textdomain' ),
]
);
分隔符
设置控件分隔符的位置。可用值包括:
default:根据控件类型自动定位分隔符before/after:将分隔符置于控件前/后none:隐藏分隔符
此参数适用于在两个或更多控件之间进行分隔的场景。
常规控件
常规控件是基础构建模块,允许用户为不同类型的输入字段(文本、数字、颜色、图像、图标等)设置不同的值。常规控件通过 add_control() 方法添加。
常规控件结构
使用以下代码添加控件:
$this->add_control(
'control-name',
[
'label' => esc_html__( '标题', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
]
);
控制参数
每个控件包含以下关键参数:
- 控件名称
(string)– 代码中使用的唯一标识符。 - 控件设置
(array)– 额外的控制参数。每个控件除了基于控件类型的默认设置外,还有其专属的自定义设置。例如,文本控件有"占位符"设置,滑块有"范围"设置,颜色控件有"默认值"设置等。
示例
文本控件
在下面的示例中,我们将添加一个在 control_text 类中定义的简单文本控件,该控件允许用户保存一个简单的字符串。该控件将设置一个占位符:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'type' => \Elementor\Controls_Manager::TEXT,
'label' => esc_html__( 'Title', 'textdomain' ),
'placeholder' => esc_html__( 'Enter your title', 'textdomain' ),
]
);
$this->end_controls_section();
}
}
数字控件
在下面的示例中,我们将添加一个在 Control_Number 类中定义的简单数字控件,它将允许用户保存数字:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'size',
[
'type' => \Elementor\Controls_Manager::NUMBER,
'label' => esc_html__( 'Size', 'textdomain' ),
'placeholder' => '0',
'min' => 0,
'max' => 100,
'step' => 1,
'default' => 50,
]
);
$this->end_controls_section();
}
}
选择控件
另一个简单的例子是 Control_Select 类,它允许用户选择预定义的字段:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'open_lightbox',
[
'type' => \Elementor\Controls_Manager::SELECT,
'label' => esc_html__( 'Lightbox', 'textdomain' ),
'options' => [
'default' => esc_html__( 'Default', 'textdomain' ),
'yes' => esc_html__( 'Yes', 'textdomain' ),
'no' => esc_html__( 'No', 'textdomain' ),
],
'default' => 'no',
]
);
$this->end_controls_section();
}
}
选择控件
选择控件是下拉选择控件的改进版本。Control_Choose 类允许用户选择预定义的字段,但每个选项的组件都带有图标样式。
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'alignment',
[
'type' => \Elementor\Controls_Manager::CHOOSE,
'label' => esc_html__( 'Alignment', 'textdomain' ),
'options' => [
'left' => [
'title' => esc_html__( 'Left', 'textdomain' ),
'icon' => 'eicon-text-align-left',
],
'center' => [
'title' => esc_html__( 'Center', 'textdomain' ),
'icon' => 'eicon-text-align-center',
],
'right' => [
'title' => esc_html__( 'Right', 'textdomain' ),
'icon' => 'eicon-text-align-right',
],
],
'default' => 'center',
]
);
$this->end_controls_section();
}
}
滑块控件
另一个有用的控件是 Control_Slider,它显示一个可拖动的范围滑块:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'font_size',
[
'type' => \Elementor\Controls_Manager::SLIDER,
'label' => esc_html__( 'Size', 'textdomain' ),
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
'range' => [
'px' => [
'min' => 1,
'max' => 200,
],
],
'default' => [
'unit' => 'px',
'size' => 20,
],
]
);
$this->end_controls_section();
}
}
颜色控制
Control_Color 是较为流行的控件之一,它允许用户选择颜色:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'text_color',
[
'type' => \Elementor\Controls_Manager::COLOR,
'label' => esc_html__( 'Text Color', 'textdomain' ),
'default' => '#fefefe',
]
);
$this->end_controls_section();
}
}
媒体控件
最后,对于高级用户,您可以使用 Control_Media 从 WordPress 媒体库中选择图片:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'image',
[
'type' => \Elementor\Controls_Manager::MEDIA,
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'default' => [
'url' => \Elementor\Utils::get_placeholder_image_src(),
]
]
);
$this->end_controls_section();
}
}
响应式控件
响应式控件本质上是具备特殊功能的常规控件,允许用户为不同设备和屏幕尺寸设置不同的值。我们使用 add_responsive_control() 方法来添加响应式控件。
响应式控制结构
以下代码将添加一个新的响应式控制:
$this->add_responsive_control(
'control-name',
[
'label' => esc_html__( '间距', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SLIDER,
]
);
控制参数
每个控件包含以下关键参数:
- 控件名称
(string)– 代码中使用的唯一标识符。 - 控件设置
(array)– 额外的控制参数。每个控件除了基于控件类型的默认设置外,还有其自身的自定义设置。响应式控件还包含基于设备的额外设置,例如根据屏幕尺寸设置不同的默认值。
Examples
Responsive Slider
The regular slider control defined in Control_Slider adds a draggable range slider. To make it responsive, and allow the user to set different values based on the device, use the following code:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style Section', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_responsive_control(
'space_between',
[
'type' => \Elementor\Controls_Manager::SLIDER,
'label' => esc_html__( 'Spacing', 'textdomain' ),
'range' => [
'px' => [
'min' => 0,
'max' => 100,
],
],
'devices' => [ 'desktop', 'tablet', 'mobile' ],
'default' => [
'size' => 30,
'unit' => 'px',
],
'tablet_default' => [
'size' => 20,
'unit' => 'px',
],
'mobile_default' => [
'size' => 10,
'unit' => 'px',
],
'selectors' => [
'{{WRAPPER}} .widget-image' => 'margin-bottom: {{SIZE}}{{UNIT}};',
],
]
);
$this->end_controls_section();
}
}
Responsive Dimensions
Another handy control is the dimensions control, defined in Control_Dimensions. It adds input fields for top, right, bottom, left and includes the option to link the fields together. It’s usually used for margins, paddings and borders. With responsive dimensions, we can set different values based on the device:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style Section', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_responsive_control(
'title_padding',
[
'type' => \Elementor\Controls_Manager::DIMENSIONS,
'label' => esc_html__( 'Padding', 'textdomain' ),
'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
'selectors' => [
'{{WRAPPER}} .widget-title' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
],
]
);
$this->end_controls_section();
}
}
Responsive Choose
Finally, we are going to use the select/choose control, which is defined in Control_Choose. This will allow us to set custom alignments with responsive values, allowing users to set different alignments for different screen sizes.
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'style_section',
[
'label' => esc_html__( 'Style Section', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_responsive_control(
'content_align',
[
'type' => \Elementor\Controls_Manager::CHOOSE,
'label' => esc_html__( 'Alignment', 'textdomain' ),
'options' => [
'left' => [
'title' => esc_html__( 'Left', 'textdomain' ),
'icon' => 'eicon-text-align-left',
],
'center' => [
'title' => esc_html__( 'Center', 'textdomain' ),
'icon' => 'eicon-text-align-center',
],
'right' => [
'title' => esc_html__( 'Right', 'textdomain' ),
'icon' => 'eicon-text-align-right',
],
],
'devices' => [ 'desktop', 'tablet' ],
'prefix_class' => 'content-align-%s',
]
);
$this->end_controls_section();
}
}
选择器字典
在某些情况下,您可能需要更新特定控件的值。但这样做可能会破坏现有网站,因为这些网站将旧值存储在数据库中。针对这些情况,Elementor 提供了一个字典,帮助开发者在代码使用前将旧值转换为新值。
选择器字典参数
使用 selectors_dictionary 参数将旧值替换为新值。
$this->add_control(
'text-align',
[
'label' => esc_html__( 'Control Label', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SELECT,
'selectors_dictionary' => [
'old-value-1' => 'new-value-1',
'old-value-2' => 'new-value-2',
],
]
);
选择器字典示例
使用选择控件的字典
让我们看看如何更新控件值,并将控件从"物理 CSS 属性"迁移到"逻辑 CSS 属性"。我们希望将 text-align: right|center|left; 替换为 text-align: start|center|end;。
原始控件在数据库中保存了三个值之一 - right、center 或 left:
$this->add_control(
'text-align',
[
'label' => esc_html__( 'Alignment', 'textdomain' ),
'type' => \Elementor\Controls_Manager::CHOOSE,
'default' => 'center',
'options' => [
'left' => [
'title' => esc_html__( 'Left', 'textdomain' ),
'icon' => 'eicon-text-align-left',
],
'center' => [
'title' => esc_html__( 'Center', 'textdomain' ),
'icon' => 'eicon-text-align-center',
],
'right' => [
'title' => esc_html__( 'Right', 'textdomain' ),
'icon' => 'eicon-text-align-right',
],
],
'selectors' => [
'{{WRAPPER}} .some-class' => 'text-align: {{VALUE}};',
],
]
);
现在,我们希望将这些值替换为 start、center 或 end。但是,为了向后兼容,我们必须提供一个解决方案,考虑到数据库中保存的旧值。
我们可以使用 selectors_dictionary 来解决这个问题:
$this->add_control(
'text-align',
[
'label' => esc_html__( 'Alignment', 'textdomain' ),
'type' => \Elementor\Controls_Manager::CHOOSE,
'default' => 'center',
'options' => [
'end' => [
'title' => esc_html__( 'End', 'textdomain' ),
'icon' => 'eicon-text-align-' . ( is_rtl() ? 'right' : 'left' ),
],
'center' => [
'title' => esc_html__( 'Center', 'textdomain' ),
'icon' => 'eicon-text-align-center',
],
'start' => [
'title' => esc_html__( 'Start', 'textdomain' ),
'icon' => 'eicon-text-align-' . ( is_rtl() ? 'left' : 'right' ),
],
],
'selectors_dictionary' => [
'left' => is_rtl() ? 'end' : 'start',
'right' => is_rtl() ? 'start' : 'end',
],
'selectors' => [
'{{WRAPPER}} .some-class' => 'text-align: {{VALUE}};',
],
]
);
带选择控件的字典
让我们看看如何将 selectors_dictionary 与选择控件结合使用。在这个案例中,一个流行的插件曾使用前缀类来保存 border-style 值。该插件为每种边框样式类型定义了 5 个 CSS 类:
$this->add_control(
'border_style',
[
'label' => esc_html__( 'Border Style', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'' => esc_html__( 'Default', 'textdomain' ),
'1' => esc_html__( 'None', 'textdomain' ),
'2' => esc_html__( 'Solid', 'textdomain' ),
'3' => esc_html__( 'Double', 'textdomain' ),
'4' => esc_html__( 'Dotted', 'textdomain' ),
'5' => esc_html__( 'Dashed', 'textdomain' ),
],
'prefix_class' => 'border-style-',
]
);
为了解决这个问题,并移除所有不必要的 CSS 类,我们可以按如下方式使用 selectors_dictionary:
$this->add_control(
'border_style',
[
'label' => esc_html__( 'Border Style', 'textdomain' ),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'' => esc_html__( 'Default', 'textdomain' ),
'1' => esc_html__( 'None', 'textdomain' ),
'2' => esc_html__( 'Solid', 'textdomain' ),
'3' => esc_html__( 'Double', 'textdomain' ),
'4' => esc_html__( 'Dotted', 'textdomain' ),
'5' => esc_html__( 'Dashed', 'textdomain' ),
],
'selectors_dictionary' => [
'1' => 'none',
'2' => 'solid',
'3' => 'double',
'4' => 'dotted',
'5' => 'dashed',
],
'selectors' => [
'{{WRAPPER}}' => 'border-style: {{VALUE}};',
],
]
);
在这种情况下,用 selectors 替换 prefix_class 效率更高。此外,我们不会破坏向后兼容性。selectors_dictionary 有助于将旧值转换为新值。
注意事项
必须牢记:selectors_dictionary 参数仅适用于返回简单 string 值的控件。它不适用于多值控件、单位控件、分组控件或中继器,这些控件都返回 array 值。
CSS 选择器
为了将控件值转换为 CSS 样式,Elementor 对分组控件使用 selector 参数,对其他控件使用 selectors 参数。这两个参数定义了使用哪些 CSS 选择器以及将值设置到哪些 CSS 属性上。让我们看看它是如何工作的。
自定义样式表
当创建 WordPress 文章/页面时,系统会为其分配一个唯一的 id。Elementor 编辑器利用此 id,根据每个控件的用户数据为该页面生成高度特定的样式表。随后,每次页面加载时,Elementor 都会加载属于该特定页面的样式表。
样式表路径
样式表保存在 /elementor/css/ 文件夹中,该文件夹位于 WordPress 的 /uploads/ 文件夹内。文件本身可通过其 id 来识别。
https://example.com/wp-content/uploads/elementor/css/post-{id}.css
当页面加载时,Elementor 会自动加载对应的样式表,其中包含从该页面小部件使用的控件中获取的样式选项。
自定义 CSS
编辑器控件允许用户输入内容或样式数据。要将控件值转换为 CSS 样式,控件需告知编辑器需要创建 CSS。这通过指定 CSS 选择器、属性和值的列表来实现。
'selectors' => [
'.css-selectors' => 'css-property: css-value;',
],
Selector Arguments
Elementor has two selector arguments. The first is applied on group controls, the second on non-group controls. Both methods convert user data into a CSS style in a stylesheet.
Group Controls
To convert group control data to a specific CSS selector:
$this->add_group_control(
\Elementor\Group_Control_Background::get_type(),
[
'name' => 'background',
'selector' => '{{WRAPPER}} .css-selector',
]
);
$this->add_group_control(
\Elementor\Group_Control_Background::get_type(),
[
'name' => 'background_hover',
'selector' => '{{WRAPPER}}:hover .css-selector',
]
);
The selector argument is a string. It is passed to all the inner controls in the group popup. When using group controls without specifying the selector argument, Elementor will use { { WRAPPER } } as a fallback.
非分组控件
要将非分组控件数据转换为 CSS 选择器:
$this->add_control(
'unique-control-name',
[
'label' => esc_html__( 'Control Label', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .css-selector' => 'css-property: {{VALUE}};',
],
]
);
selectors 参数是一个 array。它可以接受单个或多个键值对。
选择器变体
在大多数情况下,单个选择器就足够了:
$this->add_control(
'text-color',
[
'label' => esc_html__( 'Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .custom-container' => 'color: {{VALUE}};',
],
]
);
选择器也可以用于在单个选择器中指定多个 CSS 属性:
$this->add_control(
'text-color',
[
'label' => esc_html__( 'Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .custom-container' => 'color: {{VALUE}}; border-color: {{VALUE}}; outline-color: {{VALUE}};',
],
]
);
或者在单个控件选择器中使用多个(逗号分隔的)CSS 选择器:
$this->add_control(
'text-color',
[
'label' => esc_html__( 'Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .custom-container .heading, {{WRAPPER}} .custom-container .content' => 'color: {{VALUE}};',
],
]
);
上面的代码可以写成多个选择器:
$this->add_control(
'text-color',
[
'label' => esc_html__( 'Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .custom-container .heading' => 'color: {{VALUE}};',
'{{WRAPPER}} .custom-container .content' => 'color: {{VALUE}};',
],
]
);
为了同时支持 LTR 和 RTL 网站,您可以根据书写方向指定不同的选择器值:
$this->add_control(
'gap-size',
[
'label' => esc_html__( 'Gap', 'textdomain' ),
'type' => \Elementor\Controls_Manager::NUMBER,
'selectors' => [
'body:not(.rtl) {{WRAPPER}} .custom-container' => 'padding-left: {{VALUE}}',
'body.rtl {{WRAPPER}} .custom-container' => 'padding-right: {{VALUE}}',
],
]
);
作用域样式
Elementor 提供了两种在部件内部特定元素上应用自定义 CSS 的方法。它使用 { { WRAPPER } } 或 { { ID } } 关键字来实现作用域样式。这两个关键字都放置在键值对的左侧。
元素包装器
当选择器中使用元素包装器变量时:
'selectors' => [
'{{WRAPPER}} .widget-container' => 'color: red;',
],
它会生成包含该部件实例选择器的 CSS:
.elementor-123 .elementor-element.elementor-element-1a2b3c4 .widget-container {
color: red;
}
如果省略部件包装器,样式将应用于页面上所有 .widget-container 类。使用包装器后,样式将仅应用于该部件的 .widget-container 类。这本质上是 Elementor 为特定部件实例创建作用域样式的方式。
元素 ID
当选择器中使用元素 ID 变量时:
'selectors' => [
'#elementor-element-{{ID}}' => 'color: red;',
],
它会生成包含该部件实例 ID 的 CSS:
#elementor-element-1a2b3c4 {
color: red;
}
元素 ID 变量有助于创建唯一元素,但当部件在页面上有多个实例时,这会带来问题。这是因为 id 属性在页面上应该是唯一的。因此,我们不鼓励外部开发者使用此技术。它仅在非常特定的用例中被 Elementor 内部使用。
控件值到 CSS 值的转换
每个控件返回不同的值类型,有些返回字符串,有些返回数组。因此你需要熟悉控件类型,这将帮助你理解如何正确地将它们转换为 CSS 值。
数据控件
所有数据控件都返回 string 类型。要将用户选择的值应用到样式中,我们需要将控件值插入到选择器参数中:
'selectors' => [
'{{WRAPPER}} .widget-container' => 'color: {{VALUE}};',
],
单位控制
滑块控件 返回一个包含尺寸和单位的 array([ 'size' => '', 'unit' => '' ]),要在选择器参数中使用此用户数据:
'selectors' => [
'{{WRAPPER}} .widget-container' => 'width: {{SIZE}}{{UNIT}};',
],
尺寸控制
尺寸控制 返回一个包含所有四个边和单位的 array ([ 'top' => '', 'right' => '', 'bottom' => '', 'left' => '', 'unit' => '', 'isLinked' => '' ]),以便在 selectors 参数中使用用户数据:
'selectors' => [
'{{WRAPPER}} .widget-container' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
],
URL 控件
URL 控件 返回一个包含 URL 和一些属性的 数组 ([ 'url' => '', 'is_external' => '', 'nofollow' => '', 'custom_attributes' => '' ]),以便在 selectors 参数中使用用户数据:
'selectors' => [
'{{WRAPPER}} .widget-container' => 'background-image: url( {{URL}} );',
],
媒体控制
媒体控件 返回一个包含媒体 ID 和 URL 的 array ([ 'id' => '', 'url' => '' ]),以便在选择器参数中使用用户数据:
'selectors' => [
'{{WRAPPER}} .widget-container' => 'background-image: url( {{URL}} );',
],
多值控件
其他多值控件会返回不同的 array 类型,但我们不对这些控件应用 CSS,因为它们被视为内容控件而非样式控件。
来自其他控件的值
在某些较少见的情况下,您可能需要多个样式控件来创建单个 CSS 属性。对于这些情况,Elementor 提供了在值前添加控件名称前缀的功能。此方法提供了从其他控件提取数据的方式。
简单示例
一个简单的示例是 aspect-ratio 场景,我们需要使用两个数字控件来设置一个 CSS 声明:
aspect-ratio: {{width}} / {{height}};
要实现这一点,你需要两个控件,以及一个利用这两个控件值的 selectors 参数:
$this->add_control(
'aspect-ratio-width',
[
'label' => esc_html__( '宽高比宽度', 'textdomain' ),
'type' => \Elementor\Controls_Manager::NUMBER,
]
);
$this->add_control(
'aspect-ratio-height',
[
'label' => esc_html__( '宽高比高度', 'textdomain' ),
'type' => \Elementor\Controls_Manager::NUMBER,
'selectors' => [
'{{WRAPPER}} .custom-container img' => 'aspect-ratio: {{aspect-ratio-width.VALUE}} / {{aspect-ratio-height.VALUE}};'
],
]
);
复杂示例
一个更复杂的示例是包含单个角度、多种颜色和停止位置的 linear-gradient():
background-image: linear-gradient(
{{angle}},
{{color1}} {{position1}},
{{color2}} {{position2}},
{{color3}} {{position3}}
);
在这种情况下,我们将允许您自行实现此功能,以便您进行练习。
使用控件
控件可以在 Elementor 小部件或 Elementor 面板中使用。最终用户使用控件来选择他们的数据。这些数据保存在数据库中,随后用于根据用户的选择生成自定义输出。
注册控件
在您的小部件类中,可以在 register_controls() 方法内添加控件,如下所示:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section();
$this->add_control();
$this->add_responsive_control();
$this->add_group_control();
$this->end_controls_section();
}
}
可用的控件类型
Elementor 有三种可以添加到小部件的控件类型:
Elementor 还有控件的 UI 包装器,可用于对控件进行分组和重新排列:
控件方法
Elementor 控件有一个用于注册设置字段的单一方法。控件的 UI 包装器有两个/四个方法来包装其他控件。
可用的方法:
- 常规控件 -
add_control() - 响应式控件 -
add_responsive_control() - 组控件 -
add_group_control() - 控件部分 -
start_controls_section()和end_controls_section() - 控件弹出框 -
start_popover()和end_popover() - 控件选项卡 -
start_controls_tabs()和end_controls_tabs()以及start_controls_tab()和end_controls_tab()
Add Items to an Existing Category
In some cases, developers would like to add new items to existing finder categories. You can do that using the elementor/finder/categories filter hook.
Add Items
In the example below, the developer is adding the theme-template item to the create category. This will allow users to easily add new theme templates:
public function add_new_finder_items( array $categories ) {
$categories['create']['items']['theme-template'] = [
'title' => esc_html__( 'Add New Theme Template', 'textdomain' ),
'icon' => 'plus-circle-o',
'url' => $this->get_admin_templates_url() . '#add_new',
'keywords' => [ 'template', 'theme', 'new', 'create' ],
];
return $categories;
}
add_filter( 'elementor/finder/categories', 'add_new_finder_items' );
The filter hook accepts the $categories parameter, which is basically an array of finder categories. We can filter categories from this array and return an updated array.
添加新的查找器项目
对于添加到查找器的每个新项目(链接),我们需要定义几个字段。这包括标签、URL、图标等。所有这些链接被分组在一个数组中并一起返回。
新建类别
查找器类别包含所有类别标签及其项目。
class New_Finder_Category extends \Elementor\Core\Common\Modules\Finder\Base_Category {
public function get_id(): string {
return 'my-category-name';
}
public function get_title(): string {
return esc_html__( 'Category Label', 'textdomain' );
}
public function get_category_items( array $options = [] ): array {
return [
'elementor-website' => [
'title' => esc_html__( 'Elementor', 'textdomain' ),
'icon' => 'elementor',
'url' => 'https://elementor.com/',
'keywords' => [ 'elementor', 'website' ],
],
'wordpress-website' => [
'title' => esc_html__( 'WordPress', 'textdomain' ),
'icon' => 'wordpress',
'url' => 'https://wordpress.org/',
'keywords' => [ 'wordpress', 'website' ],
],
];
}
}
每个项目必须包含以下属性:
- name – 用于定义
$items数组中的 ID(必需)。 - title – 用于定义向用户显示的标签(必需)。
- icon – 用于定义在标题/标签前显示的图标。
- url – 用于定义 URL(必需)。
- keywords – 用于定义相关的搜索关键词。
注册查找器类别
当查找器类别类准备就绪后,我们必须将其添加到类别管理器中。这是通过 elementor/finder/register 动作钩子完成的。
添加新类别时,我们需要提供类本身,代码如下:
function register_new_finder_category( $finder_categories_manager ) {
$finder_categories_manager->register( new New_Finder_Category() );
};
add_action( 'elementor/finder/register', 'register_new_finder_category' );
高级示例
针对更高级的用例,我们将用核心 WordPress 函数替换静态链接,以链接到 WordPress 仪表盘设置面板。
文件夹结构
该插件将包含两个文件:一个用于查找器分类的文件,以及一个用于注册类的主文件。
elementor-finder-wordpress-settings/
|
├─ finder/
| └─ wordpress-settings.php
|
└─ elementor-finder-wordpress-settings.php
Plugin Files
elementor-finder-wordpress-settings.php
<?php
/**
* Plugin Name: Elementor Finder WordPress Settings
* Description: Custom WordPress settings links in Elementor Finder.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-finder-wordpress-settings
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Add custom Finder categories.
*
* Include finder file and register the class.
*
* @since 1.0.0
* @param \Elementor\Core\Common\Modules\Finder\Categories_Manager $finder_categories_manager.
* @return void
*/
function elementor_finder_wordpress_settings( $finder_categories_manager ) {
require_once( __DIR__ . '/finder/wordpress-settings.php' );
$finder_categories_manager->register( new Elementor_Finder_WordPress_Settings() );
};
add_action( 'elementor/finder/register', 'elementor_finder_wordpress_settings' );
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Finder - WordPress Settings
*
* Provides searchable items related to WordPress settings.
*/
class Elementor_Finder_WordPress_Settings extends \Elementor\Core\Common\Modules\Finder\Base_Category {
/**
* Get finder category id.
*
* @since 1.0.0
* @access public
* @return string Finder category id.
*/
public function get_id(): string {
return 'wordpress-settings';
}
/**
* Get finder category title.
*
* @since 1.0.0
* @access public
* @return string Finder category title.
*/
public function get_title(): string {
return esc_html__( 'WordPress Settings', 'elementor-finder-wordpress-settings' );
}
/**
* Get finder category items.
*
* @since 1.0.0
* @access public
* @param array $options
* @return array An array of category items.
*/
public function get_category_items( array $options = [] ): array {
return [
'general' => [
'title' => esc_html__( 'General', 'elementor-finder-wordpress-settings' ),
'icon' => 'wordpress',
'url' => admin_url( 'options-general.php' ),
'keywords' => [ 'wordpress', 'dashboard', 'general', 'settings' ],
],
'writing' => [
'title' => esc_html__( 'Writing', 'elementor-finder-wordpress-settings' ),
'icon' => 'edit',
'url' => admin_url( 'options-writing.php' ),
'keywords' => [ 'wordpress', 'dashboard', 'writing', 'settings' ],
],
'reading' => [
'title' => esc_html__( 'Reading', 'elementor-finder-wordpress-settings' ),
'icon' => 'post-content',
'url' => admin_url( 'options-reading.php' ),
'keywords' => [ 'wordpress', 'dashboard', 'reading', 'settings' ],
],
'discussion' => [
'title' => esc_html__( 'Discussion', 'elementor-finder-wordpress-settings' ),
'icon' => 'comments',
'url' => admin_url( 'options-discussion.php' ),
'keywords' => [ 'wordpress', 'dashboard', 'discussion', 'settings' ],
],
'media' => [
'title' => esc_html__( 'Media', 'elementor-finder-wordpress-settings' ),
'icon' => 'image',
'url' => admin_url( 'options-media.php' ),
'keywords' => [ 'wordpress', 'dashboard', 'media', 'settings' ],
],
'permalink' => [
'title' => esc_html__( 'Permalink', 'elementor-finder-wordpress-settings' ),
'icon' => 'editor-link',
'url' => admin_url( 'options-permalink.php' ),
'keywords' => [ 'wordpress', 'dashboard', 'permalink', 'settings' ],
],
];
}
}
The Result
Finder 分类
查找器返回一组按分类组织的链接。每个分类包含指向网站不同部分的链接。对于用户输入的每个搜索词,查找器会根据相关的“关键词”过滤链接列表。
可用分类
默认情况下,查找器提供对以下链接组的快速访问:
- 创建 (
create) – 提供与创建新文章/页面/模板等相关的链接。 - 编辑 (
edit) – 提供与编辑文章/页面/模板等相关的链接。 - 常规 (
general) – 提供与 Elementor 相关的常规链接。 - 设置 (
settings) – 提供与 Elementor 设置相关的链接。 - 工具 (
tools) – 提供与 Elementor 工具相关的链接。 - 站点 (
site) – 提供与站点相关的链接。
Finder 钩子
Finder 分类有两个开发者可以使用的钩子:
elementor/finder/register动作 - 用于注册新的查找器分类。elementor/finder/categories过滤器 - 用于修改查找器分类数组。
Finder 结构
Finder 按类别组织,每个类别包含一组链接。
Finder 类
要编辑 Finder 的类别,我们首先需要创建一个继承 \Elementor\Core\Common\Modules\Finder\Base_Category 类(基础 Finder 类别类)的类:
class New_Finder_Category extends \Elementor\Core\Common\Modules\Finder\Base_Category {
}
Finder 方法
扩展类将包含以下方法:
class New_Finder_Category extends \Elementor\Core\Common\Modules\Finder\Base_Category {
public function get_id(): string {}
public function get_title(): string {}
public function get_category_items(): array {}
public function is_dynamic(): bool {}
}
-
类别 ID -
get_id()方法返回一个在代码中使用的唯一 ID。 -
类别标题 -
get_title()方法返回向用户显示的标签。 -
类别项 -
get_category_items()方法返回属于该类别的链接数组。 -
是否为动态 -
is_dynamic()方法是一个可选方法,返回布尔值。当类别项通过 Ajax 请求(如文章/页面标题)返回数据时使用。本文档不涵盖此方法。
Elementor Finder
Finder 组件会打开一个弹出式搜索栏,方便快捷地访问网站上的许多页面和设置。它可用于创建新文章、编辑其他页面、导航到不同的设置页面等。
Finder 结构
Finder 包含一个类别数组。每个类别包含多个项目。每个项目都包含一个标签、一个链接和一组关键词。当用户输入搜索词时,Finder 会根据相关的关键词筛选项目列表。
了解更多关于 finder 结构、其主类以及可用方法的信息。
扩展 Finder
外部开发者可以注册自己的自定义 Finder 类别及其自定义链接。了解更多:
代码示例
看看扩展 Finder 是多么容易:
移除查找器分类
开发者可以使用 elementor/finder/categories 过滤器钩子来移除整个查找器分类及其所有项目。
移除分类
在下面的示例中,我们将移除 "edit" 分类:
function remove_elementor_finder_category( array $categories ) {
unset( $categories['edit'] );
return $categories;
}
add_filter( 'elementor/finder/categories', 'remove_elementor_finder_category' );
该过滤器钩子接受 $categories 参数,它本质上是一个查找器分类数组。我们可以从这个数组中筛选分类,并返回更新后的数组。
移除查找器项目
开发者可以通过使用 elementor/finder/categories 过滤器钩子,从查找器类别中移除特定项目。
移除项目
在下面的示例中,我们将从 "create" 类别中移除 "post" 项目:
function remove_elementor_finder_item( array $categories ) {
unset( $categories['create']['items']['post'] );
return $categories;
}
add_filter( 'elementor/finder/categories', 'remove_elementor_finder_item' );
$categories 参数包含所有类别及其项目。我们可以移除特定项目并返回更新后的数组。
简单示例
为了展示扩展查找器是多么容易,我们将创建一个非常简单的查找器类别,其中包含指向社交媒体网站的静态链接。
文件夹结构
该插件将包含两个文件。一个用于查找器分类的文件,以及一个用于注册类的主文件。
elementor-finder-social-media/
|
├─ finder/
| └─ social-media.php
|
└─ elementor-finder-social-media.php
Plugin Files
elementor-finder-social-media.php
<?php
/**
* Plugin Name: Elementor Finder Social Media
* Description: Custom Social Media links in Elementor Finder.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-finder-social-media
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Add custom Finder categories.
*
* Include finder file and register the class.
*
* @since 1.0.0
* @param \Elementor\Core\Common\Modules\Finder\Categories_Manager $finder_categories_manager.
* @return void
*/
function elementor_finder_social_media( $finder_categories_manager ) {
require_once( __DIR__ . '/finder/social-media.php' );
$finder_categories_manager->register( new Elementor_Finder_Social_Media() );
};
add_action( 'elementor/finder/register', 'elementor_finder_social_media' );
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Finder - Social Media
*
* Provides searchable items to social media websites.
*/
class Elementor_Finder_Social_Media extends \Elementor\Core\Common\Modules\Finder\Base_Category {
/**
* Get finder category id.
*
* @since 1.0.0
* @access public
* @return string Finder category id.
*/
public function get_id(): string {
return 'social-media';
}
/**
* Get finder category title.
*
* @since 1.0.0
* @access public
* @return string Finder category title.
*/
public function get_title(): string {
return esc_html__( 'Social Media Websites', 'elementor-finder-social-media' );
}
/**
* Get finder category items.
*
* @since 1.0.0
* @access public
* @param array $options
* @return array An array of category items.
*/
public function get_category_items( array $options = [] ): array {
return [
'facebook' => [
'title' => esc_html__( 'Facebook', 'elementor-finder-social-media' ),
'icon' => 'facebook',
'url' => 'https://facebook.com/',
'keywords' => [ 'facebook', 'social', 'media' ],
],
'twitter' => [
'title' => esc_html__( 'Twitter', 'elementor-finder-social-media' ),
'icon' => 'twitter',
'url' => 'https://twitter.com/',
'keywords' => [ 'twitter', 'social', 'media' ],
],
'pinterest' => [
'title' => esc_html__( 'Pinterest', 'elementor-finder-social-media' ),
'icon' => 'pinterest',
'url' => 'https://www.pinterest.com/',
'keywords' => [ 'pinterest', 'social', 'media' ],
],
];
}
}
The Result
Action Controls
Each action can incorporate controls (setting fields), that allow users to select their data. When a user selects an action with these controls the control will be activated. Data entered into those fields is saved in the database and later used when triggering the action.
Registering Controls
In your action class, you can add controls using the register_settings_section() method as follows:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
protected function register_settings_section( $widget ): void {
$widget->start_controls_section();
$widget->add_control();
$widget->add_control();
$widget->add_control();
$widget->end_controls_section();
}
}
- Action Controls – The
register_settings_section()method lets you define which controls (setting fields) the action will have. The$widgetparameter is an instance of the form widget.
Add Controls to your Action
In the example below, we're going to add a few controls to the widget instance to allow users to save additional data:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function register_settings_section( $widget ): void {
$widget->start_controls_section(
'custom_action_section',
[
'label' => esc_html__( 'Custom Action', 'textdomain' ),
'condition' => [
'submit_actions' => $this->get_name(),
],
]
);
$widget->add_control(
'custom_action_api_key',
[
'label' => esc_html__( 'API Key', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
]
);
$widget->add_control(
'custom_action_app_id',
[
'label' => esc_html__( 'App ID', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
]
);
$widget->end_controls_section();
}
}
Please note that we recommend adding an entire setting section dedicated to your custom action.
In addition, you should only use conditional display, to show the section if the submit_action control in the form widget contains your custom action. This way, the entire section is displayed only when the user selects this particular action.
Action Data
每个操作都包含基本信息,例如唯一的操作 ID 和标签。这些数据在代码中使用,并在编辑器中显示给用户。
数据方法
操作数据需要通过特定方法“返回”。这些方法很简单:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function get_name(): string {
return 'action_name';
}
public function get_label(): string {
return esc_html__( 'My Action Name', 'textdomain' );
}
}
-
操作名称 -
get_name()方法返回操作名称(ID),它将在代码中使用。 -
操作标签 -
get_label()方法返回操作标签,它将在编辑器中显示给用户。
导出时的处理
最佳实践是在导出 Elementor 数据时排除操作设置。如果你的表单操作添加了一些设置(操作控件),则不应导出它们。
导出方法
用于从导出过程中排除数据的方法称为 on_export()。此方法可用于在导出时排除操作数据。
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function on_export( $element ): array {
return $element;
}
}
- 导出时 -
on_export()方法用于在导出时清除设置。$element参数是一个包含导出元素数据的数组。
排除设置
在以下示例中,我们将注册一个包含两个控件的新部分——一个 API 密钥和一个应用 ID。然后我们将它们从导出的数据中排除:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function register_settings_section( $widget ): void {
$widget->start_controls_section(
'custom_action_section',
[
'label' => esc_html__( 'Custom Action', 'textdomain' ),
'condition' => [
'submit_actions' => $this->get_name(),
],
]
);
$widget->add_control(
'custom_action_api_key',
[
'label' => esc_html__( 'API Key', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
]
);
$widget->add_control(
'custom_action_app_id',
[
'label' => esc_html__( 'App ID', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
]
);
$widget->end_controls_section();
}
public function on_export( $element ): array {
unset(
$element['custom_action_api_key'],
$element['custom_action_app_id'],
);
return $element;
}
}
Action Run
表单提交时执行操作的实际方法。这是操作触发的主要方法。它可以使用来自自定义控件的可选数据,但这不是必需的。
Run 方法
触发操作的方法称为 run()。该方法仅在表单提交时执行。在你的操作类中,按如下方式使用该方法:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function run( $record, $ajax_handler ): void {
// ...
}
}
- 运行操作 -
run()方法在表单提交时触发实际的操作。$record参数是一个表单记录实例,$ajax_handler是表单 ajax 处理程序的实例。
执行操作
开发者可以在表单提交时执行任何代码,可能性是无限的。让我们看一些例子。
发送电子邮件
在下面的例子中,我们将在每次表单提交时发送一封电子邮件:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function run( $record, $ajax_handler ): void {
wp_mail( /* ... */ );
}
}
发送 HTTP 请求
在下面的例子中,我们将在每次表单提交时发送一个 HTTP 请求:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function run( $record, $ajax_handler ): void {
wp_remote_post( /* ... */ )
}
}
创建 WordPress 文章/页面/自定义文章类型
另一个用例是在每次表单提交后创建 WordPress 自定义文章类型:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function run( $record, $ajax_handler ): void {
wp_insert_post( /* ... */ );
}
}
Action Structure
Creating custom form actions, triggered after a form's submission, is not as hard as it sounds.
Each form action needs to have a few basic settings. First, it needs a unique name and a label that will be used in the editor. Next are the controls. These are basically optional fields where users can configure their custom data. The last setting is the actual method that executes the action once the form is submitted.
Form Action Class
First, we need to create a class that extends the \ElementorPro\Modules\Forms\Classes\Action_Base class:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
}
Form Action Structure
As mentioned above, an Elementor Form Action extends the \ElementorPro\Modules\Forms\Classes\Action_Base class and inherits its methods. A simple action skeleton will look as follows:
class Elementor_Test_Action extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public function get_name(): string {}
public function get_label(): string {}
public function register_settings_section( $widget ): void {}
public function run( $record, $ajax_handler ): void {}
public function on_export( $element ): array {}
}
Let’s break it down:
get_name()– Return action name (id) that will be used in the code.get_label()– Return the action label that will be displayed in the editor.register_settings_section()– (Optional) Define action controls (setting fields).run()– Runs the actual action on form submission.on_export()– Used to clear settings when exporting.
Add New Action
The form widget has several built-in actions, but external developers can create and register new form actions.
Registering Actions
To register new actions you simply need to initiate the action class:
function register_new_form_actions( $form_actions_registrar ) {
require_once( __DIR__ . '/forms/actions/action-1.php' );
require_once( __DIR__ . '/forms/actions/action-2.php' );
$form_actions_registrar->register( new \Action_1() );
$form_actions_registrar->register( new \Action_2() );
}
add_action( 'elementor_pro/forms/actions/register', 'register_new_form_actions' );
This hooks to the elementor_pro/forms/actions/register action hook, which holds the form registrar manager. The manager then registers the new actions by passing the action instances.
高级示例
我们将创建一个更高级的示例插件,该插件将使用 Sendy 的 API 向服务器添加新订阅者。
文件夹结构
该插件将包含两个文件。一个用于新的表单操作,另一个主文件用于注册操作并处理所有其他事项。
elementor-forms-sendy-action/
|
├─ form-actions/
| └─ sendy.php
|
└─ elementor-forms-sendy-action.php
Plugin Files
elementor-forms-sendy-action.php
<?php
/**
* Plugin Name: Elementor Forms Sendy Action
* Description: Custom addon which adds new subscriber to Sendy after form submission.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-forms-sendy-action
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Add new subscriber to Sendy.
*
* @since 1.0.0
* @param ElementorPro\Modules\Forms\Registrars\Form_Actions_Registrar $form_actions_registrar
* @return void
*/
function add_new_sendy_form_action( $form_actions_registrar ) {
include_once( __DIR__ . '/form-actions/sendy.php' );
$form_actions_registrar->register( new Sendy_Action_After_Submit() );
}
add_action( 'elementor_pro/forms/actions/register', 'add_new_sendy_form_action' );
form-actions/sendy.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor form Sendy action.
*
* Custom Elementor form action which adds new subscriber to Sendy after form submission.
*
* @since 1.0.0
*/
class Sendy_Action_After_Submit extends \ElementorPro\Modules\Forms\Classes\Action_Base {
/**
* Get action name.
*
* Retrieve Sendy action name.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_name(): string {
return 'sendy';
}
/**
* Get action label.
*
* Retrieve Sendy action label.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_label(): string {
return esc_html__( 'Sendy', 'elementor-forms-sendy-action' );
}
/**
* Register action controls.
*
* Add input fields to allow the user to customize the action settings.
*
* @since 1.0.0
* @access public
* @param \Elementor\Widget_Base $widget
*/
public function register_settings_section( $widget ): void {
$widget->start_controls_section(
'section_sendy',
[
'label' => esc_html__( 'Sendy', 'elementor-forms-sendy-action' ),
'condition' => [
'submit_actions' => $this->get_name(),
],
]
);
$widget->add_control(
'sendy_url',
[
'label' => esc_html__( 'Sendy URL', 'elementor-forms-sendy-action' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => 'https://your_sendy_installation/',
'description' => esc_html__( 'Enter the URL where you have Sendy installed.', 'elementor-forms-sendy-action' ),
]
);
$widget->add_control(
'sendy_list',
[
'label' => esc_html__( 'Sendy List ID', 'elementor-forms-sendy-action' ),
'type' => \Elementor\Controls_Manager::TEXT,
'description' => esc_html__( 'The list ID you want to subscribe a user to. This encrypted & hashed ID can be found under "View all lists" section.', 'elementor-forms-sendy-action' ),
]
);
$widget->add_control(
'sendy_email_field',
[
'label' => esc_html__( 'Email Field ID', 'elementor-forms-sendy-action' ),
'type' => \Elementor\Controls_Manager::TEXT,
]
);
$widget->add_control(
'sendy_name_field',
[
'label' => esc_html__( 'Name Field ID', 'elementor-forms-sendy-action' ),
'type' => \Elementor\Controls_Manager::TEXT,
]
);
$widget->end_controls_section();
}
/**
* Run action.
*
* Runs the Sendy action after form submission.
*
* @since 1.0.0
* @access public
* @param \ElementorPro\Modules\Forms\Classes\Form_Record $record
* @param \ElementorPro\Modules\Forms\Classes\Ajax_Handler $ajax_handler
*/
public function run( $record, $ajax_handler ): void {
$settings = $record->get( 'form_settings' );
// Make sure that there is a Sendy installation URL.
if ( empty( $settings['sendy_url'] ) ) {
return;
}
// Make sure that there is a Sendy list ID.
if ( empty( $settings['sendy_list'] ) ) {
return;
}
// Make sure that there is a Sendy email field ID (required by Sendy to subscribe users).
if ( empty( $settings['sendy_email_field'] ) ) {
return;
}
// Get submitted form data.
$raw_fields = $record->get( 'fields' );
// Normalize form data.
$fields = [];
foreach ( $raw_fields as $id => $field ) {
$fields[ $id ] = $field['value'];
}
// Make sure the user entered an email (required by Sendy to subscribe users).
if ( empty( $fields[ $settings['sendy_email_field'] ] ) ) {
return;
}
// Request data based on the param list at https://sendy.co/api
$sendy_data = [
'email' => $fields[ $settings['sendy_email_field'] ],
'list' => $settings['sendy_list'],
'ipaddress' => \ElementorPro\Core\Utils::get_client_ip(),
'referrer' => isset( $_POST['referrer'] ) ? $_POST['referrer'] : '',
];
// Add name if field is mapped.
if ( empty( $fields[ $settings['sendy_name_field'] ] ) ) {
$sendy_data['name'] = $fields[ $settings['sendy_name_field'] ];
}
// Send the request.
wp_remote_post(
$settings['sendy_url'] . 'subscribe',
[
'body' => $sendy_data,
]
);
}
/**
* On export.
*
* Clears Sendy form settings/fields when exporting.
*
* @since 1.0.0
* @access public
* @param array $element
*/
public function on_export( $element ): array {
unset(
$element['sendy_url'],
$element['sendy_list'],
$element['sendy_email_field'],
$element['sendy_name_field']
);
return $element;
}
}
结果
Elementor 表单小部件中新增的 "Sendy" 操作控件:
Elementor 表单操作
表单操作是访客提交数据后执行的任务。一个操作可以通过电子邮件发送表单数据、将其重定向到其他页面,或将数据发送到外部营销服务——可能性是无限的。
Elementor Pro 提供了一套工具来添加您自己的自定义操作。
操作
当用户向页面添加表单小部件时,他们可以选择访客提交表单后将执行的操作。选择一个操作会将其设置添加到一个独立的部分中。
可用操作
表单小部件默认包含以下操作:
- 收集提交
- 电子邮件
- 电子邮件 2
- 重定向
- Webhook
- MailChimp
- Drip
- ActiveCampaign
- GetResponse
- ConvertKit
- MailerLite
- Slack
- Discord
- 弹出窗口
管理表单操作
外部开发者可以注册新的表单操作。了解更多:
创建表单操作
了解更多关于操作的结构以及如何创建您自己的操作:
代码示例
看看添加新操作是多么容易:
简单示例
为了演示创建新表单操作是多么容易,我们将创建一个用于通知外部服务器的插件。
文件夹结构
该插件将包含两个文件。一个用于新表单操作的文件,以及一个主文件用于注册操作并处理所有其他事项。
elementor-forms-ping-action/
|
├─ form-actions/
| └─ ping.php
|
└─ elementor-forms-ping-action.php
Plugin Files
elementor-forms-ping-action.php
<?php
/**
* Plugin Name: Elementor Forms Ping Action
* Description: Custom addon which will ping an external server.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-forms-ping-action
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Add new form action after form submission.
*
* @since 1.0.0
* @param ElementorPro\Modules\Forms\Registrars\Form_Actions_Registrar $form_actions_registrar
* @return void
*/
function add_new_ping_action( $form_actions_registrar ) {
include_once( __DIR__ . '/form-actions/ping.php' );
$form_actions_registrar->register( new \Ping_Action_After_Submit() );
}
add_action( 'elementor_pro/forms/actions/register', 'add_new_ping_action' );
form-actions/ping.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor form ping action.
*
* Custom Elementor form action which will ping an external server.
*
* @since 1.0.0
*/
class Ping_Action_After_Submit extends \ElementorPro\Modules\Forms\Classes\Action_Base {
/**
* Get action name.
*
* Retrieve ping action name.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_name(): string {
return 'ping';
}
/**
* Get action label.
*
* Retrieve ping action label.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_label(): string {
return esc_html__( 'Ping', 'elementor-forms-ping-action' );
}
/**
* Run action.
*
* Ping an external server after form submission.
*
* @since 1.0.0
* @access public
* @param \ElementorPro\Modules\Forms\Classes\Form_Record $record
* @param \ElementorPro\Modules\Forms\Classes\Ajax_Handler $ajax_handler
*/
public function run( $record, $ajax_handler ): void {
wp_remote_post(
'https://api.example.com/',
[
'method' => 'GET',
'headers' => [
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'site' => get_home_url(),
'action' => 'Form submitted',
]),
'httpversion' => '1.0',
'timeout' => 60,
]
);
}
/**
* Register action controls.
*
* Ping action has no input fields to the form widget.
*
* @since 1.0.0
* @access public
* @param \Elementor\Widget_Base $widget
*/
public function register_settings_section( $widget ): void {}
/**
* On export.
*
* Ping action has no fields to clear when exporting.
*
* @since 1.0.0
* @access public
* @param array $element
*/
public function on_export( $element ): array {}
}
结果
在"提交后操作"部分新增的"Ping"操作:
Add New Field
The Form widget has built-in field types, but it also accepts new fields registered by external developers.
Registering Fields
To register new fields just initiate the field class:
function register_new_form_fields( $form_fields_registrar ) {
require_once( __DIR__ . '/forms/fields/field-1.php' );
require_once( __DIR__ . '/forms/fields/field-2.php' );
$form_fields_registrar->register( new \Field_1() );
$form_fields_registrar->register( new \Field_2() );
}
add_action( 'elementor_pro/forms/fields/register', 'register_new_form_fields' );
This hooks to the elementor_pro/forms/fields/register action hook which holds the form registrar manager. The manager then registers the new fields by passing the field instances.
高级示例
我们将创建一个包含信用卡字段的插件作为更高级的示例。
文件夹结构
该插件将包含两个文件。一个用于新字段类型的文件,以及一个主文件用于注册新字段并处理所有其他事项。
elementor-form-credit-card-number-field/
|
├─ form-fields/
| └─ credit-card-number.php
|
└─ elementor-form-credit-card-number-field.php
Plugin Files
elementor-form-credit-card-number-field.php
<?php
/**
* Plugin Name: Elementor Forms Credit Card Number Field
* Description: Custom addon that adds a "credit-card" field to Elementor Forms Widget.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-form-credit-card-number-field
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register `credit-card-number` field-type to Elementor form widget.
*
* @since 1.0.0
* @param \ElementorPro\Modules\Forms\Registrars\Form_Fields_Registrar $form_fields_registrar
* @return void
*/
function add_new_credit_card_number_field( $form_fields_registrar ) {
require_once( __DIR__ . '/form-fields/credit-card-number.php' );
$form_fields_registrar->register( new \Elementor_Credit_Card_Number_Field() );
}
add_action( 'elementor_pro/forms/fields/register', 'add_new_credit_card_number_field' );
form-fields/credit-card-number.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Form Field - Credit Card Number
*
* Add a new "Credit Card Number" field to Elementor form widget.
*
* @since 1.0.0
*/
class Elementor_Credit_Card_Number_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
/**
* Get field type.
*
* Retrieve credit card number field unique ID.
*
* @since 1.0.0
* @access public
* @return string Field type.
*/
public function get_type(): string {
return 'credit-card-number';
}
/**
* Get field name.
*
* Retrieve credit card number field label.
*
* @since 1.0.0
* @access public
* @return string Field name.
*/
public function get_name(): string {
return esc_html__( 'Credit Card Number', 'elementor-form-credit-card-number-field' );
}
/**
* Render field output on the frontend.
*
* Written in PHP and used to generate the final HTML.
*
* @since 1.0.0
* @access public
* @param mixed $item
* @param mixed $item_index
* @param mixed $form
* @return void
*/
public function render( $item, $item_index, $form ): void {
$form_id = $form->get_id();
$form->add_render_attribute(
'input' . $item_index,
[
'class' => 'elementor-field-textual',
'for' => $form_id . $item_index,
'type' => 'tel',
'inputmode' => 'numeric',
'maxlength' => '19',
'pattern' => '[0-9]{4}\s[0-9]{4}\s[0-9]{4}\s[0-9]{4}',
'placeholder' => $item['credit-card-placeholder'],
'autocomplete' => 'cc-number',
]
);
echo '<input ' . $form->get_render_attribute_string( 'input' . $item_index ) . '>';
}
/**
* Field validation.
*
* Validate credit card number field value to ensure it complies to certain rules.
*
* @since 1.0.0
* @access public
* @param \ElementorPro\Modules\Forms\Classes\Field_Base $field
* @param \ElementorPro\Modules\Forms\Classes\Form_Record $record
* @param \ElementorPro\Modules\Forms\Classes\Ajax_Handler $ajax_handler
* @return void
*/
public function validation( $field, $record, $ajax_handler ): void {
if ( empty( $field['value'] ) ) {
return;
}
if ( preg_match( '/^[0-9]{4}\s[0-9]{4}\s[0-9]{4}\s[0-9]{4}$/', $field['value'] ) !== 1 ) {
$ajax_handler->add_error(
$field['id'],
esc_html__( 'Credit card number must be in "XXXX XXXX XXXX XXXX" format.', 'elementor-form-credit-card-number-field' )
);
}
}
/**
* Update form widget controls.
*
* Add input fields to allow the user to customize the credit card number field.
*
* @since 1.0.0
* @access public
* @param \Elementor\Widget_Base $widget The form widget instance.
* @return void
*/
public function update_controls( $widget ): void {
$elementor = \ElementorPro\Plugin::elementor();
$control_data = $elementor->controls_manager->get_control_from_stack( $widget->get_unique_name(), 'form_fields' );
if ( is_wp_error( $control_data ) ) {
return;
}
$field_controls = [
'credit-card-placeholder' => [
'name' => 'credit-card-placeholder',
'label' => esc_html__( 'Card Placeholder', 'elementor-form-credit-card-number-field' ),
'type' => \Elementor\Controls_Manager::TEXT,
'default' => 'xxxx xxxx xxxx xxxx',
'dynamic' => [
'active' => true,
],
'condition' => [
'field_type' => $this->get_type(),
],
'tab' => 'content',
'inner_tab' => 'form_fields_content_tab',
'tabs_wrapper' => 'form_fields_tabs',
],
];
$control_data['fields'] = $this->inject_field_controls( $control_data['fields'], $field_controls );
$widget->update_control( 'form_fields', $control_data );
}
/**
* Field constructor.
*
* Used to add a script to the Elementor editor preview.
*
* @since 1.0.0
* @access public
* @return void
*/
public function __construct() {
parent::__construct();
add_action( 'elementor/preview/init', [ $this, 'editor_preview_footer' ] );
}
/**
* Elementor editor preview.
*
* Add a script to the footer of the editor preview screen.
*
* @since 1.0.0
* @access public
* @return void
*/
public function editor_preview_footer(): void {
add_action( 'wp_footer', [ $this, 'content_template_script' ] );
}
/**
* Content template script.
*
* Add content template alternative, to display the field in Elementor editor.
*
* @since 1.0.0
* @access public
* @return void
*/
public function content_template_script(): void {
?>
<script>
jQuery( document ).ready( () => {
elementor.hooks.addFilter(
'elementor_pro/forms/content_template/field/<?php echo $this->get_type(); ?>',
function ( inputField, item, i ) {
const fieldType = 'tel';
const fieldId = `form_field_${i}`;
const fieldClass = `elementor-field-textual elementor-field ${item.css_classes}`;
const inputmode = 'numeric';
const maxlength = '19';
const pattern = '[0-9\s]{19}';
const placeholder = item['credit-card-placeholder'];
const autocomplete = 'cc-number';
return `<input type="${fieldType}" id="${fieldId}" class="${fieldClass}" inputmode="${inputmode}" maxlength="${maxlength}" pattern="${pattern}" placeholder="${placeholder}" autocomplete="${autocomplete}">`;
}, 10, 3
);
});
</script>
<?php
}
}
The Result
The new "Credit Card Number" field inside the Elementor form widget:
字段内容模板
在渲染小部件时,我们有一个 PHP 模板和一个 JS 模板。然而,表单字段渲染只有 PHP 模板,没有 JS 模板。外部开发者可以使用一种变通方法来克服这个障碍。
渲染 JS 模板
以下代码是一个简单的变通方法,用于在 Elementor 编辑器中渲染 JS 模板。
<?php
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function __construct() {
parent::__construct();
add_action( 'elementor/preview/init', [ $this, 'editor_preview_footer' ] );
}
public function editor_preview_footer(): void {
add_action( 'wp_footer', [ $this, 'content_template_script' ] );
}
public function content_template_script(): void {
?>
<script>
jQuery( document ).ready( () => {
elementor.hooks.addFilter(
'elementor_pro/forms/content_template/field/<?php echo $this->get_type(); ?>',
function ( inputField, item, i ) {
const fieldType = 'text';
const fieldId = `form_field_${i}`;
const fieldClass = `elementor-field-textual elementor-field ${item.css_classes}`;
const title = "<?php echo esc_html__( 'Some text...', 'textdomain' ); ?>";
return `<input type="${fieldType}" id="${fieldId}" class="${fieldClass}" title="${title}">`;
}, 10, 3
);
});
</script>
<?php
}
}
::: warning 请注意
- 上述描述的变通方法是一个临时解决方案。
- 我们可能会引入一个官方的
content_template()方法来渲染 JS 模板,就像为 Elementor 小部件所做的那样。 - 为确保您的代码具有未来兼容性,请确保您的字段类没有名为
content_template()的方法。 :::
字段控件
表单字段可以拥有额外的控件,允许用户自定义表单字段。当字段被添加到表单时,这些控件将显示在字段设置中。输入到这些控件中的数据会被保存到数据库,之后可用于渲染字段输出或验证字段值。
注册控件
在您的字段类中,可以使用 update_controls() 方法添加控件,如下所示:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function update_controls( $widget ): void {
/* ... */
}
}
- 字段控件 –
update_controls()方法用于更新小部件控件,它允许开发者向特定字段类型添加新控件。$widget参数是表单小部件的一个实例。
向字段添加控件
在下面的示例中,我们将向小部件实例添加一些控件,以允许用户自定义表单字段:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function update_controls( $widget ): void {
$elementor = \ElementorPro\Plugin::elementor();
$control_data = $elementor->controls_manager->get_control_from_stack( $widget->get_unique_name(), 'form_fields' );
if ( is_wp_error( $control_data ) ) {
return;
}
$field_controls = [
'first-control' => [
'name' => 'first-control',
'label' => esc_html__( 'First Control', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'condition' => [
'field_type' => $this->get_type(),
],
'tab' => 'content',
'inner_tab' => 'form_fields_content_tab',
'tabs_wrapper' => 'form_fields_tabs',
],
'second-control' => [
'name' => 'second-control',
'label' => esc_html__( 'Second Control', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'condition' => [
'field_type' => $this->get_type(),
],
'tab' => 'content',
'inner_tab' => 'form_fields_content_tab',
'tabs_wrapper' => 'form_fields_tabs',
],
];
$control_data['fields'] = $this->inject_field_controls( $control_data['fields'], $field_controls );
$widget->update_control( 'form_fields', $control_data );
}
}
本质上,我们是在向表单小部件中注入新的字段控件。这些字段被注入到“字段重复器”中,用户在此处向表单添加字段。
$control_data 是表单小部件内部的字段重复器。此代码注入了新的字段,并设置了显示条件,使其仅在特定字段类型和字段内容选项卡中显示。
Field Data
Every field has basic information such as the field unique ID and the field label. This data is used in the code and displayed to the user in the editor.
Data Methods
Field data needs to be "returned" by certain methods. These methods are simple:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function get_type(): string {
return 'field_id';
}
public function get_name(): string {
return esc_html__( 'My Field Label', 'textdomain' );
}
}
-
Field Type – The
get_type()method returns the field id that will be used in the code. -
Field Name – The
get_name()method returns the field label that will be displayed to the user.
字段依赖关系
某些表单字段的功能依赖于自定义脚本,外观则依赖于自定义样式。让我们看看如何设置字段依赖关系。
依赖属性
在字段类内部,我们可以通过以下方式声明所需的任何 JS 或 CSS 依赖:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function get_script_depends(): array {
return [ 'script-handle' ];
}
public function get_style_depends(): array {
return [ 'style-handle' ];
}
}
-
字段脚本 –
get_script_depends()方法定义了显示字段所需的 JS 文件。 -
字段样式 –
get_style_depends()方法定义了显示字段所需的 CSS 文件。
在 WordPress 中注册脚本与样式
与其他 WordPress 插件一样,脚本和样式必须在插件的 PHP 文件中使用 wp_register_script() 和 wp_register_style() 函数进行注册。
你可以使用 wp_enqueue_scripts 钩子在前端页面注册脚本和样式。
Registering Scripts & Styles in Elementor
Elementor addon developers should register JS and CSS dependencies in the main file, usually where form fields are registered:
/**
* Register Elementor form fields.
*/
function elementor_test_field_registration( $form_fields_registrar ) {
require_once( __DIR__ . '/forms/fields/field-1.php' );
require_once( __DIR__ . '/forms/fields/field-2.php' );
$form_fields_registrar->register( new \Elementor_Test_Field_1() );
$form_fields_registrar->register( new \Elementor_Test_Field_2() );
}
add_action( 'elementor_pro/forms/fields/register', 'elementor_test_field_registration' );
/**
* Register scripts and styles for Elementor form fields.
*/
function elementor_test_field_dependencies() {
/* Scripts */
wp_register_script( 'field-script', plugins_url( 'assets/js/field-script.js', __FILE__ ) );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
/* Styles */
wp_register_style( 'field-style', plugins_url( 'assets/css/field-style.css', __FILE__ ) );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'elementor_test_field_dependencies' );
Then, each form field should set its dependencies as follows:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function get_script_depends(): array {
return [ 'field-script', 'external-library' ];
}
public function get_style_depends(): array {
return [ 'field-style', 'external-framework' ];
}
}
向后兼容性
在 Elementor 3.28 版本之前,依赖声明通过 $depended_scripts 和 $depended_styles 属性实现:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public $depended_scripts = [ 'script-handle' ];
public $depended_styles = [ 'style-handle' ];
}
如需支持 3.28 之前的 Elementor 版本,请将这些属性添加到表单字段类中,并配置所需的脚本/样式句柄。
字段渲染
表单中使用的字段需要在前端有输出。渲染方法用于设置字段在网站前端向用户显示时的代码。
渲染方法
实际生成字段输出的方法称为 render()。在你的字段类中,按如下方式使用此方法:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function render( $item, $item_index, $form ): void {
echo '<input type="text" class="elementor-test-field" title="Some text...">';
}
}
- 字段渲染 –
render()方法渲染数据并显示字段输出。
渲染属性
要以“Elementor 的方式”添加属性,不应将 HTML 元素与属性硬编码。应使用 add_render_attribute() 方法。此方法负责以编程方式定义属性及其值。
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function render( $item, $item_index, $form ): void {
$form->add_render_attribute(
'input' . $item_index,
[
'type' => 'text',
'class' => 'elementor-test-field',
'placeholder' => esc_html__( 'Some placeholder', 'textdomain' ),
]
);
echo '<input ' . $form->get_render_attribute_string( 'input' . $item_index ) . '>';
}
}
从字段控件获取数据
某些字段具有自定义控件,允许用户自定义字段。在表单小部件中显示用户数据的方式如下:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function render( $item, $item_index, $form ): void {
$form->add_render_attribute(
'textarea' . $item_index,
[
'class' => 'elementor-test-field',
'rows' => $item['textarea-rows'],
'cols' => $item['textarea-cols'],
]
);
echo '<textarea ' . $form->get_render_attribute_string( 'textarea' . $item_index ) . '></textarea>';
}
}
Field Structure
When creating new form fields we needs to have a few basic settings like a unique name and a label that will be used in the editor. Next is the render function that outputs the field markup. The field can also have a validation check. This last piece is an optional set of controls, where a user can configure their custom data.
Form Field Class
First, we need to create a class that extends the \ElementorPro\Modules\Forms\Fields\Field_Base class:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
}
Form Field Structure
As mentioned above, Elementor form fields extend the \ElementorPro\Modules\Forms\Fields\Field_Base class and inherit its methods. A simple field skeleton will look as follows:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function get_type(): string {}
public function get_name(): string {}
public function get_script_depends(): array {}
public function get_style_depends(): array {}
public function render( $item, $item_index, $form ): void {}
public function validation( $field, $record, $ajax_handler ): void {}
public function update_controls( $widget ): void {}
}
Let’s break it down:
-
Field Type – The
get_type()method returns the field name (id) that will be used in the code. -
Field Name – The
get_name()method returns the field label that will be displayed to the user. -
Field Scripts – The
get_script_depends()method defines the JS files required to display the field. -
Field Styles – The
get_style_depends()method defines the CSS files required to display the field. -
Field Render – The
render()method renders the data and displays the field output. -
Field Validation – The
validation()method runs a series of checks to ensure the data complies to certain rules. -
Field Controls – The
update_controls()method updates the widget controls, it allows developers to add new controls to specific field types.
Field Validation
Elementor offers the ability to run a series of checks to ensure that field data complies to a certain set of rules. The validating method checks if the field value is a valid value.
Validation Method
The method that triggers the validation process called validation(). This method makes sure the end-user entered a valid value by running a set of checks. If one of the checks fails, the method adds an error using $ajax_handler->add_error( $field, $message ).
When the form is submitted, Elementor checkes whether all the fields have valid values. Using the ajax handler, Elementor can add error messages to the fields that fail validation. If the field value is valid, the server will process the form submission. Otherwise, an ajax handler will be sent with the error message.
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function validation( $field, $record, $ajax_handler ): void {
if ( empty( $field['value'] ) ) {
return;
}
if ( (int) $field['value'] > 0 ) {
$ajax_handler->add_error(
$field['id'],
esc_html__( 'The field must contain a positive number.', 'textdomain' )
);
}
}
}
This method accepts three parameters. The $field parameter is an instance of the field itself. The $record parameter is an instance of the form record containing the user data. The $ajax_handler parameter is an instance of form ajax, responsible for handling the form ajax.
Field Controls
Some fields have custom controls that allow the user to customize the field. Developers can use user data from the form widget for validation as follows:
class Elementor_Test_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
public function validation( $field, $record, $ajax_handler ): void {
if ( empty( $field['value'] ) ) {
return;
}
if ( (int) $field['value'] > 0 ) {
$ajax_handler->add_error(
$field['id'],
esc_html__( 'The field must contain a positive number.', 'textdomain' )
);
}
if ( ( ! empty( $field['minimum'] ) ) && ( (int) $field['value'] > $field['minimum'] ) ) {
$ajax_handler->add_error(
$field['id'],
sprintf( esc_html__( 'The field must be greater than %s.', 'elementor-pro' ), $field['minimum'] )
);
}
}
}
In the example above, the field has a custom control called minimum where the user can set the minimum number. We have two validation checks to make sure the value is a positive number and its value is greater than the defined minimum number.
Elementor 表单字段
Elementor 表单小部件 是一个高级但易于使用的工具,用于创建网页表单。该小部件使得使用数十种字段类型来创建和设计任何表单变得轻而易举。
表单字段
当用户将表单小部件添加到页面时,他们可以选择在表单中显示哪些字段。
Elementor 使用 "Repeater" 控件允许用户向表单添加多个字段。对于每个字段,用户可以从可用字段列表中选择字段类型。
可用字段
表单小部件开箱即用,包含以下字段:
- 文本 (
text) - 电子邮件 (
email) - 文本域 (
textarea) - URL (
url) - 电话 (
tel) - 单选按钮 (
radio) - 选择框 (
select) - 复选框 (
checkbox) - 同意条款 (
acceptance) - 数字 (
number) - 日期 (
date) - 时间 (
time) - 文件上传 (
upload) - 密码 (
password) - HTML (
html) - 隐藏字段 (
hidden) - 步骤 (
step) - reCAPTCHA (
recaptcha) - reCAPTCHA V3 (
recaptcha_v3) - 蜜罐 (
honeypot)
管理表单字段
外部开发者可以注册新字段或注销现有字段。了解更多操作方法:
创建表单字段
外部开发者可以了解更多关于字段结构以及如何创建自己的字段:
代码示例
看看添加新字段是多么容易:
Remove Fields
To remove an existing field from the form widget we simply need to delete it from the list of available fields.
Hooks
To do that, we simply hook to the elementor_pro/forms/field_types filter. This filter holds the list of available fields as a parameter. Developers can change this list to match their needs.
Remove Fields
A good example is when you don't allow your users to create forms with "File Upload" fields, for security reasons. You can remove the upload field from the Elementor form widget with the following code:
/**
* Remove `upload` field from Elementor Form Widget.
*
* @param array $fields Elementor form fields.
* @return array Updated fields list.
*/
function remove_elementor_form_field( $fields ) {
unset( $fields['upload'] );
return $fields;
}
add_filter( 'elementor_pro/forms/field_types', 'remove_elementor_form_field' );
简单示例
为了展示扩展表单小部件的简易性,我们将创建一个插件,用于移除旧的 tel 字段并添加一个 local-tel 字段。
文件夹结构
该插件将包含两个文件。一个用于新字段类型,另一个主文件用于注册字段并处理所有其他事项。
elementor-form-local-tel-field/
|
├─ form-fields/
| └─ local-tel.php
|
└─ elementor-form-local-tel-field.php
Plugin Files
elementor-form-local-tel-field.php
<?php
/**
* Plugin Name: Elementor Forms Local Tel Field
* Description: Custom addon that adds a "local-tel" field to Elementor Forms Widget.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-form-local-tel-field
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Remove `tel` field from Elementor form widget.
*
* @since 1.0.0
* @param array $fields Elementor form fields.
* @return array Updated fields list.
*/
function remove_existing_form_field( $fields ) {
unset( $fields['tel'] );
return $fields;
}
add_filter( 'elementor_pro/forms/field_types', 'remove_existing_form_field' );
/**
* Add new `local-tel` field to Elementor form widget.
*
* @since 1.0.0
* @param \ElementorPro\Modules\Forms\Registrars\Form_Fields_Registrar $form_fields_registrar
* @return void
*/
function add_new_form_field( $form_fields_registrar ) {
require_once( __DIR__ . '/form-fields/local-tel.php' );
$form_fields_registrar->register( new \Elementor_Local_Tel_Field() );
}
add_action( 'elementor_pro/forms/fields/register', 'add_new_form_field' );
form-fields/local-tel.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Form Field - Local Tel
*
* Add a new "Local Tel" field to Elementor form widget.
*
* @since 1.0.0
*/
class Elementor_Local_Tel_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
/**
* Get field type.
*
* Retrieve local-tel field unique ID.
*
* @since 1.0.0
* @access public
* @return string Field type.
*/
public function get_type(): string {
return 'local-tel';
}
/**
* Get field name.
*
* Retrieve local-tel field label.
*
* @since 1.0.0
* @access public
* @return string Field name.
*/
public function get_name(): string {
return esc_html__( 'Local Tel', 'elementor-form-local-tel-field' );
}
/**
* Render field output on the frontend.
*
* Written in PHP and used to generate the final HTML.
*
* @since 1.0.0
* @access public
* @param mixed $item
* @param mixed $item_index
* @param mixed $form
* @return void
*/
public function render( $item, $item_index, $form ): void {
$form->add_render_attribute(
'input' . $item_index,
[
'size' => '1',
'class' => 'elementor-field-textual',
'pattern' => '[0-9]{3}-[0-9]{3}-[0-9]{4}',
'title' => esc_html__( 'Format: 123-456-7890', 'elementor-form-local-tel-field' ),
]
);
echo '<input ' . $form->get_render_attribute_string( 'input' . $item_index ) . '>';
}
/**
* Field validation.
*
* Validate local-tel field value to ensure it complies to certain rules.
*
* @since 1.0.0
* @access public
* @param \ElementorPro\Modules\Forms\Classes\Field_Base $field
* @param \ElementorPro\Modules\Forms\Classes\Form_Record $record
* @param \ElementorPro\Modules\Forms\Classes\Ajax_Handler $ajax_handler
* @return void
*/
public function validation( $field, $record, $ajax_handler ): void {
if ( empty( $field['value'] ) ) {
return;
}
if ( preg_match( '/^[0-9]{3}-[0-9]{3}-[0-9]{4}$/', $field['value'] ) !== 1 ) {
$ajax_handler->add_error(
$field['id'],
esc_html__( 'Phone number must be in "123-456-7890" format.', 'elementor-form-local-tel-field' )
);
}
}
/**
* Field constructor.
*
* Used to add a script to the Elementor editor preview.
*
* @since 1.0.0
* @access public
* @return void
*/
public function __construct() {
parent::__construct();
add_action( 'elementor/preview/init', [ $this, 'editor_preview_footer' ] );
}
/**
* Elementor editor preview.
*
* Add a script to the footer of the editor preview screen.
*
* @since 1.0.0
* @access public
* @return void
*/
public function editor_preview_footer(): void {
add_action( 'wp_footer', [ $this, 'content_template_script' ] );
}
/**
* Content template script.
*
* Add content template alternative, to display the field in Elementor editor.
*
* @since 1.0.0
* @access public
* @return void
*/
public function content_template_script(): void {
?>
<script>
jQuery( document ).ready( () => {
elementor.hooks.addFilter(
'elementor_pro/forms/content_template/field/<?php echo $this->get_type(); ?>',
function ( inputField, item, i ) {
const fieldId = `form_field_${i}`;
const fieldClass = `elementor-field-textual elementor-field ${item.css_classes}`;
const size = '1';
const pattern = '[0-9]{3}-[0-9]{3}-[0-9]{4}';
const title = "<?php echo esc_html__( 'Format: 123-456-7890', 'elementor-forms-local-tel-field' ); ?>";
return `<input id="${fieldId}" class="${fieldClass}" size="${size}" pattern="${pattern}" title="${title}">`;
}, 10, 3
);
});
</script>
<?php
}
}
The Result
The new "Local Tel" field inside the Elementor form widget:
What is an Elementor addon?
Before you start planning and developing your Elementor addon, it’s important to understand what addons are and how they fit into Elementor. Addons are a way third party developers can extend the Elementor’s functionality, add new features, integrate external services, customize workflow and more.
Addons in the Market
Some examples of addons currently available from the market:
- Collections of professionally designed templates.
- New toolkits that let users build dynamic architectures.
- Lead collection addons that send information from Elementor forms directly to the users’ CRM.
- Extensions that provide users with attractive and improved sliders for their sites.
- Visibility addons that let users hide or show different elements based on various criteria (dates, whether or not the visitor is logged in, etc.).
- Post widgets that allow users to customize the presentation of their content.
- Addons that integrate interactive elements.
Elementor Core vs. Addons
In essence, Elementor has developed into a strong framework. This framework, in turn, supports third party addons which serve to solve specific needs not answered by Elementor itself. While some developers developed niche features, others took it to the next level, reinventing existing elements and integrating new functionalities.
Addon Ideas
As you can see from the above list, the possibilities for creating new addons are almost endless. There are opportunities for developers to create advanced widgets, form integrations, dynamic tags, animations, extensions for lead collection, custom fonts and font icons, sophisticated sliders, mega menus, visibility functionality and more. Have your own idea for a cool addon? You can start here, by building your first addon.
最佳实践
这份最佳实践指南是面向 Elementor 扩展开发者的动态文档,将随着 Elementor 的更新、新功能的引入以及额外建议的提供而不断修订。我们建议遵循这些最佳实践。
支持的 PHP 版本
确保您的扩展兼容最常用的 PHP 版本 (v7.4) 以及最新的 PHP 版本 (v8.0 及以上)。
兼容性标签
Elementor 拥有自己的 头部注释,您可以在其中注明扩展所测试的 Elementor 版本。这是一个可选的头部信息,但我们建议使用它。
兼容性检查
检查网站使用的 Elementor 和 PHP 版本,以确保您的扩展支持该环境。否则,请通知用户网站不满足扩展的要求。
脚本与样式注册
Elementor 有其自己的 注册脚本和样式的方法。使用推荐的方法可以确保您的扩展针对性能进行了优化。
国际化
使用 WordPress 函数对您的字符串进行 国际化。
移除已弃用的代码
已经拥有一个扩展?请使用 Elementor 已弃用代码检测器 运行检查,查看您的扩展是否包含任何 已弃用的代码。如果是,我们强烈建议将其移除。您可以在此处查看 近期弃用列表。
采用最新的性能特性
实施 元素缓存 以将元素输出存储在缓存中,从而构建性能更高的网站。
Elementor Pro 开发者许可证
通过申请 开发者许可证 来使用 Elementor Pro 进行测试。
安全性
参与 Patchstack 免费的 mVDP 计划,通过清晰的漏洞报告结构来维护您产品的安全卫生状况。
Elementor 组件
Elementor 包含众多开发者可以修改的组件,以扩展 Elementor 的功能。本节列出了当前文档所涵盖的组件。
可用组件
以下是 Elementor 组件的列表,附有简短说明和更深入信息的链接:
-
Elementor 在小部件面板中包含数十个有用的小部件。开发者可以创建自己的小部件,引入 Elementor 目前不具备的高级功能。
-
Elementor 控件是用于构建界面的输入字段和 UI 元素。开发者可以自定义可用设置,并更改编辑器预览区域中的设计。
-
动态标签用于根据各种来源插入自定义数据。插件开发者可以创建广泛的动态标签,甚至可以使用外部 API 将数据拉取到 Elementor。
-
表单操作是访问者提交表单数据后执行的任务。一个操作可以通过电子邮件发送表单数据、重定向到不同页面或将数据发送到外部服务。
-
表单字段帮助用户使用 Elementor 表单小部件创建网页表单。插件开发者可以扩展数十种内置字段类型以添加新的字段类型。
-
主题构建器使用基于条件的机制来显示模板。该机制涵盖了原生的 WordPress 模板层次结构,但开发者可以添加额外的条件。
-
主题构建器将 Elementor 从页面构建器转变为完整的站点构建器。主题开发者可以通过主题位置使其主题“与 Elementor 兼容”。
-
在预览区域编辑元素时,右键单击元素可以访问可通过上下文菜单应用的操作。可以向这些上下文菜单添加自定义操作。
-
查找器可以轻松访问站点上的许多页面和设置。开发者可以扩展查找器,添加和删除项目及类别。
更多组件
随着 Elementor 的发展,我们将为更多组件添加文档。这是我们鼓励和支持第三方开发者的基本承诺的一部分。作为此过程的一部分,我们正在尽一切可能简化我们的代码库,使外部开发者更容易在 Elementor 基础设施中实现他们的想法。
创建您的首个扩展插件
让我们创建一个简单的 Elementor 扩展插件,为 Elementor 添加两个小部件。第一个将是简单的 "Hello World" 小部件,而第二个将与之类似,但功能有所增强。
插件文件夹结构
第一步将是注册这两个小部件。
插件应放置在您网站的 wp-content/plugins/ 文件夹中,文件夹结构如下所示:
elementor-addon/
|
├─ widgets/
| ├─ hello-world-widget-1.php
| └─ hello-world-widget-2.php
|
└─ elementor-addon.php
您可以将整个 elementor-addon 文件夹压缩,然后从“WordPress 仪表盘” > “插件”页面将 zip 文件上传到您的网站。
插件文件
这些小组件需要多个文件。主文件 elementor-addon.php 将用于注册小组件。hello-world-widget-1.php 和 hello-world-widget-2.php 文件将控制小组件的功能:
The Main Addon File
elementor-addon.php
<?php
/**
* Plugin Name: Elementor Addon
* Description: Simple hello world widgets for Elementor.
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-addon
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
function register_hello_world_widget( $widgets_manager ) {
require_once( __DIR__ . '/widgets/hello-world-widget-1.php' );
require_once( __DIR__ . '/widgets/hello-world-widget-2.php' );
$widgets_manager->register( new \Elementor_Hello_World_Widget_1() );
$widgets_manager->register( new \Elementor_Hello_World_Widget_2() );
}
add_action( 'elementor/widgets/register', 'register_hello_world_widget' );
Header comments are the standard way WordPress uses to provide information about plugins:
Elementor register new widgets with the widget registration function. Here, we will use the elementor/widgets/register lifecycle hook to run the register_hello_world_widget() function.
The function first loads the two widget files and then registers the widget classes using the widget manager. After running the code, the widget panel will display the two widgets:
第一个小部件
第一个小部件是 widgets/hello-world-widget-1.php。它非常简单,只是在屏幕上打印文本 "Hello World"。使用以下代码创建它:
<?php
class Elementor_Hello_World_Widget_1 extends \Elementor\Widget_Base {
public function get_name(): string {
return 'hello_world_widget_1';
}
public function get_title(): string {
return esc_html__( 'Hello World 1', 'elementor-addon' );
}
public function get_icon(): string {
return 'eicon-code';
}
public function get_categories(): array {
return [ 'basic' ];
}
public function get_keywords(): array {
return [ 'hello', 'world' ];
}
protected function render(): void {
?>
<p> Hello World </p>
<?php
}
protected function content_template(): void {
?>
<p> Hello World </p>
<?php
}
}
The Second Widget
The second widget is widgets/hello-world-widget-2.php. It creates two controls in the widget panel. One allows the user to enter their own text and style the text with a custom color (with "Hello World" being the default text). Create it using the following code:
<?php
class Elementor_Hello_World_Widget_2 extends \Elementor\Widget_Base {
public function get_name(): string {
return 'hello_world_widget_2';
}
public function get_title(): string {
return esc_html__( 'Hello World 2', 'elementor-addon' );
}
public function get_icon(): string {
return 'eicon-code';
}
public function get_categories(): array {
return [ 'basic' ];
}
public function get_keywords(): array {
return [ 'hello', 'world' ];
}
protected function register_controls(): void {
// Content Tab Start
$this->start_controls_section(
'section_title',
[
'label' => esc_html__( 'Title', 'elementor-addon' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'label' => esc_html__( 'Title', 'elementor-addon' ),
'type' => \Elementor\Controls_Manager::TEXTAREA,
'default' => esc_html__( 'Hello world', 'elementor-addon' ),
]
);
$this->end_controls_section();
// Content Tab End
// Style Tab Start
$this->start_controls_section(
'section_title_style',
[
'label' => esc_html__( 'Title', 'elementor-addon' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'title_color',
[
'label' => esc_html__( 'Text Color', 'elementor-addon' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .hello-world' => 'color: {{VALUE}};',
],
]
);
$this->end_controls_section();
// Style Tab End
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['title'] ) ) {
return;
}
?>
<p class="hello-world">
<?php echo $settings['title']; ?>
</p>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.title ) {
return;
}
#>
<p class="hello-world">
{{ settings.title }}
</p>
<?php
}
}
Now that you’ve seen how easy it is to create your first Elementor addon, it’s time to take advantage of the growing Elementor market and start working on your own cool ideas.
Continue reading more about Building Advanced Addons with best practices, coding standards and even more code examples.
什么是 Elementor?
Elementor 是终极的 WordPress 网站构建器,它让用户能够直观、专业地创建像素级完美的 WordPress 网站,而无需编写代码。同时,它提供了一个框架,允许开发者扩展其功能,为用户提供更多特性。Elementor 不仅使用起来极其简便,而且功能强大、灵活,让创作者能够在 Elementor 框架内实现复杂的设计和功能。
Elementor 版本
Elementor 提供不同版本:
Elementor Core 是一个免费的 WordPress 插件。它包含 Elementor 的核心功能,让用户能够通过具备拖放功能的图形用户界面来构建网站。
Elementor Pro 是一个付费版本,增加了许多免费版所不具备的高级功能和选项。它极大地丰富并改进了专业网页创作者可用的工具。
Elementor Beta Developer 是 Elementor Pro 插件的一个版本,面向开发者提供,让他们能够预览我们尚在开发中的最先进功能。该版本几乎每日更新,使开发者能在新功能公开发布前有时间熟悉它们。
除了这些版本,外部开发者还致力于创建 Elementor 扩展插件,为 Elementor 引入他们自己的功能,其中许多已被我们的用户广泛采用。
Elementor 的发展
目前已有超过 1300 万个活跃网站由 Elementor 驱动,对新解决方案的需求持续增长。网站创作者始终在寻找 Elementor 功能集范围之外的新颖、细分功能。
Elementor 生态圈
多年来,为满足这一需求,外部开发者已为 Elementor 创建了数百款自定义插件。这些插件随后被推广和销售给数百万 Elementor 用户,构成了不断壮大的 Elementor 生态圈。我们的文档旨在帮助您加入这个蓬勃发展的市场。
Elementor 社区
五年来,Elementor 始终自豪地为网站创作者提供最优质的页面与站点构建软件。
与此同时,Elementor 社区也激励着全球的外部开发者创建强大的扩展、精致的部件、将先进的 JavaScript 库与 Elementor 集成,并定制主题。所有这些都助力拓宽了 Elementor 的能力边界。
Elementor 的基础架构能够支持许多产品本身未包含的特性和功能。这种灵活性帮助 Elementor 成为最受欢迎的 WordPress 插件之一。您有机会加入这个快速发展的开发者与网站创作者社区,交流建议,并成长为一名专业的附加组件开发者。
Elementor 内部机制
Elementor 拥有底层技术,我们称之为内部机制。在本节中,我们将介绍开发 Elementor 插件时需要理解的概念。
可用的内部机制
以下是 Elementor 内部机制的列表,附有简短说明和深入信息的链接:
-
编辑器是用户创建页面和控制设置的地方。它分为预览区和面板区。面板承载小部件列表,是用户控制设置的地方。预览屏幕是他们查看页面外观的地方。
-
Elementor 的架构使用特殊的管理器来注册和注销元素。外部开发者需要使用这些管理器来注册自己的元素。这将让 Elementor 知道它们的存在,从而启用它们。
-
开发者需要了解不同的 Elementor 组件如何加载自定义 JS 和 CSS 文件。由于这些文件可能严重影响性能,学习为每个组件加载它们的正确方法非常重要。
-
Elementor 提供了广泛的钩子供使用。本文档包含了 Elementor 提供的所有可用钩子的完整列表——过滤器钩子、动作钩子、PHP 钩子、JS 钩子、前端钩子和编辑器钩子。
-
随着时间的推移,代码会被移除或替换。弃用过程是渐进的,Elementor 的弃用过程包含几个步骤。开发者需要了解 Elementor 如何弃用代码,以及他们如何调试和更新已弃用的代码。
-
Elementor 与 WP-CLI 集成,使开发者能够通过命令行界面运行某些 Elementor 任务,而无需使用 Web 浏览器。所有可用命令及其参数和使用示例都列在此处。
-
本节包含针对不熟悉 WordPress 的人员的信息。它讨论了基本的 WordPress 插件开发,以及 Elementor 插件和高级主题,包括插件和面向对象编程的背景信息。
要求
在开始工作之前,请确保您满足以下概述的要求。
服务器
要开始工作,您需要一个 WordPress 站点,最好是一个全新的 WordPress 安装(本地主机或暂存/开发环境)。您可以使用运行 WordPress 所需的基本服务器要求。
您的服务器应使用满足或超过 Elementor 要求 的 PHP 版本。
插件和主题
您的站点应安装 Elementor 插件 和 Hello 主题。如果您计划为 Elementor Pro 开发插件,则需要安装 Elementor Pro。
编程语言
我们还建议您具备 WordPress 插件开发 的实用知识,并熟悉 HTML、CSS、JavaScript 和 PHP。
文档网站
为了进一步支持和鼓励开发者社区,Elementor 创建了这个更新和修订后的文档中心,开发者可以在此访问详细的文档,清晰地了解 Elementor 的工作原理以及它为开发者提供的选项。
使用本文档
本网站包含的文档描述了 Elementor 的概念和组件、它们的工作原理以及如何修改它们。通过这些信息,您应该能够在短时间内创建自己的插件。
文档结构
顶部导航栏分为三个主要区域:
在描述 Elementor 组件的章节中,您经常会找到指导您如何创建自己插件的教程,逐步引导您完成每个步骤。您可以随意复制此代码,并根据您的需求进行修改。
通过代码示例学习
在每个主题的末尾,您会找到完整插件的代码示例,展示如何运用您在该主题中学到的知识来创建自己的插件。然后,您可以获取这些插件并将其复制到您自己的项目中使用,或作为创建原创插件的起点。
为文档做贡献
此文档平台使用基于 Markdown 页面(*.md 文件)构建的静态站点生成器。如果您发现错误或希望贡献和改进文档,请使用位于每个页面底部的“在 Github 上编辑此页面”链接。
当然,我们无法承诺实施您的所有建议。评论在添加到文档之前将经过审核流程。
Description Meta Tag
为了在不使用外部插件的情况下改善 SEO,主题会添加一个包含页面/文章摘要的 meta 标签。开发者可以通过一个简单的钩子来移除这个 meta 标签。
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
hello_elementor_add_description_meta_tag
该钩子会在具有摘要的单篇文章页面中,向 <head> 添加 HTML <meta> 标签:
<meta name="description" content="..." />
搜索引擎、社交媒体和其他外部网站会使用 <title> 和描述 <meta> 标签中的数据。
然而,如果网站选择使用外部 SEO 插件,页面可能会出现重复的描述 meta 标签。为了避免这种情况,SEO 插件可以移除由主题添加的描述 meta 标签。
使用方法
要阻止主题显示带有页面描述的 <meta> 标签,请使用以下代码:
function remove_hello_elementor_description_meta_tag() {
remove_action( 'wp_head', 'hello_elementor_add_description_meta_tag' );
}
add_action( 'after_setup_theme', 'remove_hello_elementor_description_meta_tag' );
Register Theme Features
The theme registers various WordPress theme features. Developers can override this using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_add_theme_support - Default Value:
true
The hook controls whether the theme should register various theme features. By default it's set to true, however developers can prevent the theme from registering various theme features.
Usage
To prevent the theme from registering various theme features, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_add_theme_support', '__return_false' );
To register custom theme features, use the WordPress native add_theme_support() function as follows:
add_theme_support( 'title-tag' );
add_theme_support( 'post-thumbnails' );
Register WooCommerce Features
The theme registers various WooCommerce theme features. Developers can override this using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_add_woocommerce_support - Default Value:
true
The hook controls whether the theme should register various WooCommerce features. By default it's set to true, however developers can prevent the theme from registering various WooCommerce features.
Usage
To prevent the theme from registering WooCommerce features, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_add_woocommerce_support', '__return_false' );
To register various WooCommerce theme features, use the WordPress native add_theme_support() function as follows:
add_theme_support( 'woocommerce' );
add_theme_support( 'wc-product-gallery-zoom' );
add_theme_support( 'wc-product-gallery-lightbox' );
add_theme_support( 'wc-product-gallery-slider' );
Content Width
The theme sets content width of 800 pixels. Developers can override this using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_content_width - Default Value:
800
The hook modifies the default content width set by the theme. By default it's set to 800 pixels, however developers can set different widths.
Usage
To set custom content width, use the following hook in a child-theme functions.php file:
function custom_hello_elementor_content_width() {
return 1024;
}
add_filter( 'hello_elementor_content_width', 'custom_hello_elementor_content_width' );
Enable Skip Link
The theme has a "Skip to content" link at the top of the page, it's used by screen readers to quickly navigate to the main content area. Developers can disable the skip link using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_enable_skip_link - Default Value:
true
The hook controls whether the theme should enable the "Skip to content" link. By default it's set to true, however developers can disable it.
Usage
To prevent the theme from displaying the "Skip to content" link for screen readers, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_enable_skip_link', '__return_false' );
Enqueue Styles
The theme loads the style.min.css file by default. Developers can override this using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_enqueue_style - Default Value:
true
The hook controls whether the theme should enqueue the style.min.css stylesheet. By default it's set to true, however developers can prevent the theme from enqueuing the file.
Usage
To prevent the theme from loading the style.min.css stylesheet, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_enqueue_style', '__return_false' );
Enqueue Theme Styles
The theme loads the theme.min.css file by default. Developers can override this using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_enqueue_theme_style - Default Value:
true
The hook controls whether the theme should enqueue the theme.min.css stylesheet. By default it's set to true, however developers can prevent the theme from enqueuing the file.
Usage
To prevent the theme from loading the theme.min.css stylesheet, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_enqueue_theme_style', '__return_false' );
Page Title
The theme displays the <h1> page title above the content area. Developers can override this using a filter hook in a child-theme. This is useful when using page builders to style the entire page, titles included.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_page_title - Default Value:
true
The hook controls whether the theme should display the <h1> page title above the content area. By default it's set to true, however developers can prevent the theme from displaying the page title.
Page builders, like Elementor, have the option to hide the title. In most cases it's done using CSS, but the HTML code remains. This hook removed the HTML from the page completely.
Usage
To prevent the theme from displaying the <h1> page title, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_page_title', '__return_false' );
Register Post Type Features
The theme registers a single post-type feature that adds excerpts to page. Developers can override this using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_post_type_support - Default Value:
true
The hook controls whether the theme should register various post-type supported features. By default it's set to true, however developers can prevent the theme from registering post-type features.
Usage
To prevent the theme from registering post-type features, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_post_type_support', '__return_false' );
To register custom post-type supported features, use the WordPress native add_post_type_support() function as follows:
add_post_type_support( 'my_post_type', 'comments' );
add_post_type_support( 'my_post_type', 'excerpt' );
Register Elementor Theme Locations
The theme registers Elementor theme locations. Developers can override this using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_register_elementor_locations - Default Value:
true
The hook controls whether the theme should register Elementor theme locations. By default it's set to true, however developers can prevent the theme from registering Elementor theme locations.
Usage
To prevent the theme from registering Elementor theme locations, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_register_elementor_locations', '__return_false' );
Register Navigation Menus
The theme registers two WordPress navigation menus, one for the header and the other footer. Developers can override this using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_register_menus - Default Value:
true
The hook controls whether the theme's navigation menus should be registered or not. By default it's set to true, however developers can prevent the theme from registering navigation menus.
Usage
To prevent the theme from registering the default navigation menus, use the following hook in a child-theme functions.php file:
add_filter( 'hello_elementor_register_menus', '__return_false' );
To register custom navigation menus, use the WordPress native register_nav_menus() function as follows:
register_nav_menus( [ 'my-header-menu' => esc_html__( 'Header Menu', 'textdomain' ) ] );
register_nav_menus( [ 'my-footer-menu' => esc_html__( 'Footer Menu', 'textdomain' ) ] );
register_nav_menus( [ 'my-mobile-menu' => esc_html__( 'Mobile Menu', 'textdomain' ) ] );
Skip Link URL
The theme has a "Skip to content" link at the top of the page, it's used by screen readers to quickly navigate to the main content area. Developers can modify the skip link URL using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_skip_link_url - Default Value:
#content
The hook controls the URL of the main content on the page. By default it links to #content, i.e. an element with a content ID.
Usage
To modify the skip link URL, use the following hook in a child-theme functions.php file:
function custom_hello_elementor_skip_link_url() {
return '#main';
}
add_filter( 'hello_elementor_skip_link_url', 'custom_hello_elementor_skip_link_url' );
For conditional URLs based on WordPress Template Hierarchy use the following hook:
function custom_hello_elementor_skip_link_url() {
if ( is_404() ) {
return '#404-content';
} else if ( is_page() ) {
return '#page-content';
} else if ( is_post() ) {
return '#post-content';
} else {
return '#main-content';
}
}
add_filter( 'hello_elementor_skip_link_url', 'custom_hello_elementor_skip_link_url' );
Viewport Content
The theme has a viewport meta tag, in the head, that controls the viewport's size and shape. Developers can modify the content attribute of the meta tag using a filter hook in a child-theme.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
hello_elementor_viewport_content - Default Value:
width=device-width, initial-scale=1
The hook controls the content of the viewport meta tag. By default the viewport width is set to the device-width and the initial scale is set to 1:
<meta name="viewport" content="width=device-width, initial-scale=1">
Usage
To modify the viewport content, use the following hook in a child-theme functions.php file:
function custom_hello_elementor_viewport_content() {
return 'width=100vw, height=100vh, user-scalable=no';
}
add_filter( 'hello_elementor_viewport_content', 'custom_hello_elementor_viewport_content' );
The result:
<meta name="viewport" content="width=100vw, height=100vh, user-scalable=no">
Hello Elementor 主题
Hello Elementor Theme 是一款轻量级、极简风格的 WordPress 主题,专为配合 Elementor 页面构建器插件而设计。该主题提供了多个功能,开发者可以通过 WordPress 钩子进行控制。
可用的过滤器钩子
该主题提供了多个过滤器钩子,可用于子主题的 functions.php 文件中,以修改默认设置。
功能钩子
样式钩子
内容钩子
自定义查询过滤器
文章小工具和作品集小工具都配备了强大的查询控件,可让您选择要在小工具中显示的特定文章。但有时,您需要对查询进行更多控制。针对这些情况,自定义查询过滤器应运而生,它公开了 WP_Query 对象,允许您以任意方式自定义查询。
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
elementor/query/{$query_id} - 影响范围: 查询
钩子参数
| 参数 | 类型 | 描述 |
|---|---|---|
query |
\WP_Query |
WordPress 查询实例。 |
widget |
\Elementor\Widget_Base |
小部件实例。 |
设置自定义筛选器
在文章或作品集小工具中,为您的查询设置一个ID,确保其唯一性,除非您希望筛选器在多个文章或作品集小工具上运行。
在以下示例中,查询ID设置为 my_custom_filter,因此当Elementor渲染小工具时,将基于该查询ID创建一个自定义筛选器:elementor/query/my_custom_filter。
Using the Custom Filter
After you have set up the custom query filter, you can use it to modify the query in the same way that the WordPress native pre_get_posts hook lets you modify a query. Using the custom query filter is just like any other WordPress native action hook:
/**
* Update the posts widget or portfolio widget query.
*
* @since 1.0.0
* @param \WP_Query $query The WordPress query instance.
*/
function custom_query_callback( $query ) {
// Modify the posts query here
}
add_action( 'elementor/query/{$query_id}', 'custom_query_callback' );
示例
在文章小工具中显示多种文章类型
使用以下代码片段在文章小工具中显示多种文章类型:
/**
* 更新查询以使用特定的文章类型。
*
* @since 1.0.0
* @param \WP_Query $query WordPress 查询实例。
*/
function my_query_by_post_types( $query ) {
$query->set( 'post_type', [ 'custom-post-type1', 'custom-post-type2' ] );
}
add_action( 'elementor/query/{$query_id}', 'my_query_by_post_types' );
Filter Posts by the Posts' Metadata in a Portfolio Widget
Use the code below to show posts with a metadata key filter in a portfolio widget:
/**
* Update the query by specific post meta.
*
* @since 1.0.0
* @param \WP_Query $query The WordPress query instance.
*/
function my_query_by_post_meta( $query ) {
// Get current meta Query
$meta_query = $query->get( 'meta_query' );
// If there is no meta query when this filter runs, it should be initialized as an empty array.
if ( ! $meta_query ) {
$meta_query = [];
}
// Append our meta query
$meta_query[] = [
'key' => 'project_type',
'value' => [ 'design', 'development' ],
'compare' => 'in',
];
$query->set( 'meta_query', $meta_query );
}
add_action( 'elementor/query/{$query_id}', 'my_query_by_post_meta' );
按评论数排序的帖子小工具中最受欢迎的文章
使用以下代码在帖子小工具中按评论数排序显示文章:
/**
* 按评论数对查询中的文章进行排序。
*
* @since 1.0.0
* @param \WP_Query $query WordPress 查询实例。
*/
function my_query_by_different_order( $query ) {
$query->set( 'orderby', 'comment_count' );
}
add_action( 'elementor/query/{$query_id}', 'my_query_by_different_order' );
在文章小部件中显示多种状态的文章
使用以下代码显示特定文章状态的文章:
注意:使用此代码片段可能导致显示私有数据,请谨慎使用。
/**
* 更新查询以使用特定的文章状态。
*
* @since 1.0.0
* @param \WP_Query $query WordPress 查询实例。
*/
function my_query_by_post_status( $query ) {
$query->set( 'post_status', [ 'future', 'draft'] );
}
add_action( 'elementor/query/{$query_id}', 'my_query_by_post_status' );
增加文章小工具中的文章数量
使用以下代码来更改文章小工具中显示的文章数量:
/**
* 更新查询以设置要显示的文章数量。
*
* @since 1.0.0
* @param \WP_Query $query WordPress 查询实例。
*/
function my_query_posts_per_page( $query ) {
$query->set( 'posts_per_page', 20 );
}
add_action( 'elementor/query/{$query_id}', 'my_query_posts_per_page' );
注意事项
您可能需要刷新编辑器才能看到滤镜效果。
Elementor 初始化
Elementor 提供了一个钩子,在插件完全加载时触发。
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
elementor/init - 影响范围: 初始化过程
示例
function my_plugin() {
// ...
}
add_action( 'elementor/init', 'my_plugin' );
Elementor 已加载
Elementor 有一个钩子,会在插件加载后、加载所有组件之前触发。
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
elementor/loaded - 影响范围: 初始化过程
示例
function my_plugin() {
// ...
}
add_action( 'elementor/loaded', 'my_plugin' );
Font Display
Elementor offers a filter hook that lets developers overwrite the "Custom Fonts" font-display value. In other words, you can control how font files are loaded and displayed by the browser.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
elementor_pro/custom_fonts/font_display - Affects: Frontend
Font Display
The CSS font-display property defines how font files are loaded and displayed by the browser and can be set with one of the following values:
- Default – The font display strategy is defined by the browser.
- Blocking – Hides the text until the font has fully loaded.
- Swap – Use a fallback-font to display, until the font has fully loaded.
- Fallback – Hides the text for a minimal period and will use the font only if loaded within a few seconds.
- Optional – Hides the text for a minimal period and will use the fallback-font unless the font is already fully loaded.
Applying Font Display
Google Fonts
It is possible to set the font-display value for "Google Fonts" from the WordPress admin. Simply go to Elementor → Settings → Advanced → Google Fonts Load.
Custom Fonts
In order to overwrite the font-display value for "Custom Fonts", the following actions should be applied:
Add the following filter in the Elementor Pro plugin folder:
/**
* Control how font files are loaded and displayed by the browser.
* Set the `font-display` property to `swap`.
*
* @since 1.0.0
*/
function update_font_display() {
return 'swap'; // Or any other value.
}
add_filter( 'elementor_pro/custom_fonts/font_display', 'update_font_display' );
To regenerate CSS files from the admin (the value will be changed only after regenerating, go to Elementor → Tools → General → Regenerate CSS.
表单验证
表单验证允许您运行一系列检查,以确保数据符合特定规则。Elementor Pro 提供了一套工具,用于验证通过表单小部件发送的数据。
验证生命周期
当表单模块加载完成且为包含表单操作的 POST 请求时,此处可添加表单验证处理器。
验证钩子
Elementor Pro 提供以下操作钩子来验证表单数据:
elementor_pro/forms/validationelementor_pro/forms/validation/{$field_type}
第一个钩子应用于所有字段,第二个钩子应用于特定的字段类型。
Examples
Validating email field:
function elementor_form_email_field_validation( $field, $record, $ajax_handler ) {
// Validate email format
if ( ! is_email( $field['value'] ) ) {
$ajax_handler->add_error( $field['id'], esc_html__( 'Invalid email address, it must be in xx@xx.xx format.', 'textdomain' ) );
return;
}
// Do your validation here.
}
add_action( 'elementor_pro/forms/validation/email', 'elementor_form_email_field_validation', 10, 3 );
Validate the Ticket ID field is in XXX-XXXX format:
function elementor_form_validation( $record, $ajax_handler ) {
$fields = $record->get_field( [
'id' => 'ticket_id',
] );
if ( empty( $fields ) ) {
return;
}
$field = current( $fields );
if ( 1 !== preg_match( '/^\w{3}-\w{4}$/', $field['value'] ) ) {
$ajax_handler->add_error( $field['id'], esc_html__( 'Invalid Ticket ID, it must be in XXX-XXXX format.', 'textdomain' ) );
}
}
add_action( 'elementor_pro/forms/validation', 'elementor_form_validation', 10, 2 );
Tel match this format XXX-XXX-XXXX, i.e. 123-456-7890
function elementor_form_tel_field_validation( $field, $record, $ajax_handler ) {
// Remove native validation
$forms_module = \ElementorPro\Plugin::instance()->modules_manager->get_modules( 'forms' );
remove_action( 'elementor_pro/forms/validation/tel', [ $forms_module->fields_registrar->get( 'tel' ), 'validation' ], 10, 3 );
// Run your own validation, ex:
if ( empty( $field['value'] ) ) {
return;
}
// Match this format XXX-XXX-XXXX, e.g. 123-456-7890
if ( preg_match( '/[0-9]{3}(-?)[0-9]{3}(-?)[0-9]{4}/', $field['value'] ) !== 1 ) {
$ajax_handler->add_error( $field['id'], esc_html__( 'Please make sure the phone number is in XXX-XXX-XXXX format, eg: 123-456-7890', 'textdomain' ) );
}
}
add_action( 'elementor_pro/forms/validation/tel', 'elementor_form_tel_field_validation', 10, 3 );
function elementor_form_tel_field_rendering( $item, $item_index, $form ) {
// Remove native render
$forms_module = \ElementorPro\Plugin::instance()->modules_manager->get_modules( 'forms' );
remove_action( 'elementor_pro/forms/render_field/tel', [ $forms_module->fields_registrar->get( 'tel' ), 'field_render' ], 10, 3 );
// Add custom render ex:
$form->add_render_attribute( 'input' . $item_index, 'class', 'elementor-field-textual' );
$form->add_render_attribute( 'input' . $item_index, 'pattern', '[0-9]{3}(-?)[0-9]{3}(-?)[0-9]{4}' );
$form->add_render_attribute( 'input' . $item_index, 'title', esc_html__( 'Number should be in this format xxx-xxx-xxxx.', 'textdomain' ) );
echo '<input size="1" ' . $form->get_render_attribute_string( 'input' . $item_index ) . '>';
}
add_action( 'elementor_pro/forms/render_field/tel', 'elementor_form_tel_field_rendering', 9, 3 );
Elementor Forms
::: danger This page will be deleted once all the content will be moved to individual pages inside Elementor Hooks. :::
Elementor Form Builder is an advanced Elementor Widget that allows users to create forms with the ultimate drag and drop visual form builder.
[[toc]]
概述
表单 API 是一组特定功能,允许开发者扩展 Elementor 表单功能。
外部开发者可以扩展表单小部件功能以满足自身需求。例如:以新方式验证数据、集成新的营销自动化工具和 CRM 服务、在保存或发送前修改收集的数据等。
表单钩子
Elementor Pro 为核心 Elementor 添加了新功能。表单 API 允许开发者过滤内容、验证数据、修改网络钩子、执行自定义代码等。
表单验证
elementor_pro/forms/validation
在表单模块加载后,并且这是一个包含表单操作的 POST 请求时。这是添加表单验证处理程序的地方。
Arguments
| Argument | Type | Description |
|---|---|---|
record |
Form_Record |
The record submitted. |
ajax_handler |
Ajax_Handler |
The Ajax Handler component. |
Example
// Validate the Ticket ID field is in XXX-XXXX format.
add_action( 'elementor_pro/forms/validation', function ( $record, $ajax_handler ) {
$fields = $record->get_field( [
'id' => 'ticket_id',
] );
if ( empty( $fields ) ) {
return;
}
$field = current( $fields );
if ( 1 !== preg_match( '/^\w{3}-\w{4}$/', $field['value'] ) ) {
$ajax_handler->add_error( $field['id'], 'Invalid Ticket ID, it must be in the format XXX-XXXX' );
}
}, 10, 2 );
elementor_pro/forms/validation/{$field_type}
在表单模块加载后,且为包含表单操作的 POST 请求时触发。此钩子允许开发者验证单个字段类型。
钩子名称的动态部分 $field_type 指代字段类型。
Arguments
| Argument | Type | Description |
|---|---|---|
field |
Array |
The submitted field. |
record |
Form_Record |
The record submitted. |
ajax_handler |
Ajax_Handler |
The Ajax Handler component. |
Example
// Validate the Tel field is in XXX-XXX-XXXX format.
add_action( 'elementor_pro/forms/validation/tel', function( $field, $record, $ajax_handler ) {
// Match this format XXX-XXX-XXXX, 123-456-7890
if ( preg_match( '/[0-9]{3}-[0-9]{3}-[0-9]{4}/', $field['value'] ) !== 1 ) {
$ajax_handler->add_error( $field['id'], 'Please make sure the phone number is in XXX-XXX-XXXX format, eg: 123-456-7890' );
}
}, 10, 3 );
表单处理
elementor_pro/forms/process
在表单字段验证和处理完成后触发。这是添加额外表单字段处理工作处理程序的地方。
Arguments
| Argument | Type | Description |
|---|---|---|
record |
Form_Record |
The record submitted. |
ajax_handler |
Ajax_Handler |
The Ajax Handler component. |
elementor_pro/forms/process/{$field_type}
在表单字段验证通过后,当处理单个表单字段时触发。这允许开发者处理特定的字段类型。
钩子名称的动态部分 $field_type 指代字段类型。
Arguments
| Argument | Type | Description |
|---|---|---|
field |
Array |
The submitted field. |
record |
Form_Record |
The record submitted. |
ajax_handler |
Ajax_Handler |
The Ajax Handler component. |
表单提交
elementor_pro/forms/form_submitted
在表单模块加载后,且为包含表单操作的 POST 请求时触发。此处用于添加表单处理器。
参数
| 参数 | 类型 | 描述 |
|---|---|---|
module |
ElementorPro\Modules\Forms |
当前页面/文章的完整 Elementor HTML 输出。 |
示例
add_action( 'elementor_pro/forms/form_submitted', function( $module ) {
$module->add_component( 'uploads_handler', new Uploads_Handler() );
} );
创建新记录
elementor_pro/forms/new_record
在表单操作运行后触发。此处用于添加自定义表单处理程序。
Arguments
| Argument | Type | Description |
|---|---|---|
record |
Form_Record |
The record submitted. |
ajax_handler |
Ajax_Handler |
The Ajax Handler component. |
Example
function send_custom_webhook( $record, $handler ) {
$form_name = $record->get_form_settings( 'form_name' );
// Replace MY_FORM_NAME with the name you gave your form
if ( 'MY_FORM_NAME' !== $form_name ) {
return;
}
$raw_fields = $record->get( 'fields' );
$fields = [];
foreach ( $raw_fields as $id => $field ) {
$fields[ $id ] = $field['value'];
}
wp_remote_post(
'https://api.example.com/',
[
'body' => $fields,
]
);
}
add_action( 'elementor_pro/forms/new_record', 'send_custom_webhook', 10, 2 );
表单 Webhooks 响应
elementor_pro/forms/webhooks/response
处理 Webhook 响应。
Arguments
| Argument | Type | Description |
|---|---|---|
response |
array/WP_Error |
The wp_remote_post response. See wp_remote_retrieve_response_message() function for more information |
record |
Form_Record |
The record submitted. |
表单邮件头过滤器
elementor_pro/forms/wp_mail_headers
参数
| 参数 | 类型 | 描述 |
|---|---|---|
headers |
string |
用于 wp_mail 参数的电子邮件头信息。 |
表单邮件消息过滤器
elementor_pro/forms/wp_mail_message
参数
| 参数 | 类型 | 描述 |
|---|---|---|
email_text |
string |
用于 wp_mail 参数的电子邮件 HTML 内容。 |
邮件发送成功后的操作
elementor_pro/forms/mail_sent
Arguments
| Argument | Type | Description |
|---|---|---|
settings |
array |
The form settings. |
record |
Form_Record |
The record submitted. |
Frontend Content
Elementor has a hook that filters frontend content. It is applied to the final HTML content, i.e., all the content Elementor displays on the page/post. Developers can change the HTML output before Elementor displays it to the end-user.
Hook Details
- Hook Type: Action Hook
- Hook Name:
elementor/frontend/the_content - Affects: Frontend
Hook Arguments
| Argument | Type | Description |
|---|---|---|
content |
string |
The entire Elementor HTML output of the current page/post |
Check Whether or Not to Display the Content
Membership addons can use this filter hook to check whether or not the user can see the page content:
/**
* Check whether the content is restricted by a membership
* plugin. If it does, show a restriction text.
*
* Otherwise, display the page content.
*
* @since 1.0.0
* @param string $content The content.
*/
function restrict_content_check( $content ) {
if ( ! membership_plugin_is_content_allowed() ) {
$content = esc_html__( 'Forbidden', 'textdomain' );
return;
}
return $content;
}
add_action( 'elementor/frontend/the_content', 'restrict_content_check' );
Elementor Hooks
Elementor has many interesting hooks that let developers change default settings and even extend Elementor with new functionality.
What are Hooks
A hook is a feature that allows developers to manipulate functionality without modifying core files. A hook can help developers inject some functions or edit default settings.
Action hooks are used to run custom code when certain events occur. Filter hooks are used to return modified values for certain parameters, based on different factors.
Elementor Hooks
Elementor has both filter hooks and action hooks. It also offers PHP hooks and JS hooks. These hooks come as both frontend hooks and editor hooks.
注入控件
Elementor 提供了一套特殊的钩子,允许开发者以编程方式将新控件注入到多种类型的元素中。您可以将新控件注入到所有元素、特定元素、Elementor 默认小部件以及其他插件开发者开发的小部件中。
共有八个可用的钩子供选择,其中四个钩子用于将控件注入到所有元素中,另外四个钩子用于将控件注入到特定元素中。
定位所有元素
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
elementor/element/before_section_startelementor/element/after_section_startelementor/element/before_section_endelementor/element/after_section_end
- 影响范围: 编辑器
Hook Arguments
| Argument | Type | Description |
|---|---|---|
element |
\Elementor\Controls_Stack |
The edited element. |
section_id |
string |
Section id. |
args |
array |
Section arguments sent to $element->start_controls_section |
elementor/element/before_section_start
elementor/element/after_section_end
在编辑器部分注册之前或之后运行。这用于在某个部分前后添加额外的部分,并影响面板中的所有元素。如果你需要在特定位置(特定元素和部分)添加一个部分,下面描述的钩子会更合适(参见“定位特定元素”部分)。
Example
/**
* @param \Elementor\Controls_Stack $element The element type.
* @param string $section_id Section ID.
* @param array $args Section arguments.
*/
function inject_custom_control( $element, $section_id, $args ) {
if ( 'section' === $element->get_name() && 'section_background' === $section_id ) {
$element->start_controls_section(
'custom_section',
[
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
'label' => esc_html__( 'Custom Section', 'textdomain' ),
]
);
$element->add_control(
'custom_control',
[
'type' => \Elementor\Controls_Manager::NUMBER,
'label' => esc_html__( 'Custom Control', 'textdomain' ),
]
);
$element->end_controls_section();
}
}
add_action( 'elementor/element/before_section_start', 'inject_custom_control', 10, 3 );
elementor/element/after_section_start
elementor/element/before_section_end
在编辑器中某个部分打开后、关闭前运行。这是向现有部分添加额外控件的地方。如果您需要将控件添加到特定位置(特定元素和部分),下面描述的钩子会更合适。
Example
/**
* @param \Elementor\Controls_Stack $element The element type.
* @param string $section_id Section ID.
* @param array $args Section arguments.
*/
function inject_custom_control( $element, $section_id, $args ) {
if ( 'section' === $element->get_name() && 'section_background' === $section_id ) {
$element->add_control(
'custom_control',
[
'type' => \Elementor\Controls_Manager::NUMBER,
'label' => esc_html__( 'Custom Control', 'textdomain' ),
]
);
}
}
add_action( 'elementor/element/after_section_start', 'inject_custom_control', 10, 3 );
定位特定元素
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
elementor/element/{$stack_name}/{$section_id}/before_section_startelementor/element/{$stack_name}/{$section_id}/after_section_startelementor/element/{$stack_name}/{$section_id}/before_section_endelementor/element/{$stack_name}/{$section_id}/after_section_end
- 说明: 钩子名称中的动态部分
$stack_name和$section_id分别指代栈名称和区块 ID。 - 影响范围: 编辑器
要定位特定元素(如 heading 部件)和特定区块(如 section_title 区块),请使用以下钩子之一:
elementor/element/heading/section_title/before_section_startelementor/element/heading/section_title/after_section_startelementor/element/heading/section_title/before_section_endelementor/element/heading/section_title/after_section_end
Hook Arguments
| Argument | Type | Description |
|---|---|---|
element |
Element_Base |
The edited element. |
args |
array |
Section arguments sent to $element->start_controls_section. |
elementor/element/{$stack_name}/{$section_id}/before_section_start
elementor/element/{$stack_name}/{$section_id}/after_section_end
在特定元素和特定区块之前/之后运行。
Example
/**
* @param \Elementor\Controls_Stack $element The element type.
* @param array $args Section arguments.
*/
function inject_heading_controls( $element, $args ) {
$element->start_controls_section(
'custom_section',
[
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
'label' => esc_html__( 'Custom Section', 'textdomain' ),
]
);
$element->add_control(
'custom_control',
[
'type' => \Elementor\Controls_Manager::NUMBER,
'label' => esc_html__( 'Custom Control', 'textdomain' ),
]
);
$element->end_controls_section();
}
add_action( 'elementor/element/heading/section_title/before_section_start', 'inject_heading_controls', 10, 2 );
elementor/element/{$stack_name}/{$section_id}/after_section_start
elementor/element/{$stack_name}/{$section_id}/before_section_end
在编辑器部分内部运行,于其打开之后、关闭之前。这是在特定元素及其内部特定部分之前和之后添加额外控件的位置。
Example
/**
* @param \Elementor\Controls_Stack $element The element type.
* @param array $args Section arguments.
*/
function inject_heading_controls( $element, $args ) {
$element->add_control(
'custom_control',
[
'type' => \Elementor\Controls_Manager::NUMBER,
'label' => esc_html__( 'Custom Control', 'textdomain' ),
]
);
}
add_action( 'elementor/element/heading/section_title/before_section_start', 'inject_heading_controls', 10, 2 );
JS Hooks
Elementor has a number of JS hooks that allow developers to change default behavior and even add new functionality.
前端过滤器
frontend/handlers/menu_anchor/scroll_top_distance
应用于菜单锚点小部件,设置自定义顶部距离
Arguments
| Argument | Type | Description |
|---|---|---|
scrollTop |
integer |
The default scrollTop. It only takes the WordPress admin bar into account |
Example
jQuery( function( $ ) {
// Add space for Elementor Menu Anchor link
if ( window.elementorFrontend ) {
elementorFrontend.hooks.addFilter( 'frontend/handlers/menu_anchor/scroll_top_distance', function( scrollTop ) {
return scrollTop - 30;
} );
}
} );
add_action( 'wp_footer', function() {
if ( ! defined( 'ELEMENTOR_VERSION' ) ) {
return;
}
?>
<script>
jQuery( function( $ ) {
// Add space for Elementor Menu Anchor link
if ( window.elementorFrontend ) {
elementorFrontend.hooks.addFilter( 'frontend/handlers/menu_anchor/scroll_top_distance', function( scrollTop ) {
return scrollTop - 30;
} );
}
} );
</script>
<?php
} );
前端操作
elementor/frontend/init
加载 Elementor 前端。
Arguments
None
Example
elementorFrontend.hooks.addAction( 'elementor/frontend/init', function() {
// Do something that is based on the elementorFrontend object.
} );
frontend/element_ready/global
当每个元素(包括节和列)准备就绪时运行。
参数
| 参数 | 类型 | 描述 |
|---|---|---|
$scope |
当前元素,已用 jQuery 包装 |
|
$ |
jQuery 实例 |
示例
elementorFrontend.hooks.addAction( 'frontend/element_ready/global', function( $scope ) {
if ( $scope.data( 'shake' ) ){
$scope.shake();
}
} );
frontend/element_ready/widget
在每个部件准备就绪时运行。
Arguments
| Argument | Type | Description |
|---|---|---|
$scope |
The current element wrapped with jQuery |
|
$ |
The jQuery instance |
示例
elementorFrontend.hooks.addAction( 'frontend/element_ready/widget', function( $scope ) {
if ( $scope.data( 'shake' ) ){
$scope.shake();
}
} );
frontend/element_ready/{elementType.skinName}
当特定元素类型及其皮肤准备就绪时运行。
Arguments
| Argument | Type | Description |
|---|---|---|
$scope |
The current element wrapped with jQuery |
|
$ |
The jQuery instance |
Example
// For a widget without a skin (skin = default)
elementorFrontend.hooks.addAction( 'frontend/element_ready/image.default', function( $scope ) {
if ( $scope.find( 'a' ) ){
$scope.find( 'a' ).lightbox();
}
} );
// For a widget with a skin named `satellite`
elementorFrontend.hooks.addAction( 'frontend/element_ready/google-maps.satellite', function( $scope ) {
var $iframe = $scope.find( 'iframe' );
var $iframeUrl = $iframe.attr( 'src' );
$iframe.attr( 'src', $iframeUrl + '&maptype=satellite' );
} );
编辑器钩子
panel/open_editor/{elementType}
当打开设置面板以编辑元素时应用。
Arguments
| Argument | Type | Description |
|---|---|---|
panel |
object |
The panel object |
model |
object |
The backbone model instance |
view |
object |
The backbone view instance |
Example
elementor.hooks.addAction( 'panel/open_editor/widget', function( panel, model, view ) {
if ( 'section' !== model.elType && 'column' !== model.elType ) {
return;
}
var $element = view.$el.find( '.elementor-selector' );
if ( $element.length ) {
$element.click( function() {
alert( 'Some Message' );
} );
}
} );
panel/open_editor/{elementType}/{elementName}
当打开设置面板以编辑特定元素名称时应用。
参数
| 参数 | 类型 | 描述 |
|---|---|---|
panel |
object |
面板对象 |
model |
object |
Backbone 模型实例 |
view |
object |
Backbone 视图实例 |
Example
elementor.hooks.addAction( 'panel/open_editor/widget/slider', function( panel, model, view ) {
var $element = view.$el.find( '.elementor-selector' );
if ( $element.length ) {
$element.click( function() {
alert( 'Some Message' );
} );
}
} );
Mask Shapes
Elementor offers the ability to apply overlay masks that create stylish designs for any element. By default Elementor offers a set of predefined masks. Additional masks can be added using a dedicated filter hook.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
elementor/mask_shapes/additional_shapes - Affects: Editor
Hook Arguments
| Argument | Type | Description |
|---|---|---|
additional_shapes |
array |
A list of additional mask shapes. |
An array of additional mask shapes that should include the following parameters:
'mask-shape-id' => [
'title' => (string) Mask label.
'image' => (string) Mask file URI.
]
Examples
To add new mask shapes use the following code:
/**
* Add additional mask shapes to Elementor.
*
* @since 1.0.0
*/
function custom_elementor_mask_shapes() {
return [
'shape-id-1' => [
'title' => esc_html__( 'Shape name 1', 'textdomain' ),
'image' => PLUGIN_ASSETS_URL . 'mask-shapes/shape-1.svg',
],
'shape-id-2' => [
'title' => esc_html__( 'Shape name 2', 'textdomain' ),
'image' => PLUGIN_ASSETS_URL . 'mask-shapes/shape-2.svg',
],
];
}
add_filter( 'elementor/mask_shapes/additional_shapes', 'custom_elementor_mask_shapes' );
To avoid conflicts with other plugins, shape IDs should be prefixed.
The PLUGIN_ASSETS_URL should be updated using plugin_dir_path( __FILE__ ), get_stylesheet_directory_uri() or any other method that retrieves the assets URL.
解析元素 CSS
Elementor 提供了一个钩子,允许开发者在 CSS 文件生成之前向元素添加新的 CSS 规则。
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
elementor/element/parse_css - 影响范围: 前端
钩子参数
| 参数 | 类型 | 描述 |
|---|---|---|
post_css |
\Elementor\Core\Files\CSS\Post |
文章 CSS 文件实例 |
element |
\Elementor\Element_Base |
元素实例 |
示例
让我们向生成的 CSS 文件添加一个简单的 CSS 规则:
/**
* 添加自定义 CSS 规则。
*
* @since 1.0.0
* @param \Elementor\Core\Files\CSS\Post $post_css_file 文章 CSS 文件实例。
* @param \Elementor\Element_Base $element 元素实例。
*/
function add_custom_css_rule_to_the_css_file( $post_css_file, $element ) {
$post_css_file->get_stylesheet()->add_rules(
'.my-selector',
[
'width' => '50px',
'height' => '50px',
]
);
}
add_action( 'elementor/element/parse_css', 'add_custom_css_rule_to_the_css_file', 10, 2 );
现在,让我们添加一个带有唯一 Elementor 选择器的 CSS 规则:
/**
* 解析元素 CSS。
*
* @since 1.0.0
* @param \Elementor\Core\Files\CSS\Post $post_css_file 文章 CSS 文件实例。
* @param \Elementor\Element_Base $element 元素实例。
*/
function add_custom_rules_to_css_file( $post_css_file, $element ) {
$item_width = some_get_theme_config_function( 'item_width' );
$item_height = some_get_theme_config_function( 'item_height' );
$post_css_file->get_stylesheet()->add_rules(
$element->get_unique_selector(),
[
'width' => $item_width . 'px',
'height' => $item_height . 'px',
]
);
}
add_action( 'elementor/element/parse_css', 'add_custom_rules_to_css_file', 10, 2 );
PHP Hooks
Elementor's PHP hooks, both filter hooks and action hooks.
Filter Hooks
elementor/admin/create_new_post/metaelementor/admin/dashboard_overview_widget/footer_actionselementor/admin/localize_settingselementor/api/get_templates/body_argselementor/connect/additional-connect-infoelementor/controls/animations/additional_animationselementor/controls/hover_animations/additional_animationselementor/controls/exit-animations/additional_animationselementor/core/admin/noticeselementor/divider/styles/additional_styleselementor/document/configelementor/document/save/dataelementor/document/urls/editelementor/document/urls/exit_to_dashboardelementor/document/urls/previewelementor/document/urls/wp_previewelementor/documents/ajax_save/return_dataelementor/documents/get/post_idelementor/editor/localize_settingselementor/editor/user/restrictionselementor/element/get_child_typeelementor/extended_allowed_html_tags/{$tag}elementor/files/allow_unfiltered_uploadelementor/files/file_nameelementor/files/svg/allowed_attributeselementor/files/svg/allowed_elementselementor/files/svg/enabled- elementor/finder/categories
elementor/fonts/additional_fontselementor/fonts/groupselementor/frontend/admin_bar/settingselementor/frontend/assets_urlelementor/frontend/builder_content_dataelementor/frontend/google_font_subsets- elementor/frontend/print_google_fonts
- elementor/frontend/the_content
elementor/frontend/{$element_type}/should_renderelementor/icons_manager/additional_tabselementor/icons_manager/nativeelementor/icons_manager/migration_allowedelementor/image_size/get_attachment_image_htmlelementor/import/stage_1/resultelementor/kit/export/manifest-dataelementor/kit/import-export/directory/{$path}elementor/maintenance_mode/is_login_page- elementor/mask_shapes/additional_shapes
- elementor/shapes/additional_shapes
elementor/schemes/enabled_schemeselementor/settings/controls/checkbox_list_cpt/post_type_objectselementor/settings/tools/rollback/is_valid_rollback_versionelementor/settings/{$settings_name}/success_response_dataelementor/template/viewport_tagelementor/template-library/create_new_dialog_typeselementor/template_library/sources/local/register_category_argselementor/template_library/sources/local/register_post_type_argselementor/template_library/sources/local/register_taxonomy_argselementor/template_library/sources/local/register_taxonomy_cptselementor/template-library/get_templateelementor/template-library/get_template_label_by_typeelementor/template_library/is_template_supports_exportelementor/tools/replace-urlselementor/tracker/admin_description_textelementor/tracker/last_send_intervalelementor/tracker/last_send_timeelementor/tracker/send_overrideelementor/tracker/send_tracking_data_params- elementor/utils/get_placeholder_image_src
elementor/utils/is_post_supportelementor/utils/is_post_type_support- elementor/widget/render_content
elementor/widgets/black_listelementor/widgets/read_more/default_link_textelementor/widgets/wordpress/widget_args- elementor/{$element_type}/print_template
动作钩子
elementor/admin/after_create_settings/{$page_id}elementor/admin/dashboard_overview_widget/after_versionelementor/ajax/register_actionselementor/app/initelementor/common/after_register_scriptselementor/connect/apps/register- elementor/controls/register
elementor/core/files/clear_cacheelementor/core/files/assets/assets_registeredelementor/css-file/{$name}/enqueueelementor/css-file/{$name}/parseelementor/db/before_saveelementor/document/after_saveelementor/document/before_saveelementor/document/save_versionelementor/documents/registerelementor/documents/register_controls- elementor/dynamic_tags/register
elementor/dynamic_tags/before_renderelementor/dynamic_tags/after_renderelementor/editor/init- elementor/editor/after_save
- elementor/editor/after_enqueue_scripts
- elementor/editor/before_enqueue_scripts
- elementor/editor/after_enqueue_styles
- elementor/editor/before_enqueue_styles
elementor/editor/footerelementor/editor/wp_headelementor/element/before_parse_css- elementor/element/parse_css
- elementor/element/after_section_start
- elementor/element/before_section_start
- elementor/element/before_section_end
- elementor/element/after_section_end
- elementor/element/{$section_name}/{$section_id}/before_section_start
- elementor/element/{$section_name}/{$section_id}/after_section_start
- elementor/element/{$stack_name}/{$section_id}/before_section_end
- elementor/element/{$stack_name}/{$section_id}/after_section_end
elementor/element/after_add_attributeselementor/elements/elements_registeredelementor/elements/categories_registeredelementor/experiments/feature-registeredelementor/experiments/default-features-registered- elementor/finder/register
elementor/fonts/print_font_links/{$font_type}- elementor/frontend/after_render
- elementor/frontend/before_render
- elementor/frontend/{$element_type}/before_render
- elementor/frontend/{$element_type}/after_render
elementor/frontend/after_enqueue_scripts- elementor/frontend/after_enqueue_styles
- elementor/frontend/after_register_scripts
elementor/frontend/after_register_styleselementor/frontend/before_enqueue_scripts- elementor/frontend/before_enqueue_styles
- elementor/frontend/before_register_scripts
elementor/frontend/before_register_styleselementor/frontend/before_get_builder_contentelementor/frontend/get_builder_contentelementor/frontend/render_mode/register- elementor/init
elementor/kit/register_tabs- elementor/loaded
elementor/loggers/registerelementor/maintenance_mode/mode_changedelementor/page_templates/canvas/before_contentelementor/page_templates/canvas/after_contentelementor/page_templates/header-footer/before_contentelementor/page_templates/header-footer/after_contentelementor/preview/init- elementor/preview/enqueue_scripts
- elementor/preview/enqueue_styles
elementor/role/restrictions/controlselementor/safe_mode/initelementor/template-library/after_get_source_dataelementor/template-library/after_save_templateelementor/template-library/after_update_templateelementor/template-library/before_get_source_dataelementor/template-library/create_new_dialog_fieldselementor/widget/before_render_content- elementor/widget/{$widget_name}/skins_init
- elementor/widgets/register
占位图
Elementor 图片小部件和基于媒体的控件会显示占位图,除非用户从媒体库中选择特定图片。
默认情况下,Elementor 使用位于 Elementor 插件资源文件夹中的默认图片。但是,您可以用自定义图片替换此默认图片。
钩子详情
- 钩子类型: 过滤器钩子
- 钩子名称:
elementor/utils/get_placeholder_image_src - 影响范围: 编辑器
占位图过滤器钩子
通过 elementor/utils/get_placeholder_image_src 过滤器钩子,开发者可以更改默认占位图的来源。
您可以从外部 URL 设置占位图:
/**
* 更改默认的 Elementor 占位图。
*
* 使用位于外部 URL 的图片。
*
* @since 1.0.0
*/
function custom_elementor_placeholder_image() {
return 'https://developers.elementor.com/path/to/placeholder.png';
}
add_filter( 'elementor/utils/get_placeholder_image_src', 'custom_elementor_placeholder_image' );
或者设置位于您插件文件夹中的占位图:
/**
* 更改默认的 Elementor 占位图。
*
* 使用位于插件资源文件中的图片。
*
* @since 1.0.0
*/
function custom_elementor_placeholder_image() {
return plugins_url( 'assets/images/placeholder.png', __FILE__ );
}
add_filter( 'elementor/utils/get_placeholder_image_src', 'custom_elementor_placeholder_image' );
注意: Elementor 使用的默认占位图位于:"plugins/elementor/assets/images/placeholder.png"。
禁用 Google 字体加载
Elementor 提供了一个特殊的过滤器钩子,允许开发者阻止 Google 字体的加载。换句话说,并非所有前端 Google 字体都会被加入队列。
钩子详情
- 钩子类型: 过滤器钩子
- 钩子名称:
elementor/frontend/print_google_fonts - 影响范围: 前端
控制 Google 字体入队
要阻止 Elementor 在前端加载 Google 字体:
/**
* 阻止 Elementor 在前端加载 Google 字体。
*
* @since 1.0.0
*/
add_filter( 'elementor/frontend/print_google_fonts', '__return_false' );
Print Widget Template
Elementor has a hook that lets developers change a widget's JavaScript template in the preview area.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
elementor/{$element_type}/print_template - Notes: The dynamic portion of the hook name,
$element_type, refers towidget. - Affects: Preview
Hook Arguments
| Argument | Type | Description |
|---|---|---|
template |
string |
The JavaScript template output |
widget |
\Elementor\Widget_Base |
The widget instance |
Example
/**
* Update the heading widget JS template in Elementor preview.
*
* Adds an icon to all the external links.
*
* @since 1.0.0
* @param string $template The JavaScript template output.
* @param \Elementor\Widget_Base $widget The widget instance.
*/
function change_heading_js_template( $template, $widget ) {
if ( 'heading' === $widget->get_name() ) {
$old_template = '<a href="\' + settings.link.url + \'">\' + title_html + \'</a>';
$new_template = '<a href="\' + settings.link.url + \'">\' + title_html + ( settings.link.is_external ? \'<i class="fa fa-external-link" aria-hidden="true"></i>\' : \'\' ) + \'</a>';
$template = str_replace( $old_template, $new_template, $template );
}
return $template;
}
add_filter( 'elementor/widget/print_template', 'change_heading_js_template', 10, 2 );
The code above is only an example. We do not recommend using str_replace on templates, because the template may be changed and the str_replace will fail. Instead, edit the entire original template for your needs.
Notes
To change the widget content in the frontend see elementor/widget/render_content.
Render Frontend Elements
Elementor has a hook that lets developers add code before or after elements in the frontend. This hook can be applied to either a single element or all the elements on a page and is applied to the final HTML output of the element(s). Developers can use this hook to change the HTML output before Elementor displays it to the end-user.
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
elementor/frontend/before_renderelementor/frontend/after_renderelementor/frontend/{$element_type}/before_renderelementor/frontend/{$element_type}/after_render
- 说明: 钩子名称中的动态部分
$element_type指的是元素类型。 - 影响范围: 前端
Hook Arguments
| Argument | Type | Description |
|---|---|---|
element |
\Elementor\Element_Base |
The element instance. |
元素类型
动态部分 $element_type 指的是您要定位的元素类型。例如,以下是一些可用的元素类型:
section- 应用于版块和内部版块。column- 应用于列和内部列。container- 应用于容器和内部容器。widget- 应用于所有小部件。
Example
All Elements
Apply changes to all the elements:
<?php
/**
* Add `<div>` before all the elements in the page.
*
* @since 1.0.0
* @param \Elementor\Element_Base $element The element instance.
*/
function add_div_before_all_elements( $element ) {
?>
<div class="before-element">Text before element</div>
<?php
}
add_action( 'elementor/frontend/before_render', 'add_div_before_all_elements' );
/**
* Add `<div>` after all the elements in the page.
*
* @since 1.0.0
* @param \Elementor\Element_Base $element The element instance.
*/
function add_div_after_all_elements( $element ) {
?>
<div class="after-element">Text after element</div>
<?php
}
add_action( 'elementor/frontend/after_render', 'add_div_after_all_elements' );
Specific Elements
Apply changes only on widgets:
<?php
/**
* Add `<div>` before all the widgets in the page.
*
* @since 1.0.0
* @param \Elementor\Element_Base $element The element instance.
*/
function add_div_before_all_the_widget( $element ) {
?>
<div class="before-widget">Text before widget</div>
<?php
}
add_action( 'elementor/frontend/widget/before_render', 'add_div_before_all_the_widget' );
/**
* Add `<div>` after all the widgets in the page.
*
* @since 1.0.0
* @param \Elementor\Element_Base $element The element instance.
*/
function add_div_after_all_the_widget( $element ) {
?>
<div class="after-widget">Text after widget</div>
<?php
}
add_action( 'elementor/frontend/widget/after_render', 'add_div_after_all_the_widget' );
Advanced Usage
Change the element instance using the $element parameter.
<?php
/**
* Add a custom class and a data attribute to all the elements
* containing a specific setting defined through the element control.
*
* @since 1.0.0
* @param \Elementor\Element_Base $element The element instance.
*/
function add_attributes_to_elements( $element ) {
if ( ! $element->get_settings( 'my-custom-setting' ) ) {
return;
}
$element->add_render_attribute(
'_wrapper',
[
'class' => 'my-custom-class',
'data-my-custom-value' => 'my-custom-data-value',
]
);
}
add_action( 'elementor/frontend/before_render', 'add_attributes_to_elements' );
Render Widget Content
Elementor has a hook that lets developers change a widget's content in the frontend. These changes will be applied to the final HTML content of the widget. In the preview area, they will be shown after the user finishes editing the element.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
elementor/widget/render_content - Affects: Frontend
Hook Arguments
| Argument | Type | Description |
|---|---|---|
content |
string |
The widget HTML output |
widget |
\Elementor\Widget_Base |
The widget instance |
Change Widget Content
Go over all the heading widgets and, if the heading uses external links, add an icon after the links indicating it's an external link:
/**
* Filters heading widgets and change their content.
*
* @since 1.0.0
* @param string $widget_content The widget HTML output.
* @param \Elementor\Widget_Base $widget The widget instance.
* @return string The changed widget content.
*/
function change_heading_widget_content( $widget_content, $widget ) {
if ( 'heading' === $widget->get_name() ) {
$settings = $widget->get_settings();
if ( ! empty( $settings['link']['is_external'] ) ) {
$widget_content .= '<i class="fa fa-external-link" aria-hidden="true"></i>';
}
}
return $widget_content;
}
add_filter( 'elementor/widget/render_content', 'change_heading_widget_content', 10, 2 );
Notes
To change the widget JavaScript template see elementor/widget/print_template.
Save Editor Data
Elementor has a hook that lets developers run code after the user has saved data in the editor.
Hook Details
- Hook Type: Action Hook
- Hook Name:
elementor/editor/after_save - Affects: Editor
Hook Arguments
| Argument | Type | Description |
|---|---|---|
post_id |
integer |
The post ID. |
editor_data |
array |
A list of Elementor elements |
Examples
A good example of using this hook is when you want to log user activities. Each time the user saves Elementor data, you can log this activity:
/**
* Log user activity when the user saves Elementor data.
*
* @since 1.0.0
* @param int $post_id The ID of the post.
* @param array $editor_data The editor data.
*/
function log_saved_elementor_data( $post_id, $editor_data ) {
// Interact with your activity log plugin
insert_activity_log_data(
[
'action' => 'saved',
'object_type' => 'Elementor Data',
'object_id' => $post_id,
'object_name' => get_the_title( $post_id ),
]
);
}
add_action( 'elementor/editor/after_save', 'log_saved_elementor_data', 10, 2 );
Another example is when you want to clear the cache each time the user updates a post:
/**
* Clear old cache when the user saves new Elementor data.
*
* @since 1.0.0
* @param int $post_id The ID of the post.
* @param array $editor_data The editor data.
*/
function clear_cache_when_updating_elementor( $post_id, $data ) {
if ( get_post_status( $post_id ) != 'publish' ) {
return;
}
// Interact with your caching plugin
clear_old_cache_data_for_your_post( $post_id );
}
add_action( 'elementor/editor/after_save', 'clear_cache_when_updating_elementor', 10 , 2 );
Shape Dividers
Elementor offers the ability to add graphic shape dividers that separate the sections of a page. By default Elementor offers a set of predefined dividers. Additional shape dividers can be added using a dedicated filter hook.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
elementor/shapes/additional_shapes - Affects: Editor
Hook Arguments
| Argument | Type | Description |
|---|---|---|
additional_shapes |
array |
A list of additional shape dividers. |
An array of additional shape dividers should include the following parameters:
'shape-divider-id' => [
'title' => (string) Shape divider label.
'url' => (string) Shape divider file URI.
'path' => (string) Shape divider file path.
'has_flip' => (bool) Whether to allow to flip the shape vertically. Default is false.
'height_only' => (bool) Whether to allow to set width & height or only height. Default is false.
'has_negative' => (bool) Whether the shape divider has a negative variation. Default is false.
]
To support negative variations, you should include two files:
shape.svgshape-negative.svg
The first is the original design, the other is the same design but with negative colors.
Example
To add new shape dividers in your theme, use the following code:
/**
* Add additional shape dividers to Elementor.
*
* @since 1.0.0
*/
function custom_elementor_shape_dividers() {
return [
'shape-divider-1' => [
'title' => esc_html__( 'Shape divider 1', 'textdomain' ),
'url' => PLUGIN_ASSETS_URL . 'assets/shapes/shape-1.svg',
'path' => PLUGIN_ASSETS_PATH . 'assets/shapes/shape-1.svg',
'height_only' => true,
],
'shape-divider-2' => [
'title' => esc_html__( 'Shape divider 2', 'textdomain' ),
'url' => PLUGIN_ASSETS_URL . 'assets/shapes/shape-2.svg',
'path' => PLUGIN_ASSETS_PATH . 'assets/shapes/shape-2.svg',
'has_flip' => true,
'has_negative' => true,
'height_only' => true,
],
];
}
add_filter( 'elementor/shapes/additional_shapes', 'custom_elementor_shape_dividers' );
To avoid conflicts with other plugins, shape IDs should be prefixed.
The PLUGIN_ASSETS_URL should be updated using functions like plugin_dir_path( __FILE__ ) or get_stylesheet_directory_uri(). The PLUGIN_ASSETS_PATH should be updated using functions like plugin_dir_path( __FILE__ ) or get_stylesheet_directory().
小部件分类
Elementor 小部件分类 用于将小部件组织成组。当 Elementor 初始化时,它会注册几个默认分类。只有当分类被分配了小部件时,它们才会显示在小部件面板中。
使用小部件分类
我们在注册新的 Elementor 小部件时会使用小部件分类。通过扩展 \Elementor\Widget_Base 类,我们继承了 \Elementor\Widget_Base::get_categories() 方法,该方法默认返回通用分类。要将小部件分配到不同的分类,我们需要重写该方法并按以下方式返回新的分类:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_categories(): array {
return [ 'basic' ];
}
}
默认分类
当您选择将小部件分配到哪个分类时,可以从以下默认分类中选择一个:
- Basic –
basic分类。 - Pro – Elementor Pro 的
pro-elements分类。 - Theme – Elementor Pro 的
theme-elements分类。 - WooCommerce – Elementor Pro 的
woocommerce-elements分类。 - General –
general分类。 - WordPress – 显示 WordPress 小部件的
wordpress分类。
或者,您可以注册自己的分类。
创建新分类
Elementor 允许开发者添加新的小部件分类来分组他们自己的自定义小部件。注册新的小部件分类需要使用 elementor/elements/categories_registered 动作。
请注意,创建新分类时,您需要提供分类名称/别名、分类标题/标签和分类图标。
function add_elementor_widget_categories( $elements_manager ) {
$elements_manager->add_category(
'first-category',
[
'title' => esc_html__( 'First Category', 'textdomain' ),
'icon' => 'fa fa-plug',
]
);
$elements_manager->add_category(
'second-category',
[
'title' => esc_html__( 'Second Category', 'textdomain' ),
'icon' => 'fa fa-plug',
]
);
}
add_action( 'elementor/elements/categories_registered', 'add_elementor_widget_categories' );
小部件皮肤
Elementor 提供了一个钩子,允许开发者向小部件应用自定义皮肤。该钩子在小部件构造函数之后运行,并为支持皮肤的特定小部件类型注册自定义皮肤。
钩子详情
- 钩子类型: 动作钩子
- 钩子名称:
elementor/widget/{$widget_name}/skins_init - 说明: 钩子名称的动态部分
$widget_name指的是小部件名称。 - 影响范围: 初始化
钩子参数
| 参数 | 类型 | 描述 |
|---|---|---|
widget |
\Elementor\Widget_Base |
小部件实例 |
示例
让我们为 Google 地图小部件添加一个自定义皮肤:
/**
* 为 "Google Maps" 小部件添加深色皮肤。
*
* @since 1.0.0
* @param \Elementor\Widget_Base $widget 小部件实例。
*/
function dark_skin_for_google_maps_widget( $widget ) {
$widget->add_skin( new \MySkins\Skin_Dark_Map( $widget ) );
}
add_action( 'elementor/widget/google_maps/skins_init', 'dark_skin_for_google_maps_widget' );
Elementor Hosting
Elementor hosting is an end-to-end solution gives you everything you need in one place: WordPress Managed Hosting, Elementor & Elementor Pro, Theme and Premium support, all tailored together to provide a seamless building experience and top performing websites.
Caching Hooks
Elemenor's hosting offer several hooks to manage your website's caching.
Dynamic Page Cache
Elementor hosting offers the option to control whether a page should be cached or not, depending on its dynamic nature. By using this hook, you can prevent caching of certain pages that require real-time or dynamic content updates, ensuring that the visitors always see the latest content on those pages.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
elementor/hosting/page_cache/allow_page_cache - Affects: Elementor Hosting
Hook Arguments
| Argument | Type | Description |
|---|---|---|
allow |
bool |
Whether to allow page cache. |
Examples
Clear cache for dynamic content updates using the following code:
/**
* @param bool Whether to allow page cache.
* @return bool
*/
function custom_page_cache( $allow ) {
if ( ! $allow ) {
return $allow;
}
return is_my_special_page();
}
add_filter( 'elementor/hosting/page_cache/allow_page_cache', 'custom_page_cache', 20 );
Cache Changed URLs
Elementor hosting offers the option to add custom co-changing URLs to the page cache whenever a specific content type (post, comment, WooCommerce product etc.) is updated. This can be useful for keeping cache up-to-date for pages that depend on the updated content.
Hook Details
- Hook Type: Filter Hook
- Hook Name:
elementor/hosting/page_cache/{$content_type}_changed_urls - Affects: Elementor Hosting
The dynamic portion of the hook name, $content_type, refers to the content type, e.g post, comment, woocommerce_product etc.
Hook Arguments
| Argument | Type | Description |
|---|---|---|
urls |
array |
An array of URLs. |
content_id |
int |
Content ID. |
Examples
Clear cache for dynamic content updates, using the following code:
/**
* @param array
* @param int
* @return array
*/
function custom_clear_cache_on_woccomerce_update( $urls, $product_id ) {
if ( ( ! is_array( $urls ) ) || empty( $urls ) ) {
$urls = [];
}
$url[] = site_url('/my-path');
return $urls;
}
add_filter( 'elementor/hosting/page_cache/woocommerce_product_changed_urls', 'custom_clear_cache_on_woccomerce_update', 10, 2 );
Purge Everything
Elementor hosting offers the option to purge the entire site cache, clearing all the CDN cache for the whole domain. Please note that it might take some time for this to take effect.
Hook Details
- Hook Type: Action Hook
- Hook Name:
elementor/hosting/page_cache/purge_everything - Affects: Elementor Hosting
Hook Arguments
None.
Examples
To trigger the purge use the following code:
/**
* Purge all the cache.
*/
do_action( 'elementor/hosting/page_cache/purge_everything' );
API -- `$e.commands`
新的 Commands API(自 2.7.0 版本起)提供了一种简单便捷的方式,通过 JS 命令在编辑器中运行某些操作、创建小部件,以及显示通知或撤销更改。
可通过以下方式获取完整命令列表(包括自定义和第三方命令):$e.commands.getAll();
-
描述:
$e.commandsAPI 是所有 命令 的管理器,允许您创建通过$e.run()运行的自定义 命令。每个组件都有其独特的命令,所有命令都由该 API 管理。 -
位置:
/core/common/assets/js/components/commands.js -
父级:
elementorModules.Module -
可用命令:有关 所有 命令的更多信息,请访问
{$e.commands.getAll()}方法。
方法
| Method | Params | Returns | Description |
|---|---|---|---|
$e.commands.getAll() |
Receive all loaded commands. | ||
$e.commands.register() |
{(BaseComponent⎮string)} component, {String} command, {function()} callback |
{Commands} $e.commands |
Register new command. |
$e.commands.getComponent() |
{String} command |
{BaseComponent) |
Receive Component of the command. |
$e.commands.is() |
{String} command |
{Boolean} |
Checks if current running command is the same parameter command. |
$e.commands.isCurrentFirstTrace() |
{String} command |
{Boolean} |
Checks if parameter command is the first command in trace that currently running. |
$e.commands.getCurrent() |
{Object} |
Receive currently running components and its commands. | |
$e.commands.getCurrentArgs() |
{Object} |
Receive currently running command args. | |
$e.commands.getCurrentFirst() |
{String} |
Receive first command that currently running. | |
$e.commands.getCurrentFirstTrace() |
{Object} |
Receive first command in trace that currently running. | |
$e.commands.beforeRun() |
{String} command, {Object} args |
{Boolean} dependency result |
Method fired before the command runs. |
$e.commands.run() |
{String} command, {Object} args |
{} results |
Runs a command. |
$e.commands.runShortcut() |
{String} command, event |
{} results |
Run shortcut. |
$e.commands.afterRun() |
Method fired after the command runs. | ||
$e.commands.error() |
{String} message |
Throws error. |
Examples
// Example create and register new command.
// Important: Available to run in the console does not depends on anything else.
class ExampleCommand extends $e.modules.CommandBase {
apply( args ) {
// Output command args to console.
console.log( 'ExampleCommand: ', args );
// Return object as example.
return {
example: 'result from ExampleCommand',
};
}
}
class CustomComponent extends $e.modules.ComponentBase {
getNamespace() {
return 'custom-component';
}
defaultCommands() {
// Object of all the component commands.
return {
example: ( args ) => ( new ExampleCommand( args ) ).run(),
};
}
}
// Register the new component.
$e.components.register( new CustomComponent() );
// Run's 'example' command from 'custom-component'.
result = $e.run( 'custom-component/example', {
property: 'value',
} );
// Output command run result.
console.log( 'e-commands-eg-1-result: ', result );
指南
- 每个命令都应归属于某个组件。
- 目前,主要有 3 种基础类型:
- 命令 - 基类:
$e.modules.CommandBase-[用户]命令,代表用户操作。 - 内部命令 - 基类:
$e.modules.CommandInternalBase-[内部]供内部使用。 - 数据命令 - 基类:
$e.modules.CommandData-[数据]命令,用于与数据\缓存\后端通信。
- 命令 - 基类:
- 每个组件可以重写几个方法:
defaultCommands、defaultCommandsInternal、defaultData,这些方法用于根据命令类型导入命令。 - 命令应通过内置方法
importCommands导入。- 示例:
📦 组件
│ 📜 component.js
│
└───📂 commands
│ │ 📜 index.js ( 导出所有命令 )
│ │ 📜 example-command.js
│ │ ...
component/commands/index.js 文件第 5 行:
export { ExampleCommand } from './example-command';
使用 importCommands 示例:component/component.js 文件第 2 行:
import * as commands from './commands/';
export class Component extends $e.modules.ComponentBase {
getNamespace() {
return 'component-name';
}
defaultCommands() {
return this.importCommands( commands );
}
}
- 所有系列的命令类型都应具有唯一的文件夹和索引文件来存放它们:
- 命令:
- 如上例所示。
- 内部命令
- 示例:
- 命令:
📦 组件
│ 📜 component.js
│
└───📂 commands-internal
│ │ 📜 index.js ( 导出所有命令 )
│ │ 📜 internal-command.js
│ │ ...
component/commands-internal/index.js 文件第 5 行:
export { InternalCommand } from './internal-command';
使用 importCommands 示例:component/component.js 文件第 2 行:
import * as commandsInternal from './commands-internal/';
export class Component extends $e.modules.ComponentBase {
getNamespace() {
return 'component-name';
}
defaultCommandsInternal() {
return this.importCommands( commandsInternal );
}
}
- 数据命令
📦 组件
│ 📜 component.js
│
└───📂 commands-data
│ │ 📜 index.js ( 导出所有命令 )
│ │ 📜 data-command.js
│ │ ...
component/commands-data/index.js 文件第 5 行:
export { DataCommand } from './data-command';
使用 importCommands 示例:component/component.js 文件第 2 行:
import * as commandsData from './commands-data/';
export class Component extends $e.modules.ComponentBase {
getNamespace() {
return 'component-name';
}
defaultData() {
return this.importCommands( commandsData );
}
}
::: warning 注意
关于 {$e.modules.CommandBase} 类的更多信息。
:::
API - `$e.components`
新的组件 API(自 2.7.0 版本起),提供了一种简单便捷的方式,将属于一个 UI 组件的所有路由、命令和键盘快捷键绑定到一个控制器中。
完整的组件列表,包括自定义和第三方路由,可通过 $e.components.getAll(); 获取。每个组件都有其唯一的命名空间,其所有命令和路由都嵌套在该命名空间下。
当路由指向组件路由,且组件变为“活动”状态时,它允许为每个组件绑定键盘快捷键。 组件是可扩展的,因此第三方插件可以向现有组件添加一些路由、命令和快捷键。
-
描述:
$e.componentsAPI 是整个 api 组件的管理器。 -
位置:
core/common/assets/js/api/core/components.js -
父级:
elementorModules.Module
方法
| 方法 | 参数 | 返回值 | 描述 |
|---|---|---|---|
$e.components.getAll() |
{array.<string>} |
获取所有组件。 | |
$e.components.register() |
{ComponentBase} component |
{ComponentBase} component |
注册一个组件。 |
$e.components.get() |
{String} id |
{ComponentBase} component |
通过 id 获取组件实例。 |
$e.components.getActive() |
{Object.<ComponentBase>} activeComponents |
获取活动组件。 | |
$e.components.activate() |
{String} namespace |
激活组件。 | |
$e.components.inactivate() |
{String} namespace |
停用组件。 | |
$e.components.isActive() |
{String} namespace |
{Boolean} isActive |
组件是否处于活动状态。 |
::: warning 注意
要查看所有组件,请访问 {$e.commands.getAll()}
:::
Examples
// Example of creating and registering a new component, available to run in the console and does not depend on anything else.
class CustomComponent extends $e.modules.ComponentBase {
getNamespace() {
return 'custom-component';
}
defaultCommands() {
// Object of all the component commands.
return {
// 'example' command.
example: ( args ) => {
// Output command args to console.
console.log( 'ExampleCommand: ', args );
// Return object as example.
return {
example: 'result from ExampleCommand',
};
},
};
}
}
// Register the new component.
$e.components.register( new CustomComponent() );
// Runs 'example' command from 'custom-component'.
result = $e.run( 'custom-component/example', {
property: 'value',
} );
// Output command run result.
console.log( 'e-components-eg-1-result: ', result );
Guidelines
- You can view your component as a namespace that holds your commands, hooks, routes, tabs, shortcuts & utils.
- Component class file should be named
component.js - Component folder name should be named as a component namespace or a sub-component namespace.
- Components and sub-components convention example, described in next scenario:
Assuming you create a
Documentcomponent which creates a sub-componentElements
📦 document
│ 📜 component.js
│ 📜 index.js ( has all sub-components exported )
│
└───📂 elements
│ │ 📜 component.js
│ │ | ...
document/index.js file at line 3:
export { default as ElementsComponent } from './elements/component.js';
document/component.js file at line 2:
import * as components from './';
export default class Component extends $e.modules.ComponentBase {
getNamespace() {
return 'document';
}
registerAPI() {
// Register sub components.
Object.values( components ).forEach( ( ComponentClass ) =>
$e.components.register( new ComponentClass )
);
super.registerAPI();
}
}
export default class Component;
document/elements/component.js file at line 6:
export default class Component extends $e.modules.ComponentBase {
getNamespace() {
return 'elements';
}
}
export default class Component;
API - `$e.hooks`
$e.hooks API 是 $e.hooks.ui 和 $e.hooks.data 的管理器。它允许你创建自定义钩子。这些钩子附加到 $e.commands,每个钩子在通过 $e.run() 运行命令的 之前/之后 触发。
位置: core/common/assets/js/api/core/hooks.js
方法
| Method | Params | Returns | Description |
|---|---|---|---|
$e.hooks.activate() |
Activate all hooks. | ||
$e.hooks.deactivate() |
Deactivate all hooks. | ||
$e.hooks.getAll() |
{Array} |
Receive all loaded hooks. | |
$e.hooks.register() |
{String} type, {String} event, {HookBase} instance |
{Object} callback |
Register a hook. |
$e.hooks.run() |
{String} type, {String} event, {String} command, {Object} args, {*} result |
{Boolean} |
Run a hook. |
$e.hooks.registerDataAfter() |
{HookBase} instance |
{Object} callback |
Register data hook that runs after the command runs. |
$e.hooks.registerDataCatch() |
{HookBase} instance |
{Object} callback |
Register data hook that runs when the command fails. |
$e.hooks.registerDataDependency() |
{HookBase} instance |
{Object} callback |
Register data hook that runs before the command runs as dependency. |
$e.hooks.registerUIAfter() |
{HookBase} instance |
{Object} callback |
Register UI hook that runs after the commands run. |
$e.hooks.registerUICatch() |
{HookBase} instance |
{Object} callback |
Register UI hook that runs when the command fails. |
$e.hooks.registerUIBefore() |
{HookBase} instance |
{Object} callback |
Register UI hook that runs before the command. |
$e.hooks.runDataAfter() |
{String} command, {Object} args, {*} result |
{Boolean} |
Run a data hook that runs after the command. |
$e.hooks.runDataCatch() |
{String} command, {Object} args, {*} result |
{Boolean} |
Run a data hook that runs when the command fails. |
$e.hooks.runDataDependency() |
{String} command, {Object} args, {*} result |
{Boolean} |
Run a data hook that runs before the command as dependency. |
$e.hooks.runUIAfter() |
{String} command, {Object} args, {*} result |
{Boolean} |
Run a UI hook that runs after the commands run. |
$e.hooks.runUICatch() |
{String} command, {Object} args, {*} result |
{Boolean} |
Run a UI hook that runs when the command fails. |
$e.hooks.runUIBefore() |
{String} command, {Object} args, {*} result |
{Boolean} |
Run a UI hook that runs before the command. |
指南
// index.js
export { FooterSaverRefreshMenu } from './ui/document/elements/settings/footer-saver-refresh-menu';
export { UpdateButton } from './ui/document/save/set-is-modifed/update-button';
export { BypassImport } from './data/document/elements/import/bypass-import';
export { SaveExtras } from './data/document/save/save/save-extras';
你可以在 component/hooks/what-ever-you-wish 下的每个层级中拥有任意多个索引文件来组织代码,但要求必须在 component/hooks/index.js 处有一个索引文件来导出所有钩子。以上面的 index.js 为例:
📦 component
│ 📜 component.js
│
└───📂 hooks
│ │ 📜 index.js ( 导出所有钩子 )
│ │
│ └───📂 ui
│ │ └───📂 document
│ │ │ └───📂 elements
│ │ │ │ └───📂 settings
│ │ │ │ │ │ 📜 footer-saver-refresh-menu.js
│ │ │ │ │ │ ...
│ │ │ └───📂 save
│ │ │ │ └───📂 set-is-modfifed
│ │ │ │ │ │ 📜 update-button.js
│ │ │ │ │ │ ...
│ │ 📜 index.js ( 导出所有 ui 钩子 )
│ │ ...
│ └──📂 data
│ │ └───📂 document
│ │ │ └───📂 elements
│ │ │ │ └───📂 import
│ │ │ │ │ │ 📜 bypass-import.js
│ │ │ │ │ │ ...
│ │ │ └───📂 save
│ │ │ │ └───📂 save
│ │ │ │ │ │ 📜 save-extras.js
│ │ │ │ │ │ ...
│ │ 📜 index.js ( 导出所有 data 钩子 )
│ │ ...
component/hooks/index.js 文件第 5 行:
export * from './ui/';
export * from './data/';
component/hooks/ui/index.js 文件第 17 行:
export { FooterSeverRefreshMenu } from './document/elements/settings/footer-saver-refresh-menu';
export { UpdateButton } from './document/save/set-is-modifed/update-button';
component/hooks/data/index.js 文件第 29 行:
export { BypassImport } from './document/elements/import/bypass-import';
export { SaveExtras } from './document/save/save/save-extras';
使用 importHooks 示例:component/component.js 文件第 2 行:
import * as hooks from './hooks/';
export class Component extends $e.modules.ComponentBase {
getNamespace() {
return 'component-name';
}
defaultHooks() {
return this.importHooks( hooks );
}
}
Conventions
// {FILE_PATH}/{FILE_NAME} - This is line should be deleted - just for the example.
import HookUIAfter from 'elementor-api/modules/hooks/{TYPE}/after';
export class {FILE_NAME_CAMEL_CASE} extends HookUIAfter {
getCommand() {
return '{COMMAND}';
}
getId() {
return '{FILE_NAME_WITHOUT_JS}--{COMMAND}';
}
getContainerType() {
return '{CONTAINER_TYPE}';
}
getConditions( args ) {
return args.settings && 'undefined' !== typeof args.settings.post_status;
}
apply( args ) {
const { footerSaver } = $e.components.get( 'document/save' );
footerSaver.setMenuItems( args.container.document );
footerSaver.refreshWpPreview();
}
}
export default {FILE_NAME_CAMEL_CASE};
Legend
| Name | Format - Description | Value for example. |
|---|---|---|
{TYPE} |
ui or data depends on the hook |
ui |
{COMMAND} |
which command to hook | document/elements/settings |
{FILE_NAME} |
kebab case, name is description oh what the hook does | footer-saver-refresh-menu.js |
{FILE_NAME_CAMEL_CASE} |
camel case, of {FILE_NAME} |
FooterSaverRefreshMenu |
{FILE_NAME_WITHOUT_JS} |
{FILE_NAME} without .js |
footer-saver-refresh-menu |
{FILE_PATH} |
{TYPE}/{COMMAND}/{FILE_NAME} |
ui/document/elements/settings/footer-saver-refresh-menu.js |
{CONTAINER_TYPE} |
optional, gain performance if container type is known in advance | document |
示例
// ui/document/elements/settings/footer-saver-refresh-menu.js - 此行应删除 - 仅用于示例。
import HookUIAfter from 'elementor-api/modules/hooks/ui/after';
export class FooterSaverRefreshMenu extends HookUIAfter {
getCommand() {
return 'document/elements/settings';
}
getId() {
return 'footer-save-refresh-menu--document/elements/settings';
}
getContainerType() {
return 'document';
}
getConditions( args ) {
return args.settings && 'undefined' !== typeof args.settings.post_status;
}
apply( args ) {
const { footerSaver } = $e.components.get( 'document/save' );
footerSaver.setMenuItems( args.container.document );
footerSaver.refreshWpPreview();
}
}
export default FooterSaverRefreshMenu; // 必需 - 注释应删除。
::: warning 注意
关于如何使用钩子的更多信息,可根据其类型在 {$e.hooks.ui} 和 {$e.hooks.data} 中找到。
:::
Elementor Managers
Elementor is an extendable framework. It offers an architecture which allows external developers to add new functionality with addons. To do that, you need to create a new class for your component, which extends the base class and inherits its methods. You then need to register the class using the component manager, informing Elementor of its existence.
Registering Elements
Each component has its own manager that holds all the references to all the registered elements. To register your own element, you need to access the registration method in the component manager.
To simplify the process, Elementor adopted a standard way to register new component elements. All you need to do is to hook to manager using a action hook, pass a callback function that imports your class and then registers the class using the component manager.
function register_something( $some_manager ) {
require_once( __DIR__ . '/something/something-1.php' );
require_once( __DIR__ . '/something/something-2.php' );
$some_manager->register( new \Elementor_Something_1() );
$some_manager->register( new \Elementor_Something_2() );
}
add_action( 'elementor/something/register', 'register_something' );
Managers
Check out the different elements you can register, and how to register them properly:
Registering Controls
When you create new Elementor controls you must register them. This is done by hooking to the registration hook in the controls manager and passing a new control instance.
Registering New Controls
Developers should use the following code to register new controls:
/**
* Register new Elementor controls.
*
* @param \Elementor\Controls_Manager $controls_manager Elementor controls manager.
* @return void
*/
function register_new_controls( $controls_manager ) {
require_once( __DIR__ . '/controls/control-1.php' );
require_once( __DIR__ . '/controls/control-2.php' );
$controls_manager->register( new \Elementor_Control_1() );
$controls_manager->register( new \Elementor_Control_2() );
}
add_action( 'elementor/controls/register', 'register_new_controls' );
This code hooks to the elementor/controls/register action hook which holds the controls manager. The manager then registers the new controls by passing the control instances.
Registering Dynamic Tags
When you create new dynamic tags, you must register them. This is done by hooking to the registration hook in the dynamic tags manager and passing a new dynamic tag instance.
Registering New Dynamic Tags
Developers should use the following code to register new dynamic tags:
/**
* Register new Elementor dynamic tags.
*
* @param \Elementor\Core\DynamicTags\Manager $dynamic_tags_manager Elementor dynamic tags manager.
* @return void
*/
function register_new_dynamic_tags( $dynamic_tags_manager ) {
require_once( __DIR__ . '/dynamic-tags/dynamic-tag-1.php' );
require_once( __DIR__ . '/dynamic-tags/dynamic-tag-2.php' );
$dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_1() );
$dynamic_tags_manager->register( new \Elementor_Dynamic_Tag_2() );
}
add_action( 'elementor/dynamic_tags/register', 'register_new_dynamic_tags' );
This code hooks to the elementor/dynamic_tags/register action hook which holds the dynamic tags manager. The manager registers new dynamic tags by passing the dynamic tag instance.
注册查找器类别
当你创建新的查找器类别时,必须注册它们。这需要通过挂载到查找器管理器中的注册钩子,并传递一个新的查找器类别实例来完成。
注册新的查找器类别
开发者应使用以下代码来注册新的查找器类别:
/**
* 注册新的 Elementor 查找器类别。
*
* @param \Elementor\Core\Common\Modules\Finder\Categories_Manager $finder_categories_manager Elementor 查找器类别管理器。
* @return void
*/
function register_new_finder_categories( $finder_categories_manager ) {
require_once( __DIR__ . '/finder/finder-1.php' );
require_once( __DIR__ . '/finder/finder-2.php' );
$finder_categories_manager->register( new \Elementor_Finder_Category_1() );
$finder_categories_manager->register( new \Elementor_Finder_Category_2() );
}
add_action( 'elementor/finder/register', 'register_new_finder_categories' );
这段代码挂载到 elementor/finder/register 动作钩子,该钩子持有查找器类别管理器。然后管理器通过传递查找器类别实例来注册新的查找器类别。
Registering Widgets
When you create new Elementor widgets, you must register them. This is done by hooking to the registration hook in the widgets manager and passing a new widget instance.
Registering New Widgets
Developers should use the following code to register new widgets:
/**
* Register new Elementor widgets.
*
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
* @return void
*/
function register_new_widgets( $widgets_manager ) {
require_once( __DIR__ . '/widgets/widget-1.php' );
require_once( __DIR__ . '/widgets/widget-2.php' );
$widgets_manager->register( new \Elementor_Widget_1() );
$widgets_manager->register( new \Elementor_Widget_2() );
}
add_action( 'elementor/widgets/register', 'register_new_widgets' );
This code hooks to the elementor/widgets/register action hook which holds the widgets manager. The manager then registers new widgets by passing the widget instance.
Unregistering Controls
Developers can remove Elementor controls from the list of registered controls. This is done by hooking to the control manager and unregistering specific controls by passing the control ID.
Unregistering Existing Controls
Developers should use the following code to unregister existing controls:
/**
* Unregister Elementor controls.
*
* @param \Elementor\Controls_Manager $controls_manager Elementor controls manager.
* @return void
*/
function unregister_controls( $controls_manager ) {
$controls_manager->unregister( 'control-1' );
$controls_manager->unregister( 'control-2' );
}
add_action( 'elementor/controls/register', 'unregister_controls' );
This code hooks to the elementor/controls/register action hook which holds the control manager. The manager then unregisters controls by passing the control ID.
Unregistering Dynamic Tags
Developers can remove dynamic tags from the list of registered dynamic tags. This is done by hooking to the dynamic tags manager and unregistering specific dynamic tags by passing dynamic tag name.
Unregistering Existing Dynamic Tags
Developers should use the following code to unregister existing dynamic tags:
/**
* Unregister Elementor dynamic tags.
*
* @param \Elementor\Core\DynamicTags\Manager $dynamic_tags_manager Elementor dynamic tags manager.
* @return void
*/
function unregister_dynamic_tags( $dynamic_tags_manager ) {
$dynamic_tags_manager->unregister( 'dynamic-tag-1' );
$dynamic_tags_manager->unregister( 'dynamic-tag-2' );
}
add_action( 'elementor/dynamic_tags/register', 'unregister_dynamic_tags' );
This code hooks to the elementor/dynamic_tags/register action hook which holds the dynamic tags manager. The manager then unregisters the dynamic tag by passing the dynamic tag name.
Unregistering Finder Categories
Developers can remove finder categories from the list of registered categories. This is done by hooking to the finder categories manager and unregistering specific category by passing the category name.
Unregistering Existing Finder Categories
Developers should use the following code to unregister existing categories:
/**
* Unregister Elementor finder categories.
*
* @param \Elementor\Core\Common\Modules\Finder\Categories_Manager $finder_categories_manager Elementor finder categories manager.
* @return void
*/
function unregister_finder_categories( $finder_categories_manager ) {
$finder_categories_manager->unregister( 'finder-category-1' );
$finder_categories_manager->unregister( 'finder-category-2' );
}
add_action( 'elementor/finder/register', 'unregister_finder_categories' );
This code hooks to the elementor/finder/register action hook which holds the finder categories manager. The manager then unregisters finder categories by passing the category name.
Unregistering Widgets
Developers can remove Elementor widgets from the list of registered widgets. This is done by hooking to the widget manager and unregistering specific widgets by passing the widget name.
Unregistering Existing Widgets
Developers should use the following code to unregister existing widgets:
/**
* Unregister Elementor widgets.
*
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
* @return void
*/
function unregister_widgets( $widgets_manager ) {
$widgets_manager->unregister( 'widget-1' );
$widgets_manager->unregister( 'widget-2' );
}
add_action( 'elementor/widgets/register', 'unregister_widgets' );
This code hooks to the elementor/widgets/register action hook which holds the widget manager. The manager then unregisters widgets by passing the widget name.
Remove Unused Widgets
To remove multiple widgets that are not used in your site, you can run a "foreach" loop with a list of widget names.
/**
* Unregister multiple unused widgets.
*
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
* @return void
*/
function remove_unused_widgets( $widgets_manager ) {
$widgets_to_unregister = [
// 'common',
// 'inner-section',
// 'heading',
// 'image',
// 'text-editor',
// 'video',
// 'button',
// 'divider',
// 'spacer',
// 'image-box',
// 'google_maps',
// 'icon',
// 'icon-box',
// 'star-rating',
// 'image-carousel',
// 'image-gallery',
// 'icon-list',
// 'counter',
// 'progress',
// 'testimonial',
// 'tabs',
// 'accordion',
// 'toggle',
// 'social-icons',
// 'alert',
// 'audio',
// 'shortcode',
// 'html',
// 'menu-anchor',
// 'sidebar',
// 'read-more',
];
foreach ( $widgets_to_unregister as $widget ) {
$widgets_manager->unregister( $widget );
}
}
add_action( 'elementor/widgets/register', 'remove_unused_widgets' );
Developers can use this logic and build a UI around it to create a visual widgets manager.
Control Scripts
When you create new Elementor controls and need to register custom scripts, they must be registered using the wp_register_script() function and enqueued using the wp_enqueue_script() function. To ensure that Elementor only loads the scripts in the editor, use the control enqueue() method.
Registering Control Scripts
In the example below, we'll register scripts when creating new controls:
function my_plugin_register_control_scripts() {
wp_register_script( 'control-script-1', plugins_url( 'assets/js/control-script-1.js', __FILE__ ) );
wp_register_script( 'control-script-2', plugins_url( 'assets/js/control-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_register_control_scripts' );
Then, the control class will enqueue the scripts:
class Elementor_Test_Control extends \Elementor\Base_Control {
protected function enqueue(): void {
wp_enqueue_script( 'control-script-1' );
wp_enqueue_script( 'control-script-2' );
}
}
Control Styles
When you create new Elementor controls and need to register custom stylesheets, they must be registered using the wp_register_style() function and enqueued using wp_enqueue_style() function. To ensure that Elementor loads the stylesheets only in the editor, use the control enqueue() method.
Registering Control Styles
In the example below, we'll register stylesheets when creating new controls:
function my_plugin_register_control_styles() {
wp_register_style( 'control-style-1', plugins_url( 'assets/css/control-style-1.css', __FILE__ ) );
wp_register_style( 'control-style-2', plugins_url( 'assets/css/control-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_register_control_styles' );
Then, the control class will enqueue the styles:
class Elementor_Test_Control extends \Elementor\Base_Control {
protected function enqueue(): void {
wp_enqueue_style( 'control-style-1' );
wp_enqueue_style( 'control-style-2' );
}
}
Editor Scripts
When you develop addons that extend Elementor Editor and you have custom scripts, use elementor/editor/before_enqueue_scripts or elementor/editor/after_enqueue_scripts action hooks, which are fired when editor scripts are registered and enqueued.
Registering Editor Scripts
In the example below, we'll register and enqueue custom scripts before Elementor scripts are registered and enqueued:
function my_plugin_register_editor_scripts() {
wp_register_script( 'editor-script-1', plugins_url( 'assets/js/editor-script-1.js', __FILE__ ) );
wp_register_script( 'editor-script-2', plugins_url( 'assets/js/editor-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_register_editor_scripts' );
function my_plugin_enqueue_editor_scripts() {
wp_enqueue_script( 'editor-script-1' );
wp_enqueue_script( 'editor-script-2' );
}
add_action( 'elementor/editor/before_enqueue_scripts', 'my_plugin_enqueue_editor_scripts' );
Now we'll register and enqueue custom scripts after Elementor scripts are registered and enqueued:
function my_plugin_register_editor_scripts() {
wp_register_script( 'editor-script-1', plugins_url( 'assets/js/editor-script-1.js', __FILE__ ) );
wp_register_script( 'editor-script-2', plugins_url( 'assets/js/editor-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_register_editor_scripts' );
function my_plugin_enqueue_editor_scripts() {
wp_enqueue_script( 'editor-script-1' );
wp_enqueue_script( 'editor-script-2' );
}
add_action( 'elementor/editor/after_enqueue_scripts', 'my_plugin_enqueue_editor_scripts' );
编辑器样式
当你开发扩展 Elementor 编辑器 的插件并拥有自定义样式表时,请使用 elementor/editor/before_enqueue_styles 或 elementor/editor/after_enqueue_scripts 动作钩子,这些钩子会在编辑器样式注册和入队时触发。
注册编辑器样式
在下面的示例中,我们将在 Elementor 样式注册和入队之前注册并加入自定义样式表:
function my_plugin_register_editor_styles() {
wp_register_style( 'editor-style-1', plugins_url( 'assets/css/editor-style-1.css', __FILE__ ) );
wp_register_style( 'editor-style-2', plugins_url( 'assets/css/editor-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'elementor/editor/before_register_styles', 'my_plugin_register_editor_styles' );
function my_plugin_enqueue_editor_styles() {
wp_enqueue_style( 'editor-style-1' );
wp_enqueue_style( 'editor-style-2' );
}
add_action( 'elementor/editor/before_enqueue_styles', 'my_plugin_enqueue_editor_styles' );
现在,我们将在 Elementor 样式注册和入队之后注册并加入自定义样式表:
function my_plugin_register_editor_styles() {
wp_register_style( 'editor-style-1', plugins_url( 'assets/css/editor-style-1.css', __FILE__ ) );
wp_register_style( 'editor-style-2', plugins_url( 'assets/css/editor-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'elementor/editor/after_register_styles', 'my_plugin_register_editor_styles' );
function my_plugin_enqueue_editor_styles() {
wp_enqueue_style( 'editor-style-1' );
wp_enqueue_style( 'editor-style-2' );
}
add_action( 'elementor/editor/after_enqueue_styles', 'my_plugin_enqueue_editor_styles' );
Frontend Scripts
Some addons have custom frontend scripts loaded on pages built with Elementor. Use elementor/frontend/before_enqueue_scripts or elementor/frontend/after_enqueue_scripts action hooks, which are fired when Elementor frontend scripts are registered and enqueued.
Registering Frontend Scripts
In the example below, we'll register and enqueue custom scripts before Elementor frontend scripts are registered and enqueued:
function my_plugin_register_frontend_scripts() {
wp_register_script( 'frontend-script-1', plugins_url( 'assets/js/frontend-script-1.js', __FILE__ ) );
wp_register_script( 'frontend-script-2', plugins_url( 'assets/js/frontend-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
}
add_action( 'elementor/frontend/before_register_scripts', 'my_plugin_register_frontend_scripts' );
function my_plugin_enqueue_frontend_scripts() {
wp_enqueue_script( 'frontend-script-1' );
wp_enqueue_script( 'frontend-script-2' );
}
add_action( 'elementor/frontend/before_enqueue_scripts', 'my_plugin_enqueue_frontend_scripts' );
Now we'll register and enqueue custom scripts after Elementor frontend scripts are registered and enqueued:
function my_plugin_register_frontend_scripts() {
wp_register_script( 'frontend-script-1', plugins_url( 'assets/js/frontend-script-1.js', __FILE__ ) );
wp_register_script( 'frontend-script-2', plugins_url( 'assets/js/frontend-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
}
add_action( 'elementor/frontend/after_register_scripts', 'my_plugin_register_frontend_scripts' );
function my_plugin_enqueue_frontend_scripts() {
wp_enqueue_script( 'frontend-script-1' );
wp_enqueue_script( 'frontend-script-2' );
}
add_action( 'elementor/frontend/after_enqueue_scripts', 'my_plugin_enqueue_frontend_scripts' );
::: warning Please Note Those scripts will be loaded on all pages built with Elementor. To reduce performance impact, make sure you minify the files. :::
Frontend Styles
When using custom stylesheets, they must be registered to all pages using Elementor. Use the elementor/frontend/before_enqueue_styles or elementor/frontend/after_enqueue_styles action hooks, which are fired when Elementor frontend styles are registered and enqueued.
Registering Frontend Styles
In the example below, we'll register and enqueue custom stylesheets before Elementor frontend styles are registered and enqueued:
function my_plugin_register_frontend_styles() {
wp_register_style( 'frontend-style-1', plugins_url( 'assets/css/frontend-style-1.css', __FILE__ ) );
wp_register_style( 'frontend-style-2', plugins_url( 'assets/css/frontend-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'elementor/frontend/before_register_styles', 'my_plugin_register_frontend_styles' );
function my_plugin_enqueue_frontend_styles() {
wp_enqueue_style( 'frontend-style-1' );
wp_enqueue_style( 'frontend-style-2' );
}
add_action( 'elementor/frontend/before_enqueue_styles', 'my_plugin_enqueue_frontend_styles' );
Now we'll register and enqueue custom stylesheets after Elementor frontend styles are registered and enqueued:
function my_plugin_register_frontend_stylesheets() {
wp_register_style( 'frontend-style-1', plugins_url( 'assets/css/frontend-style-1.css', __FILE__ ) );
wp_register_style( 'frontend-style-2', plugins_url( 'assets/css/frontend-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'elementor/frontend/after_register_styles', 'my_plugin_register_frontend_stylesheets' );
function my_plugin_enqueue_frontend_stylesheets() {
wp_enqueue_style( 'frontend-style-1' );
wp_enqueue_style( 'frontend-style-2' );
}
add_action( 'elementor/frontend/after_enqueue_styles', 'my_plugin_enqueue_frontend_stylesheets' );
::: warning Please Note These stylesheets will be loaded on all pages built with Elementor. To reduce performance impact, make sure you minify the files. :::
Scripts & Styles
Just like WordPress, Elementor has special hooks to register custom scripts and styles. It's very important to use the correct hook in order to improve site performance. Using Elementor recommendations and best practices helps Elementor enqueue files dynamically only when they are used, reducing performance impact.
Static vs. Dynamic Loading
Some scripts should always be loaded, others only when used. For example, editor scripts should always be loaded, while widget scripts should only be loaded when they are being used. Elementor allows developers the freedom of choosing either method.
Each script and stylesheet increases the page size. This is why it is best practice to register assets and let Elementor decide whether or not to load them. Elementor checks to see if the page uses an element requiring your script, and only then it is loaded.
Frontend Scripts & Styles
Learn more about registering new scripts and styles to frontend pages:
Editor Scripts & Styles
Learn more about registering new scripts and styles to the Elementor Editor:
Preview Scripts & Styles
Learn more about registering new scripts and styles to Elementor preview:
Widget Scripts & Styles
Learn more about registering custom scripts and styles to Elementor widgets:
Controls Scripts & Styles
Learn more about registering custom scripts and styles to Elementor controls:
预览脚本
当你开发扩展 Elementor 预览 的插件并需要注册自定义脚本时,请使用 elementor/preview/enqueue_scripts 动作钩子,该钩子在预览脚本注册和入队时触发。
注册预览脚本
在下面的示例中,我们将在 Elementor 脚本注册和入队后,注册并入队自定义脚本:
function my_plugin_register_preview_scripts() {
wp_register_script( 'preview-script-1', plugins_url( 'assets/js/preview-script-1.js', __FILE__ ) );
wp_register_script( 'preview-script-2', plugins_url( 'assets/js/preview-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_register_preview_scripts' );
function my_plugin_enqueue_preview_scripts() {
wp_enqueue_script( 'preview-script-1' );
wp_enqueue_script( 'preview-script-2' );
}
add_action( 'elementor/preview/enqueue_scripts', 'my_plugin_enqueue_preview_scripts' );
预览样式
当你开发扩展 Elementor 预览 的插件,并且需要注册自定义样式表时,请使用 elementor/preview/enqueue_styles 动作钩子。该钩子在 Elementor 预览样式被注册和入队时触发。
注册预览样式
在下面的示例中,我们将在 Elementor 预览样式被注册和入队后,注册并加入自定义样式表:
function my_plugin_register_preview_styles() {
wp_register_style( 'preview-style-1', plugins_url( 'assets/css/preview-style-1.css', __FILE__ ) );
wp_register_style( 'preview-style-2', plugins_url( 'assets/css/preview-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_register_preview_styles' );
function my_plugin_enqueue_preview_styles() {
wp_enqueue_style( 'preview-style-1' );
wp_enqueue_style( 'preview-style-2' );
}
add_action( 'elementor/preview/enqueue_styles', 'my_plugin_enqueue_preview_styles' );
Widget Scripts
When you develop new Elementor widgets and need to register custom scripts, they must be registered using the wp_register_script() function and set as dependencies using the widget get_script_depends() method. This way, Elementor will dynamically load these scripts only on pages using these widgets.
Registering Widget Scripts
In the example below, we'll register the required scripts in the main file:
function my_plugin_register_widget_scripts() {
wp_register_script( 'widget-script-1', plugins_url( 'assets/js/widget-script-1.js', __FILE__ ) );
wp_register_script( 'widget-script-2', plugins_url( 'assets/js/widget-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_register_widget_scripts' );
Then, the widget class will set the JS dependencies:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_script_depends(): array {
return [ 'widget-script-1', 'widget-script-2' ];
}
}
Addon developers should not enqueue widget script dependencies themselves. Only Elementor enqueue these JS files, and only on pages using the widget.
Widget Styles
When you develop new Elementor widgets and need to register custom stylesheets, they must be registered using the wp_register_style() function and set as dependencies using the widget get_style_depends() method. This way, Elementor will dynamically load these stylesheets only on pages using these widgets.
Registering Widget Styles
In the example below, we'll register the required stylesheets in the main file:
function my_plugin_register_widget_styles() {
wp_register_style( 'widget-style-1', plugins_url( 'assets/css/widget-style-1.css', __FILE__ ) );
wp_register_style( 'widget-style-2', plugins_url( 'assets/css/widget-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'my_plugin_register_widget_styles' );
Then, the widget class will set the CSS dependencies:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_style_depends(): array {
return [ 'widget-style-1', 'widget-style-2' ];
}
}
Addon developers don't enqueue widget style dependencies themselves. Only Elementor enqueue these CSS files, and only on pages using the widget.
Add New Condition
Elementor's template display mechanism has several built-in conditions, but external developers can create and register their own conditions.
Registering Conditions
To register new conditions, you just need to initiate the condition class:
function register_new_theme_conditions( $conditions_manager ) {
require_once( __DIR__ . '/theme-conditions/condition-1.php' );
require_once( __DIR__ . '/theme-conditions/condition-2.php' );
$conditions_manager->get_condition( 'general' )->register_sub_condition( new \Condition_1() );
$conditions_manager->get_condition( 'general' )->register_sub_condition( new \Condition_2() );
}
add_action( 'elementor/theme/register_conditions', 'register_new_theme_conditions' );
This code snippet hooks to the elementor/theme/register_conditions action hook which holds the conditions manager. The manager then registers the condition by initiating new condition instances.
Registering Sub-Conditions
There are two ways to register sub-conditions, either from the conditions manager or from the condition class itself.
To register sub-conditions from the manager, use the following code:
function register_new_theme_conditions( $conditions_manager ) {
require_once( __DIR__ . '/theme-conditions/main-condition.php' );
require_once( __DIR__ . '/theme-conditions/sub-condition-1.php' );
require_once( __DIR__ . '/theme-conditions/sub-condition-2.php' );
$conditions_manager
->get_condition( 'general' )
->register_sub_condition( new \Main_Condition() );
$conditions_manager
->get_condition( 'main_condition_name' )
->register_sub_condition( new \Sub_Condition_1() );
$conditions_manager
->get_condition( 'main_condition_name' )
->register_sub_condition( new \Sub_Condition_2() );
}
add_action( 'elementor/theme/register_conditions', 'register_new_theme_conditions' );
To register sub-conditions from the main condition class, see the sub-conditions section.
进阶示例
针对更高级的用例,我们将创建一个插件,根据已登录访问者的角色来注册条件。该插件将帮助 Elementor 用户仅向具有特定角色的访问者显示某些模板。
文件夹结构
该插件将包含三个文件。两个文件用于条件设置,主文件用于注册条件并处理所有其他事项。
elementor-user-role-conditions/
|
├─ theme-conditions/
| ├─ logged-in-user-condition.php
| └─ user-role-condition.php
|
└─ elementor-user-role-conditions.php
Plugin Files
elementor-user-role-conditions.php
<?php
/**
* Plugin Name: Elementor User Role Conditions
* Description: Custom addon that adds user role conditions to Elementor.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-user-role-conditions
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Add user role conditions to Elementor.
*
* @since 1.0.0
* @param \ElementorPro\Modules\ThemeBuilder\Classes\Conditions_Manager $conditions_manager An instance of conditions manager.
* @return void
*/
function add_new_user_role_conditions( $conditions_manager ) {
require_once( __DIR__ . '/theme-conditions/logged-in-user-condition.php' );
require_once( __DIR__ . '/theme-conditions/user-role-condition.php' );
$conditions_manager->get_condition( 'general' )->register_sub_condition( new \Logged_In_User_Condition() );
}
add_action( 'elementor/theme/register_conditions', 'add_new_user_role_conditions' );
theme-conditions/logged-in-user-condition.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Logged-In User Condition.
*
* Add a logged-in user condition to Elementor.
*
* @since 1.0.0
*/
class Logged_In_User_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
/**
* Get condition group type.
*
* Retrieve logged-in user condition group type.
*
* @since 1.0.0
* @access public
* @return string
*/
public static function get_type(): string {
return 'general';
}
/**
* Get condition name.
*
* Retrieve logged-in user condition unique ID.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_name(): string {
return 'logged_in_user';
}
/**
* Get condition label.
*
* Retrieve logged-in user condition label.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_label(): string {
return esc_html__( 'Logged-in User', 'elementor-user-role-conditions' );
}
/**
* Get condition all label.
*
* Retrieve logged-in user condition 'All' label.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_all_label(): string {
return esc_html__( 'Any user role', 'elementor-user-role-conditions' );
}
/**
* Register sub-conditions.
*
* Add sub-conditions based on user role.
*
* @since 1.0.0
* @access public
* @return void
*/
public function register_sub_conditions(): void {
global $wp_roles;
if ( ! isset( $wp_roles ) ) {
$wp_roles = new \WP_Roles();
}
$user_roles_list = $wp_roles->get_names();
foreach ( $user_roles_list as $role ) {
$this->register_sub_condition( new \User_Role_Condition( $role ) );
}
}
/**
* Check condition.
*
* Validate logged-in user condition to ensure it complies to certain rules.
*
* @since 1.0.0
* @access public
* @return bool
*/
public function check( $args ): bool {
return is_user_logged_in();
}
}
theme-conditions/user-role-condition.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor User Role Conditions.
*
* Add a user role conditions to Elementor.
*
* @since 1.0.0
*/
class User_Role_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
/**
* Condition constructor.
*
* Initialize user role condition.
*
* @since 1.0.0
* @access public
* @return string
*/
public function __construct( $user_role ) {
parent::__construct();
$this->user_role = $user_role;
}
/**
* Get condition group type.
*
* Retrieve user role condition group type.
*
* @since 1.0.0
* @access public
* @return string
*/
public static function get_type(): string {
return 'logged_in_user';
}
/**
* Get condition name.
*
* Retrieve user role condition unique ID.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_name(): string {
return strtolower( $this->user_role . '_role' );
}
/**
* Get condition label.
*
* Retrieve user role condition label.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_label(): string {
/* translators: %s: User role label. */
return sprintf( esc_html__( '%s role', 'elementor-user-role-conditions' ), $this->user_role );
}
/**
* Check condition.
*
* Validate user role condition to ensure it complies to certain rules.
*
* @since 1.0.0
* @access public
* @return bool
*/
public function check( $args ): bool {
$current_user = wp_get_current_user();
$site_roles = (array) $current_user->roles;
return in_array( $this->user_role, $site_roles );
}
}
The Result
The "Logged-In User" > "User Roles" conditions:
The "User Roles" list:
Condition Check
Elementor runs a series of checks to ensure that conditions comply with a certain set of rules. The check() method sets these checks.
Check Method
The method that triggers this condition process is called check(). In your condition class, use the method as follows:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public function check( $args ): bool {
return true;
}
}
If the condition check is valid, the template will be applied.
Checking Conditions
Developers can add any type of condition checking. Let's see some examples.
Front Page
In the example below, we'll check to see if it's a front page:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public function check( $args ): bool {
return is_front_page();
}
}
404 Page
In the following example we'll check to see if it's a 404 page:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public function check( $args ): bool {
return is_404();
}
}
Embed Page
In this example we'll check to see if it's an embed page:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public function check( $args ): bool {
return is_embed();
}
}
SSL Page
We can use server variables to check and see if the page was accessed with SSL:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public function check( $args ): bool {
return empty( $_SERVER['HTTPS'] );
}
}
User Browser
We can apply different templates for different browsers by checking the user's browser:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public function check( $args ): bool {
$browser = get_browser(null, true);
$is_firefox = ( $browser['browser'] === 'Firefox' );
return $is_firefox;
}
}
条件数据
每个条件都包含基本信息,例如条件的唯一 ID 和条件标签。这些数据在代码中使用,并在编辑器中显示给用户。
数据方法
条件数据需要通过特定方法"返回"。这些方法很简单:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public function get_name(): string {
return 'condition_name';
}
public function get_label(): string {
return esc_html__( 'My Condition Name', 'textdomain' );
}
}
-
条件类型 –
get_type()方法返回将在代码中使用的条件名称(ID)。 -
条件名称 –
get_name()方法返回将显示给用户的条件标签。
Condition Group Type
Conditions are grouped by type. There are several pre-defined types to choose from, based on the WordPress Template Hierarchy. When creating a new condition, we have to assign the condition to a specific type.
Group Method
Condition group is defined by the following method:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public static function get_type(): string {
return 'condition_type';
}
public static function get_priority(): int {
return 40;
}
}
-
Condition Group Type – The
get_type()method returns the condition group type. -
Condition Priority – The
get_priority()method priorotize the condition in a group type.
Available Condition Groups
When you select which group to assign your condition to, you can select one of the following:
| ID | Label | Description |
|---|---|---|
>general |
> General | |
>> general |
>> Entire Site | Condition to display the template across all pages. |
>> archive |
>> Archives | Condition to display the template on archive pages. |
>> singular |
>> Singular | Condition to display the template on singular pages. |
Conditions Tree
We are basically creating a tree of conditions. Each time we add a sub-condition, we expand the tree. get_type() method tells us which group the condition belongs to.
Conditions Priority
When several sub-conditions are nested inside a group type or inside a condition, their display order can be controlled using the priority method.
Built-in conditions use a priority ranging between 0 to 100. When the get_priority() method is not defined, the default priority inherited from its the base class, there it returns 100.
Condition Structure
Each condition needs to have a few basic settings, such as a unique name and label. In addition, a condition should be assigned to a group. A condition could have sub-conditions. The final, and most important, is the check method that checks whether the condition complies with a set of predefined rules.
Theme Condition Class
First, we need to create a class that extends the \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base class:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
}
Theme Condition Structure
As mentioned above, conditions extend the \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base class and inherit its methods. A simple condition skeleton will look as follows:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public static function get_type(): string {}
public function get_priority(): int {}
public function get_name(): string {}
public function get_label(): string {}
public function get_all_label(): string {}
public function register_sub_conditions(): void {}
public function check( $args ): bool {}
}
Let’s break it down:
-
Condition Type – The
get_type()method returns the condition group type. -
Condition Priority – The
get_priority()method prioritize the condition in a group type. -
Condition Name – The
get_name()method returns the condition name (id) that will be used in the code. -
Condition Label – The
get_label()method returns the condition label that will be displayed to the user. -
Condition All Label – The
get_all_label()method returns the all/any label that will be displayed to the user, if the condition has sub-conditions. -
Condition Check – The
check()method is the actual method that checks if the condition complies to a certain set of rules. -
Sub-Conditions – The
register_sub_conditions()method registers sub-conditions.
Please note that the Condition_Base class has many more methods developers can use, but the methods mentioned above will cover the vast majority of your needs.
Theme Conditions
Elementor Pro 2.0 introduced a condition-based template display mechanism. This allows users to specify under what conditions a template will be displayed. The conditions built into the mechanism cover most of the native WordPress Template Hierarchy, but sometimes you need more control with more specific conditions.
Elementor Pro provides a set of tools for external developers to create and register custom theme conditions.
Condition Usage
Conditions determine where templates are displayed on a site, where popups are embedded and where code snippets are included. These conditions are used in the Elementor Theme Builder, Elementor Popups and Elementor Custom Code.
When defining the display conditions, multiple conditions can be selected by clicking the "Add Condition" button. These conditions can be either included or excluded, thus creating complex display rules.
Managing Conditions
External developers can register new conditions. Learn how to do that:
Creating Conditions
Learn more about condition anatomy and how to create your own:
Code Examples
Check out how easy it is to add new conditions:
简单示例
为演示扩展主题条件是多么简单,我们将创建一个插件来注册一个条件,用于检查访问者是否已登录。该插件将帮助 Elementor 用户向已登录访问者显示某些模板,而向匿名访问者显示其他模板。
文件夹结构
该插件将包含两个文件。一个文件用于处理已登录用户条件,另一个主文件则负责注册该条件并处理所有其他功能。
elementor-logged-in-user-condition/
|
├─ theme-conditions/
| └─ logged-in-user-condition.php
|
└─ elementor-logged-in-user-condition.php
Plugin Files
elementor-logged-in-user-condition.php
<?php
/**
* Plugin Name: Elementor Logged-In User Condition
* Description: Custom addon that adds a logged-in user condition to Elementor.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-logged-in-user-condition
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Add a logged-in user condition to Elementor.
*
* @since 1.0.0
* @param \ElementorPro\Modules\ThemeBuilder\Classes\Conditions_Manager $conditions_manager An instance of conditions manager.
* @return void
*/
function add_new_logged_in_user_condition( $conditions_manager ) {
require_once( __DIR__ . '/theme-conditions/logged-in-user-condition.php' );
$conditions_manager->get_condition( 'general' )->register_sub_condition( new \Logged_In_User_Condition() );
}
add_action( 'elementor/theme/register_conditions', 'add_new_logged_in_user_condition' );
theme-conditions/logged-in-user-condition.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor Logged-In User Condition.
*
* Add a logged-in user condition to Elementor.
*
* @since 1.0.0
*/
class Logged_In_User_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
/**
* Get condition group type.
*
* Retrieve logged-in user condition group type.
*
* @since 1.0.0
* @access public
* @return string
*/
public static function get_type(): string {
return 'general';
}
/**
* Get condition name.
*
* Retrieve logged-in user condition unique ID.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_name(): string {
return 'logged_in_user';
}
/**
* Get condition label.
*
* Retrieve logged-in user condition label.
*
* @since 1.0.0
* @access public
* @return string
*/
public function get_label(): string {
return esc_html__( 'Logged-in user', 'elementor-logged-in-user-condition' );
}
/**
* Check condition.
*
* Validate logged-in user condition to ensure it complies with certain rules.
*
* @since 1.0.0
* @access public
* @return bool
*/
public function check( $args ): bool {
return is_user_logged_in();
}
}
The Result
The "Logged-In User" condition as displayed on the conditions screen:
Sub-Conditions
Conditions can have sub-conditions in order to narrow the conditions. For example, instead of applying a condition to all Singular pages, applying it only to Posts, or a specific post. Sub-conditions help the user focus the main condition.
Sub-Condition Methods
When conditions have sub-conditions, the condition class needs to use the following two methods:
class Elementor_Test_Condition extends \ElementorPro\Modules\ThemeBuilder\Conditions\Condition_Base {
public function get_all_label(): string {
return esc_html__( 'All Items', 'textdomain' );
}
public function register_sub_conditions(): void {
$this->register_sub_condition( new Elementor_Test_Sub_Condition_1(); );
$this->register_sub_condition( new Elementor_Test_Sub_Condition_2(); );
}
}
- Condition All Label – The
get_all_label()method returns the all/any label that will be displayed to the user, if the condition has sub-conditions.
- Sub-Conditions – The
register_sub_conditions()method registers sub-conditions.
Displaying Locations
Displaying Elementor locations in your theme is a simple process. The elementor_theme_do_location() function will display the location as defined by the user. In addition, theme developers can set fallback designs if a template was assigned to the location.
Simple Location Display
Let’s see how this is done in an empty theme with a header and a footer. In this case, we're going to implement an archive location in our archive.php file:
<?php
get_header();
// Elementor `archive` location
elementor_theme_do_location( 'archive' );
get_footer();
Location with a Fallback Design
Some themes have default designs. Users will be able to show either; the archive location designed in Elementor, or the regular theme layout (in case the user didn’t set an Elementor design for this location).
<?php
get_header();
// Elementor `archive` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'archive' ) ) {
get_template_part( 'template-parts/archive' );
}
get_footer();
Display New Location
Many themes have sidebars. We can let the user design this area using Elementor. This is done by registering new “main-sidebar” locations.
<?php get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<?php
// Elementor `single` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'single' ) ) {
get_template_part( 'template-parts/single' );
}
?>
</main>
<aside id="secondary" class="sidebar" role="complementary">
<?php
// Elementor `main-sidebar` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'main-sidebar' ) ) {
get_sidebar( 'main' );
}
?>
</aside>
</div>
<?php get_footer(); ?>
This is a simple example. You can also add new locations above the header for your top bars, custom locations for the footer, create your own content layout in single pages, and archive pages. These will allow the user to edit each location using Elementor. The possibilities are endless.
Theme Locations
Elementor Pro 2.0 introduced a theme builder. This feature transformed Elementor from a page-builder to a full site-builder.
Overview
Before the release of Elementor Pro 2.0, Elementor was a page-builder, only affecting the_content() of a single page. Elementor couldn't set global headers, global footers, design custom archive pages, search results, author pages, 404 pages etc.
The new theme builder functionality changed everything! It has greatly empowered users. They no longer have to rely on pre-designed themes, as they can design their own layouts using simple drag-and-drop functionality without any code.
Despite this development, theme usage did not drop. In fact, themes that adapted to this development saw an increase in overall usage and total downloads.
Every theme developer can make their theme Elementor compatible by supporting the theme locations functionality. They just need to add a few lines of code wrapping some elements. This will help Elementor replace theme elements with Elementor designs, allowing users to create their own designs.
Available Locations
Themes can support all core locations, some locations or create their own custom locations. The following are the built-in Elementor locations:
- Header – template header replaces the theme
header.phpfile. - Footer – template footer replaces the theme
footer.phpfile. - Single – template content replaces the theme
singular.php,single.php,page.php,attachment.phpand404.phpfiles. - Archive – template archive replaces the theme
archive.php,taxonomy.php,author.php,date.phpandsearch.phpfiles.
Managing Locations
Learn how to develop "Elementor Compatible" themes:
Theme Migration
Check out these examples to see how easy it is to migrate an existing theme and add Elementor support:
Migrating Themes with Functions
In this example, we'll add theme locations to the original theme using simple functions. After migration, the theme will look as follows:
Themes Files
The new function.php file:
<?php
function theme_prefix_register_elementor_locations( $elementor_theme_manager ) {
$elementor_theme_manager->register_all_core_location();
}
add_action( 'elementor/theme/register_locations', 'theme_prefix_register_elementor_locations' );
The new header.php file:
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="profile" href="http://gmpg.org/xfn/11">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php
// Elementor `header` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'header' ) ) {
get_template_part( 'template-parts/header' );
}
<?php
// Elementor `footer` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'footer' ) ) {
get_template_part( 'template-parts/footer' );
}
wp_footer();
?>
</body>
</html>
The new index.php file:
<?php
get_header();
if ( is_archive() || is_home() || is_search() ) {
// Elementor `archive` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'archive' ) ) {
get_template_part( 'template-parts/archive' );
}
} elseif ( is_singular() ) {
// Elementor `single` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'single' ) ) {
get_template_part( 'template-parts/single' );
}
} else {
// Elementor `404` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'single' ) ) {
get_template_part( 'template-parts/404' );
}
}
get_footer();
The new archive.php file:
<?php
get_header();
// Elementor `archive` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'archive' ) ) {
get_template_part( 'template-parts/archive' );
}
get_footer();
The new single.php file:
<?php
get_header();
// Elementor `single` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'single' ) ) {
get_template_part( 'template-parts/single' );
}
get_footer();
The new 404.php file:
<?php
get_header();
// Elementor `single` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'single' ) ) {
get_template_part( 'template-parts/404' );
}
get_footer();
The new search.php file:
<?php
get_header();
// Elementor `archive` location
if ( ! function_exists( 'elementor_theme_do_location' ) || ! elementor_theme_do_location( 'archive' ) ) {
get_template_part( 'template-parts/search' );
}
get_footer();
Migrating Themes with Hooks
In this example, we'll add theme locations to the original theme using hooks. After migration, the theme will look as follows:
Themes Files
The new function.php file:
<?php
// Register Elementor locations
function theme_prefix_register_elementor_locations( $elementor_theme_manager ) {
$elementor_theme_manager->register_location(
'header',
[
'hook' => 'theme_prefix_header',
'remove_hooks' => [ 'theme_prefix_print_elementor_header' ],
]
);
$elementor_theme_manager->register_location(
'footer',
[
'hook' => 'theme_prefix_footer',
'remove_hooks' => [ 'theme_prefix_print_elementor_footer' ],
]
);
$elementor_theme_manager->register_location(
'single',
[
'hook' => 'theme_prefix_single',
'remove_hooks' => [ 'theme_prefix_print_elementor_single' ],
]
);
$elementor_theme_manager->register_location(
'archive',
[
'hook' => 'theme_prefix_archive',
'remove_hooks' => [ 'theme_prefix_print_elementor_archive' ],
]
);
}
add_action( 'elementor/theme/register_locations', 'theme_prefix_register_elementor_locations' );
// Theme header
function theme_prefix_print_elementor_header() {
get_template_part( 'templates-parts/header' );
}
add_action( 'theme_prefix_header', 'theme_prefix_print_elementor_header' );
// Theme footer
function theme_prefix_print_elementor_footer() {
get_template_part( 'templates-parts/footer' );
}
add_action( 'theme_prefix_footer', 'theme_prefix_print_elementor_footer' );
// Single page
function theme_prefix_print_elementor_single() {
get_template_part( 'templates-parts/single' );
}
add_action( 'theme_prefix_single', 'theme_prefix_print_elementor_single' );
// Archive page
function theme_prefix_print_elementor_archive() {
get_template_part( 'templates-parts/archive' );
}
add_action( 'theme_prefix_archive', 'theme_prefix_print_elementor_archive' );
The new header.php file:
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="profile" href="http://gmpg.org/xfn/11">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php do_action( 'theme_prefix_header' ); ?>
<?php do_action( 'theme_prefix_footer' ); ?>
<?php wp_footer(); ?>
</body>
</html>
The new archive.php file:
<?php
get_header();
do_action( 'theme_prefix_archive' );
get_footer();
The new single.php file:
<?php
get_header();
do_action( 'theme_prefix_single' );
get_footer();
Migrating Themes
Now we'll see how to support Elementor theme locations in your theme. The logic behind the process is simple, you just need to wrap your code with an Elementor function/hook that checks to see if the user prefers using the Elementor template or the original theme design.
There are two ways to support Elementor locations - you can either use custom Elementor functions or hooks. Both ways will work. With hooks, the entire logic is in the functions.php file. With functions, the checks are inside the theme files.
Live Example
In the following, we'll look at some examples of theme migration:
Original Theme
To simplify the theme migration process, we stripped all custom code from the original theme (including the WordPress loop), and moved it to the /template-parts/ folder. This way the code snippets will be much shorter and simpler to understand.
Original Files
Original header.php file:
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="profile" href="http://gmpg.org/xfn/11">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php get_template_part( 'template-parts/header' ); ?>
<?php get_template_part( 'template-parts/footer' ); ?>
</body>
</html>
Original index.php file:
<?php
get_header();
if ( is_archive() || is_home() || is_search() ) {
get_template_part( 'template-parts/archive' );
} elseif ( is_singular() ) {
get_template_part( 'template-parts/single' );
} else {
get_template_part( 'template-parts/404' );
}
get_footer();
Original archive.php file:
<?php
get_header();
get_template_part( 'template-parts/archive' );
get_footer();
Original single.php file:
<?php
get_header();
get_template_part( 'template-parts/single' );
get_footer();
Original 404.php file:
<?php
get_header();
get_template_part( 'template-parts/404' );
get_footer();
Registering Locations
To support Elementor locations, the theme needs to register supported locations in the functions.php file. Theme developers can support all core locations, some locations or create new locations.
To register new locations, we need to hook to the elementor/theme/register_locations action and use either the register_all_core_location() method to register all the locations, or the register_location() method to register new locations.
Registering All Locations
Registering all core locations is done using the following code:
function theme_prefix_register_elementor_locations( $elementor_theme_manager ) {
$elementor_theme_manager->register_all_core_location();
}
add_action( 'elementor/theme/register_locations', 'theme_prefix_register_elementor_locations' );
Registering Some Locations
Registering some of the core locations is done using the following code:
function theme_prefix_register_elementor_locations( $elementor_theme_manager ) {
$elementor_theme_manager->register_location( 'header' );
$elementor_theme_manager->register_location( 'footer' );
// $elementor_theme_manager->register_location( 'single' );
// $elementor_theme_manager->register_location( 'archive' );
}
add_action( 'elementor/theme/register_locations', 'theme_prefix_register_elementor_locations' );
Registering New Locations
Registering new locations is done using the following code:
function theme_prefix_register_elementor_locations( $elementor_theme_manager ) {
$elementor_theme_manager->register_location(
'main-sidebar',
[
'label' => esc_html__( 'Main Sidebar', 'theme-name' ),
'multiple' => true,
'edit_in_content' => false,
]
);
}
add_action( 'elementor/theme/register_locations', 'theme_prefix_register_elementor_locations' );
Let’s see what each argument does:
- label (
string) – The location label in Elementor. - multiple (
bool) – Determines whether or not to display multiple locations. If set totrue, it will display the entire template belonging to this location. If set tofalseit will display only the best match. The default isfalse. - edit_in_content (
bool) – Determines whether or not to edit the template in the content area. If set totruethe template can be edited in the content area. If set tofalseit cannot. The default istrue.
Add New Widget
Elementor offers many built-in widgets out of the box, but it also allows external developers to register new widgets.
Hooks
To do that we simply hook to the elementor/widgets/register action which provides access to the widgets manager as a parameter. Developers can use the manager to add new widgets using the register() method with the widget instance.
Registering Widgets
To register new widgets use the following code:
function register_new_widgets( $widgets_manager ) {
require_once( __DIR__ . '/widgets/widget-1.php' );
require_once( __DIR__ . '/widgets/widget-2.php' );
$widgets_manager->register( new \Elementor_Widget_1() );
$widgets_manager->register( new \Elementor_Widget_2() );
}
add_action( 'elementor/widgets/register', 'register_new_widgets' );
The manager registers new widgets by accepting widget instances. For more information about the widget class, read about the widget class structure.
Advanced Example
For a more advanced example we will create a widget with a repeater field, to allow the user to generate a list with items. It will also have a conditional field display when choosing "other" marker type, to display a new control that let's the user enter a custom marker.
文件夹结构
该插件将包含两个文件:一个用于小部件,另一个主文件用于注册小部件。
elementor-list-widget/
|
├─ widgets/
| └─ list-widget.php
|
└─ elementor-list-widget.php
Plugin Files
elementor-list-widget.php
<?php
/**
* Plugin Name: Elementor List Widget
* Description: List widget for Elementor.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-list-widget
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register List Widget.
*
* Include widget file and register widget class.
*
* @since 1.0.0
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
* @return void
*/
function register_list_widget( $widgets_manager ) {
require_once( __DIR__ . '/widgets/list-widget.php' );
$widgets_manager->register( new \Elementor_List_Widget() );
}
add_action( 'elementor/widgets/register', 'register_list_widget' );
widgets/list-widget.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor List Widget.
*
* Elementor widget that inserts an embbedable content into the page, from any given URL.
*
* @since 1.0.0
*/
class Elementor_List_Widget extends \Elementor\Widget_Base {
/**
* Get widget name.
*
* Retrieve list widget name.
*
* @since 1.0.0
* @access public
* @return string Widget name.
*/
public function get_name(): string {
return 'list';
}
/**
* Get widget title.
*
* Retrieve list widget title.
*
* @since 1.0.0
* @access public
* @return string Widget title.
*/
public function get_title(): string {
return esc_html__( 'List', 'elementor-list-widget' );
}
/**
* Get widget icon.
*
* Retrieve list widget icon.
*
* @since 1.0.0
* @access public
* @return string Widget icon.
*/
public function get_icon(): string {
return 'eicon-bullet-list';
}
/**
* Get widget categories.
*
* Retrieve the list of categories the list widget belongs to.
*
* @since 1.0.0
* @access public
* @return array Widget categories.
*/
public function get_categories(): array {
return [ 'general' ];
}
/**
* Get widget keywords.
*
* Retrieve the list of keywords the list widget belongs to.
*
* @since 1.0.0
* @access public
* @return array Widget keywords.
*/
public function get_keywords(): array {
return [ 'list', 'lists', 'ordered', 'unordered' ];
}
/**
* Get custom help URL.
*
* Retrieve a URL where the user can get more information about the widget.
*
* @since 1.0.0
* @access public
* @return string Widget help URL.
*/
public function get_custom_help_url(): string {
return 'https://developers.elementor.com/docs/widgets/';
}
/**
* Get widget promotion data.
*
* Retrieve the widget promotion data.
*
* @since 1.0.0
* @access protected
* @return array Widget promotion data.
*/
protected function get_upsale_data(): array {
return [
'condition' => true,
'image' => esc_url( ELEMENTOR_ASSETS_URL . 'images/go-pro.svg' ),
'image_alt' => esc_attr__( 'Upgrade', 'elementor-list-widget' ),
'title' => esc_html__( 'Promotion heading', 'elementor-list-widget' ),
'description' => esc_html__( 'Get the premium version of the widget with additional styling capabilities.', 'elementor-list-widget' ),
'upgrade_url' => esc_url( 'https://example.com/upgrade-to-pro/' ),
'upgrade_text' => esc_html__( 'Upgrade Now', 'elementor-list-widget' ),
];
}
/**
* Whether the widget requires inner wrapper.
*
* Determine whether to optimize the DOM size.
*
* @since 1.0.0
* @access public
* @return bool Whether to optimize the DOM size.
*/
public function has_widget_inner_wrapper(): bool {
return false;
}
/**
* Whether the element returns dynamic content.
*
* Determine whether to cache the element output or not.
*
* @since 1.0.0
* @access protected
* @return bool Whether to cache the element output.
*/
protected function is_dynamic_content(): bool {
return false;
}
/**
* Register list widget controls.
*
* Add input fields to allow the user to customize the widget settings.
*
* @since 1.0.0
* @access protected
*/
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'List Content', 'elementor-list-widget' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
/* Start repeater */
$repeater = new \Elementor\Repeater();
$repeater->add_control(
'text',
[
'label' => esc_html__( 'Text', 'elementor-list-widget' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => esc_html__( 'List Item', 'elementor-list-widget' ),
'default' => esc_html__( 'List Item', 'elementor-list-widget' ),
'label_block' => true,
'dynamic' => [
'active' => true,
],
]
);
$repeater->add_control(
'link',
[
'label' => esc_html__( 'Link', 'elementor-list-widget' ),
'type' => \Elementor\Controls_Manager::URL,
'dynamic' => [
'active' => true,
],
]
);
/* End repeater */
$this->add_control(
'list_items',
[
'label' => esc_html__( '列表项', 'elementor-list-widget' ),
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => $repeater->get_controls(), /* 使用我们的重复器 */
'default' => [
[
'text' => esc_html__( '列表项 #1', 'elementor-list-widget' ),
'link' => '',
],
[
'text' => esc_html__( '列表项 #2', 'elementor-list-widget' ),
'link' => '',
],
[
'text' => esc_html__( '列表项 #3', 'elementor-list-widget' ),
'link' => '',
],
],
'title_field' => '{{{ text }}}',
]
);
$this->end_controls_section();
$this->start_controls_section(
'marker_section',
[
'label' => esc_html__( '列表标记', 'elementor-list-widget' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'marker_type',
[
'label' => esc_html__( '标记类型', 'elementor-list-widget' ),
'type' => \Elementor\Controls_Manager::CHOOSE,
'options' => [
'ordered' => [
'title' => esc_html__( '有序列表', 'elementor-list-widget' ),
'icon' => 'eicon-editor-list-ol',
],
'unordered' => [
'title' => esc_html__( '无序列表', 'elementor-list-widget' ),
'icon' => 'eicon-editor-list-ul',
],
'other' => [
'title' => esc_html__( '自定义列表', 'elementor-list-widget' ),
'icon' => 'eicon-edit',
],
],
'default' => 'ordered',
'toggle' => false,
]
);
$this->add_control(
'marker_content',
[
'label' => esc_html__( '自定义标记', 'elementor-list-widget' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => esc_html__( '输入自定义标记', 'elementor-list-widget' ),
'default' => '🧡',
'condition' => [
'marker_type[value]' => 'other',
],
'selectors' => [
'{{WRAPPER}} .elementor-list-widget-text::marker' => 'content: "{{VALUE}}";',
],
]
);
$this->end_controls_section();
$this->start_controls_section(
'style_content_section',
[
'label' => esc_html__( '列表样式', 'elementor-list-widget' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'title_color',
[
'label' => esc_html__( '颜色', 'elementor-list-widget' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .elementor-list-widget-text' => 'color: {{VALUE}};',
'{{WRAPPER}} .elementor-list-widget-text > a' => 'color: {{VALUE}};',
],
]
);
$this->add_group_control(
\Elementor\Group_Control_Typography::get_type(),
[
'name' => 'icon_typography',
'selector' => '{{WRAPPER}} .elementor-list-widget-text, {{WRAPPER}} .elementor-list-widget-text > a',
]
);
$this->add_group_control(
\Elementor\Group_Control_Text_Shadow::get_type(),
[
'name' => 'text_shadow',
'selector' => '{{WRAPPER}} .elementor-list-widget-text',
]
);
$this->end_controls_section();
$this->start_controls_section(
'style_marker_section',
[
'label' => esc_html__( '标记样式', 'elementor-list-widget' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'marker_color',
[
'label' => esc_html__( '颜色', 'elementor-list-widget' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .elementor-list-widget-text::marker' => 'color: {{VALUE}};',
],
]
);
$this->add_control(
'marker_spacing',
[
'label' => esc_html__( '间距', 'elementor-list-widget' ),
'type' => \Elementor\Controls_Manager::SLIDER,
'size_units' => [ 'px', 'em', 'rem', 'custom' ],
'range' => [
'px' => [
'min' => 0,
'max' => 100,
],
'em' => [
'min' => 0,
'max' => 10,
],
'rem' => [
'min' => 0,
'max' => 10,
],
],
'default' => [
'unit' => 'px',
'size' => 40,
],
'selectors' => [
// '{{WRAPPER}} .elementor-list-widget' => 'padding-left: {{SIZE}}{{UNIT}};',
'{{WRAPPER}} .elementor-list-widget' => 'padding-inline-start: {{SIZE}}{{UNIT}};',
],
]
);
$this->end_controls_section();
}
/**
* 在前端渲染列表小部件输出。
*
* 使用 PHP 编写,用于生成最终的 HTML。
*
* @since 1.0.0
* @access protected
*/
protected function render(): void {
$settings = $this->get_settings_for_display();
$html_tag = [
'ordered' => 'ol',
'unordered' => 'ul',
'other' => 'ul',
];
$this->add_render_attribute( 'list', 'class', 'elementor-list-widget' );
?>
<<?php echo $html_tag[ $settings['marker_type'] ]; ?> <?php $this->print_render_attribute_string( 'list' ); ?>>
<?php
foreach ( $settings['list_items'] as $index => $item ) {
$repeater_setting_key = $this->get_repeater_setting_key( 'text', 'list_items', $index );
$this->add_render_attribute( $repeater_setting_key, 'class', 'elementor-list-widget-text' );
$this->add_inline_editing_attributes( $repeater_setting_key );
?>
<li <?php $this->print_render_attribute_string( $repeater_setting_key ); ?>>
<?php
$title = $settings['list_items'][$index]['text'];
if ( ! empty( $item['link']['url'] ) ) {
$this->add_link_attributes( "link_{$index}", $item['link'] );
$linked_title = sprintf( '<a %1$s>%2$s</a>', $this->get_render_attribute_string( "link_{$index}" ), $title );
echo $linked_title;
} else {
echo $title;
}
?>
</li>
<?php
}
?>
</<?php echo $html_tag[ $settings['marker_type'] ]; ?>>
<?php
}
/**
* 在编辑器中渲染列表小部件输出。
*
* 作为 Backbone JavaScript 模板编写,用于生成实时预览。
*
* @since 1.0.0
* @access protected
*/
protected function content_template(): void {
?>
<#
html_tag = {
'ordered': 'ol',
'unordered': 'ul',
'other': 'ul',
};
view.addRenderAttribute( 'list', 'class', 'elementor-list-widget' );
#>
<{{{ html_tag[ settings.marker_type ] }}} {{{ view.getRenderAttributeString( 'list' ) }}}>
<# _.each( settings.list_items, function( item, index ) {
const repeater_setting_key = view.getRepeaterSettingKey( 'text', 'list_items', index );
view.addRenderAttribute( repeater_setting_key, 'class', 'elementor-list-widget-text' );
view.addInlineEditingAttributes( repeater_setting_key );
#>
<li {{{ view.getRenderAttributeString( repeater_setting_key ) }}}>
<# const title = item.text; #>
<# if ( item.link ) { #>
<# view.addRenderAttribute( `link_${index}`, item.link ); #>
<a href="{{ item.link.url }}" {{{ view.getRenderAttributeString( `link_${index}` ) }}}>
{{{title}}}
</a>
<# } else { #>
{{{title}}}
<# } #>
</li>
<# } ); #>
</{{{ html_tag[ settings.marker_type ] }}}>
<?php
}
}
结果
一个带有重复器字段的新“列表”小部件:
Elementor 小工具
Elementor 在小工具面板中内置了数十个实用的小工具。这些小工具按类别划分。每个小工具都有一套自定义控件(输入字段),允许最终用户输入数据。
管理小工具
外部开发者可以注册新的小工具或注销现有小工具。了解更多操作方法:
创建新小工具
了解更多关于小工具的构成以及如何创建自己的小工具:
代码示例
查看创建 Elementor 小工具是多么简单:
Remove Widgets
To remove existing widget developers can simply unregister existing widget by passing the widget name.
Hooks
To do that we need to hook to the elementor/widgets/register action which holds the widgets manager, and pass the widget name to the unregister() method.
Unregistering Widgets
To unregister existing widgets use the following code:
function unregister_widgets( $widgets_manager ) {
$widgets_manager->unregister( 'widget-1' );
$widgets_manager->unregister( 'widget-2' );
}
add_action( 'elementor/widgets/register', 'unregister_widgets' );
Rendering HTML Attributes
This type of rendering is used to add render attributes to specific HTML elements. For example, a widget can add a new <div> tag with a hardcoded "class" attribute or add a new <a> tag with hardcoded "target" and "rel" attributes. When used, you need to add if statements to check whether or not there are classes/target/rel attributed before adding them to the HTML tag. In addition, you need to escape user data with esc_attr() to improve security.
Elementor offers another way to add HTML attributes using the add_render_attribute() and get_render_attribute_string() methods.
Simple Widget Output
Let's look at a simple widget output:
<div id="" class="" role="" aria-label=""> ... </div>
PHP Render Attribute
Using the render() method, we can add attributes to the HTML tag using add_render_attribute(), retrieve the attributes using get_render_attribute_string(), and print attributes using print_render_attribute_string():
<?php
protected function render(): void {
$settings = $this->get_settings_for_display();
$this->add_render_attribute(
'wrapper',
[
'id' => 'custom-widget-id',
'class' => [ 'custom-widget-wrapper-class', $settings['custom_class'] ],
'role' => $settings['role'],
'aria-label' => $settings['name'],
]
);
$this->add_render_attribute(
'inner',
[
'class' => 'custom-widget-inner-class',
'data-custom' => 'custom-widget-information',
]
);
?>
<div <?php echo $this->get_render_attribute_string( 'wrapper' ); ?>>
<div <?php $this->print_render_attribute_string( 'inner' ); ?>>
...
</div>
</div>
<?php
}
JS Render Attribute
Using the content_template() method, we can add attributes to the HTML tag using addRenderAttribute(), and retrieve the attribute using getRenderAttributeString():
<?php
protected function content_template(): void {
?>
<#
view.addRenderAttribute(
'wrapper',
{
'id': 'custom-widget-id',
'class': [ 'elementor-tab-title', settings.custom_class ],
'role': settings.role,
'aria-label': settings.name,
}
);
view.addRenderAttribute(
'inner',
{
'class': 'custom-widget-inner-class',
'data-custom': 'custom-widget-information',
}
);
#>
<div {{{ view.getRenderAttributeString( 'wrapper' ) }}}>
<div {{{ view.getRenderAttributeString( 'inner' ) }}}>
...
</div>
</div>
<?php
}
Rendering Inline Editing
When developing widgets, developers can define which controls will be inline editable in both the editor panel and preview area.
Inline Editing Toolbars
Elementor supports the following types of toolbars for inline editing:
- No Toolbar –
(none)Inline text editing without a toolbar, just typing text inline. - Basic Toolbar –
(basic)Inline text editing with a minimal toolbar, including: bold, italic and underline buttons. - Advanced Toolbar –
(advanced)Inline text editing with a full toolbar, including: adding/removing links, H1-H6 heading, blockquote, preformatting and bulleted or numbered list buttons.
Elementor recommends using inline editing as follows:
- Input controls – use inline editing without any toolbars in simple text/number/url/email fields.
- Textarea controls – use inline editing with a minimal toolbar.
- Wysiwyg controls – use inline editing with a full toolbar.
添加内联编辑功能
内联编辑支持通过在 widget 的 render() 方法中使用 add_inline_editing_attributes() 方法,以及在 content_template() 中使用 addInlineEditingAttributes() 方法来添加。
每个内联编辑属性包含两个参数:
- 键
(string)– 代码中使用的唯一名称。 - 工具栏
(string)– 工具栏类型。可接受的值有:advanced、basic或none。默认值为none。
使用以下方式添加新的内联编辑属性:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function render(): void {
$this->add_inline_editing_attributes( 'text', 'advanced' );
echo '<div ' . $this->get_render_attribute_string( 'text' ) . '>' . $this->get_settings( 'text' ) . '</div>';
}
protected function content_template(): void {
?>
<# view.addInlineEditingAttributes( 'text', 'advanced' ); #>
<div {{{ view.getRenderAttributeString( 'text' ) }}}>{{{ settings.text }}}</div>
<?php
}
}
Example of Inline Editing
The following is a full example using three controls all having inline support. This includes simple text without a toolbar, a textarea with a basic toolbar, and a wysiwyg with an advanced toolbar:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'default' => esc_html__( 'Title', 'textdomain' ),
]
);
$this->add_control(
'description',
[
'label' => esc_html__( 'Description', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXTAREA,
'default' => esc_html__( 'Description', 'textdomain' ),
]
);
$this->add_control(
'content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'type' => \Elementor\Controls_Manager::WYSIWYG,
'default' => esc_html__( 'Content', 'textdomain' ),
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
$this->add_inline_editing_attributes( 'title', 'none' );
$this->add_inline_editing_attributes( 'description', 'basic' );
$this->add_inline_editing_attributes( 'content', 'advanced' );
?>
<h2 <?php $this->print_render_attribute_string( 'title' ); ?>><?php echo $settings['title']; ?></h2>
<div <?php $this->print_render_attribute_string( 'description' ); ?>><?php echo $settings['description']; ?></div>
<div <?php $this->print_render_attribute_string( 'content' ); ?>><?php echo $settings['content']; ?></div>
<?php
}
protected function content_template(): void {
?>
<#
view.addInlineEditingAttributes( 'title', 'none' );
view.addInlineEditingAttributes( 'description', 'basic' );
view.addInlineEditingAttributes( 'content', 'advanced' );
#>
<h2 {{{ view.getRenderAttributeString( 'title' ) }}}>{{{ settings.title }}}</h2>
<div {{{ view.getRenderAttributeString( 'description' ) }}}>{{{ settings.description }}}</div>
<div {{{ view.getRenderAttributeString( 'content' ) }}}>{{{ settings.content }}}</div>
<?php
}
}
Rendering Media
Elementor lets you select an image using the media control defined in the \Elementor\Control_Media class. There are two ways to render media files.
Simple Image Rendering
The simplest media rendering method is to print the image URL in a custom <img> tag. You can also use the wp_get_attachment_image() function to generate the image markup.
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'image',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'default' => [
'url' => \Elementor\Utils::get_placeholder_image_src(),
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
// Get image url
echo '<img src="' . esc_url( $settings['image']['url'] ) . '" alt="">';
// Get image by id
echo wp_get_attachment_image( $settings['image']['id'], 'thumbnail' );
}
protected function content_template(): void {
?>
<img src="{{{ settings.image.url }}}">
<?php
}
}
高级图像渲染
处理图像的更高级方法是结合使用 \Elementor\Control_Media 与 \Elementor\Group_Control_Image_Size:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'image',
[
'label' => esc_html__( 'Choose Image', 'textdomain' ),
'type' => \Elementor\Controls_Manager::MEDIA,
'default' => [
'url' => \Elementor\Utils::get_placeholder_image_src(),
],
]
);
$this->add_group_control(
\Elementor\Group_Control_Image_Size::get_type(),
[
'name' => 'image',
'default' => 'large',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
echo \Elementor\Group_Control_Image_Size::get_attachment_image_html( $settings );
}
protected function content_template(): void {
?>
<#
const image = {
id: settings.image.id,
url: settings.image.url,
size: settings.image_size,
dimension: settings.image_custom_dimension,
model: view.getEditModel()
};
const image_url = elementor.imagesManager.getImageUrl( image );
if ( '' === image_url ) {
return;
}
#>
<img src="{{{ image_url }}}">
<?php
}
}
Rendering Repeaters
One advanced use case is to render multiple elements using the repeater control. Here, users set multiple fields in the repeater control and we need to print them on screen.
Render Multiple Fields
Use the following to render multiple fields:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'list',
[
'label' => esc_html__( 'List', 'textdomain' ),
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => [
[
'name' => 'text',
'label' => esc_html__( 'Text', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => esc_html__( 'List Item', 'textdomain' ),
'default' => esc_html__( 'List Item', 'textdomain' ),
],
[
'name' => 'link',
'label' => esc_html__( 'Link', 'textdomain' ),
'type' => \Elementor\Controls_Manager::URL,
'placeholder' => esc_html__( 'https://your-link.com', 'textdomain' ),
],
],
'default' => [
[
'text' => esc_html__( 'List Item #1', 'textdomain' ),
'link' => 'https://elementor.com/',
],
[
'text' => esc_html__( 'List Item #2', 'textdomain' ),
'link' => 'https://elementor.com/',
],
],
'title_field' => '{{{ text }}}',
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( ! $settings['list'] ) {
return;
}
?>
<ul>
<?php foreach ( $settings['list'] as $index => $item ) : ?>
<li>
<?php
if ( $item['link']['url'] ) {
?><a href="<?php echo esc_url( $item['link']['url'] ); ?>"><?php echo $item['text']; ?></a><?php
} else {
echo $item['text'];
}
?>
</li>
<?php endforeach; ?>
</ul>
<?php
}
protected function content_template(): void {
?>
<#
if ( ! settings.list.length ) {
return;
}
#>
<ul>
<# _.each( settings.list, function( item, index ) { #>
<li>
<# if ( item.link && item.link.url ) { #>
<a href="{{{ item.link.url }}}">{{{ item.text }}}</a>
<# } else { #>
{{{ item.text }}}
<# } #>
</li>
<# } ); #>
</ul>
<?php
}
}
Rendering Style
A common widget rendering use case is using the control value to style different HTML elements. Usually used by controls from the content tab.
Styling Elements
Let's say you have a widget with two controls in which users can set a title, and control the element "color".
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => esc_html__( 'Enter your title', 'textdomain' ),
]
);
$this->end_controls_section();
$this->start_controls_section(
'section_style',
[
'label' => esc_html__( 'Style', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]
);
$this->add_control(
'color',
[
'label' => esc_html__( 'Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'default' => '#f00',
'selectors' => [
'{{WRAPPER}} h3' => 'color: {{VALUE}}',
],
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['title'] ) ) {
return;
}
?>
<h3>
<?php echo $settings['title']; ?>
</h3>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.title ) {
return;
}
#>
<h3>
{{{ settings.title }}}
</h3>
<?php
}
}
Note that each element on the page includes a set of style settings that are printed as CSS rules under a unique element selector. The widget can easily use the returned control value as a design rule.
Our test widget will add custom CSS rules to the page's CSS file. Those rules will only affect this widget as the { { WRAPPER } } prefix means that only this instance of the widget will use this color.
Selector Tokens
When you select which category to assign your widget to, you can select one of the default categories:
| Label | Description |
|---|---|
| { { WRAPPER } } | Widget wrapper element |
| { { VALUE } } | Control value |
| { { UNIT } } | Unit control value of selected unit |
| { { URL } } | The URL returned by the media control |
| { { SELECTOR } } | Group control CSS selector |
Rendering Text
The most common widget rendering use case is to print the value of a simple text control. These controls are usually found in the content tab.
Printing Text Values
Let's say you have a widget with a single control in which the users can set a "title". To print the title entered by the user, we simply echo the control value:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => esc_html__( 'Enter your title', 'textdomain' ),
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['title'] ) ) {
return;
}
?>
<h3>
<?php echo $settings['title']; ?>
</h3>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.title ) {
return;
}
#>
<h3>
{{{ settings.title }}}
</h3>
<?php
}
}
Simple Example
Putting all these pieces together, we're going to create a simple Elementor widget which will use the native oEmbed functionality of WordPress to auto-embed content from external sites using simple URLs.
文件夹结构
该插件将包含两个文件:一个用于小部件,另一个主文件用于注册小部件。
elementor-oembed-widget/
|
├─ widgets/
| └─ oembed-widget.php
|
└─ elementor-oembed-widget.php
Plugin Files
elementor-oembed-widget.php
<?php
/**
* Plugin Name: Elementor oEmbed Widget
* Description: Auto embed any embbedable content from external URLs into Elementor.
* Plugin URI: https://elementor.com/
* Version: 1.0.0
* Author: Elementor Developer
* Author URI: https://developers.elementor.com/
* Text Domain: elementor-oembed-widget
*
* Requires Plugins: elementor
* Elementor tested up to: 3.25.0
* Elementor Pro tested up to: 3.25.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Register oEmbed Widget.
*
* Include widget file and register widget class.
*
* @since 1.0.0
* @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
* @return void
*/
function register_oembed_widget( $widgets_manager ) {
require_once( __DIR__ . '/widgets/oembed-widget.php' );
$widgets_manager->register( new \Elementor_oEmbed_Widget() );
}
add_action( 'elementor/widgets/register', 'register_oembed_widget' );
widgets/oembed-widget.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Elementor oEmbed Widget.
*
* Elementor widget that inserts an embbedable content into the page, from any given URL.
*
* @since 1.0.0
*/
class Elementor_oEmbed_Widget extends \Elementor\Widget_Base {
/**
* Get widget name.
*
* Retrieve oEmbed widget name.
*
* @since 1.0.0
* @access public
* @return string Widget name.
*/
public function get_name(): string {
return 'oembed';
}
/**
* Get widget title.
*
* Retrieve oEmbed widget title.
*
* @since 1.0.0
* @access public
* @return string Widget title.
*/
public function get_title(): string {
return esc_html__( 'oEmbed', 'elementor-oembed-widget' );
}
/**
* Get widget icon.
*
* Retrieve oEmbed widget icon.
*
* @since 1.0.0
* @access public
* @return string Widget icon.
*/
public function get_icon(): string {
return 'eicon-code';
}
/**
* Get widget categories.
*
* Retrieve the list of categories the oEmbed widget belongs to.
*
* @since 1.0.0
* @access public
* @return array Widget categories.
*/
public function get_categories(): array {
return [ 'general' ];
}
/**
* Get widget keywords.
*
* Retrieve the list of keywords the oEmbed widget belongs to.
*
* @since 1.0.0
* @access public
* @return array Widget keywords.
*/
public function get_keywords(): array {
return [ 'oembed', 'url', 'link' ];
}
/**
* Get custom help URL.
*
* Retrieve a URL where the user can get more information about the widget.
*
* @since 1.0.0
* @access public
* @return string Widget help URL.
*/
public function get_custom_help_url(): string {
return 'https://developers.elementor.com/docs/widgets/';
}
/**
* Whether the widget requires inner wrapper.
*
* Determine whether to optimize the DOM size.
*
* @since 1.0.0
* @access public
* @return bool Whether to optimize the DOM size.
*/
public function has_widget_inner_wrapper(): bool {
return false;
}
/**
* Whether the element returns dynamic content.
*
* Determine whether to cache the element output or not.
*
* @since 1.0.0
* @access protected
* @return bool Whether to cache the element output.
*/
protected function is_dynamic_content(): bool {
return false;
}
/**
* Register oEmbed widget controls.
*
* Add input fields to allow the user to customize the widget settings.
*
* @since 1.0.0
* @access protected
*/
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'elementor-oembed-widget' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'url',
[
'label' => esc_html__( 'URL to embed', 'elementor-oembed-widget' ),
'type' => \Elementor\Controls_Manager::TEXT,
'input_type' => 'url',
'placeholder' => esc_html__( 'https://your-link.com', 'elementor-oembed-widget' ),
]
);
$this->end_controls_section();
}
/**
* Render oEmbed widget output on the frontend.
*
* Written in PHP and used to generate the final HTML.
*
* @since 1.0.0
* @access protected
*/
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['url'] ) ) {
return;
}
$html = wp_oembed_get( $settings['url'] );
?>
<div class="oembed-elementor-widget">
<?php echo ( $html ) ? $html : $settings['url']; ?>
</div>
<?php
}
}
结果
一个新的 "oEmbed" 小部件:
小部件分类
Elementor 的小部件分类用于将小部件分组管理。Elementor 初始化时,会注册多个默认分类。
只有当分类下分配有小部件时,该分类才会在部件面板中显示。
外部开发者可以创建新的分类,并在品牌专属的分类中单独展示他们的小部件。
使用小部件分类
在注册新的 Elementor 小部件时,我们会使用小部件分类。通过继承 \Elementor\Widget_Base 类,我们同时也继承了 \Elementor\Widget_Base::get_categories() 方法,该方法默认返回 general 分类。
要将小部件分配到不同的分类,我们需要重写此方法,并按以下方式返回新的分类:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_categories(): array {
return [ 'basic' ];
}
}
Default Categories
When you select which category to assign your widget to, you can select one of the default categories:
| Label | Name | Package | Description |
|---|---|---|---|
| Basic | basic |
Elementor | Category for basic widgets |
| Pro | pro-elements |
ElementorPro | Category for advanced widgets |
| General | general |
Elementor | Category for general widgets |
| Site | theme-elements |
ElementorPro | Category for site & theme widgets |
| WooCommerce | woocommerce-elements |
ElementorPro | Category for WooCommerce widgets |
| {Custom} | {Addons} | Custom categories added by external developers | |
| WordPress | wordpress |
WordPress | Category for WordPress widgets |
Or you can register your own category.
创建新分类
Elementor 允许开发者添加新的小部件分类,用于分组自定义小部件。注册新分类需使用 elementor/elements/categories_registered 动作。
注意:创建新分类时,需要提供分类名称/别名、分类标题/标签以及分类图标。
function add_elementor_widget_categories( $elements_manager ) {
$elements_manager->add_category(
'first-category',
[
'title' => esc_html__( 'First Category', 'textdomain' ),
'icon' => 'fa fa-plug',
]
);
$elements_manager->add_category(
'second-category',
[
'title' => esc_html__( 'Second Category', 'textdomain' ),
'icon' => 'fa fa-plug',
]
);
}
add_action( 'elementor/elements/categories_registered', 'add_elementor_widget_categories' );
Widget Controls
Each widget needs to have some controls (setting fields), where users can select their data. This data is saved in the database and later used to generate custom output based on the user's selection.
注册控件
在您的小部件类中,可以在 register_controls() 方法内添加控件,如下所示:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section();
$this->add_control();
$this->add_control();
$this->add_control();
$this->end_controls_section();
}
}
- 小部件控件 –
register_controls()方法允许您定义小部件将包含哪些控件(设置字段)。
可用控件
Elementor 提供了多种现成控件。所有控件必须包含在章节中。您可以添加常规控件、响应式控件和分组控件。开发者甚至可以创建新控件。
Add Controls to your Widget
In the example below, we're going to add a few controls to a widget to allow users save data:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'content_section',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'type' => \Elementor\Controls_Manager::TEXT,
'label' => esc_html__( 'Title', 'textdomain' ),
'placeholder' => esc_html__( 'Enter your title', 'textdomain' ),
]
);
$this->add_control(
'size',
[
'type' => \Elementor\Controls_Manager::NUMBER,
'label' => esc_html__( 'Size', 'textdomain' ),
'placeholder' => '0',
'min' => 0,
'max' => 100,
'step' => 1,
'default' => 50,
]
);
$this->add_control(
'open_lightbox',
[
'type' => \Elementor\Controls_Manager::SELECT,
'label' => esc_html__( 'Lightbox', 'textdomain' ),
'options' => [
'default' => esc_html__( 'Default', 'textdomain' ),
'yes' => esc_html__( 'Yes', 'textdomain' ),
'no' => esc_html__( 'No', 'textdomain' ),
],
'default' => 'no',
]
);
$this->add_control(
'alignment',
[
'type' => \Elementor\Controls_Manager::CHOOSE,
'label' => esc_html__( 'Alignment', 'textdomain' ),
'options' => [
'left' => [
'title' => esc_html__( 'Left', 'textdomain' ),
'icon' => 'eicon-text-align-left',
],
'center' => [
'title' => esc_html__( 'Center', 'textdomain' ),
'icon' => 'eicon-text-align-center',
],
'right' => [
'title' => esc_html__( 'Right', 'textdomain' ),
'icon' => 'eicon-text-align-right',
],
],
'default' => 'center',
]
);
$this->end_controls_section();
}
}
Widget Data
Every widget requires basic information such as the widget ID, label and icon. In addition, a widget can have optional data providing extra information like an external link describing how to use the widget or promotion to promote premium version of the widget.
Data Methods
Widget data needs to be "returned" by certain methods. Those methods are simple:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_name(): string {
return 'widget_name';
}
public function get_title(): string {
return esc_html__( 'My Widget Name', 'textdomain' );
}
public function get_icon(): string {
return 'eicon-code';
}
public function get_categories(): array {
return [ 'general' ];
}
public function get_keywords(): array {
return [ 'keyword', 'keyword' ];
}
public function get_custom_help_url(): string {
return 'https://example.com/widget-name';
}
protected function get_upsale_data(): array {
return [];
}
}
-
Widget Name – The
get_name()method returns the widget name as it will be used in the code. -
Widget Title – The
get_title()method returns the widget label as it will be displayed to the user. -
Widget Icon – The
get_icon()method is an optional, but recommended, method. It lets you set the widget icon. You can use any Elementor icons or FontAwesome icons, to simply return the CSS class name. -
Widget Categories – The
get_categories()method lets you set the category of the widget. -
Widget Keywords – The
get_keywords()method lets you set widget keywords and is used to filter the widget list. -
Widget Help URL – The
get_custom_help_url()method is an optional method that sets a custom URL, where the user can get more information about the widget, below the controls. -
Widget Promotion – The
get_upsale_data()method is an optional method that is used to display promotions at the bottom of the widget panel.
Widget Dependencies
Some widgets are dependent on custom scripts for functionality and custom styles for look and feel. Widgets can use external JS libraries, CSS frameworks, or custom JS handlers. Let's see how to use them.
定义依赖项
在 widget 类中,我们可以通过以下方式定义所需的 JS 和 CSS 依赖项:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_script_depends(): array {
return [ 'script-handle' ];
}
public function get_style_depends(): array {
return [ 'style-handle' ];
}
}
-
脚本依赖项 –
get_script_depends()方法允许您定义运行 widget 所需的 JS 文件。 -
样式依赖项 –
get_style_depends()方法允许您定义运行 widget 所需的 CSS 文件。
请注意,这些依赖项应该已经注册。widget 类仅告知 Elementor 它需要加载哪些依赖项。
在 WordPress 中注册脚本与样式
与其他 WordPress 插件一样,脚本和样式必须在插件的 PHP 文件中使用 wp_register_script() 和 wp_register_style() 函数进行注册。
WordPress 提供了多个钩子来注册脚本/样式,具体取决于它们的使用位置:
- wp_enqueue_scripts - 用于前端页面脚本和样式的钩子
- login_enqueue_scripts - 用于登录页面脚本和样式的钩子
- admin_enqueue_scripts - 用于管理页面脚本和样式的钩子
Registering Scripts & Styles in Elementor
Elementor addon developers should register JS and CSS dependencies in the main file, usually where widgets are registered:
/**
* Register Elementor test widgets.
*/
function elementor_test_widgets_registration( $widgets_manager ) {
require_once( __DIR__ . '/widgets/test-widget-1.php' );
require_once( __DIR__ . '/widgets/test-widget-2.php' );
$widgets_manager->register( new \Elementor_Test_Widget_1() );
$widgets_manager->register( new \Elementor_Test_Widget_2() );
}
add_action( 'elementor/widgets/register', 'elementor_test_widgets_registration' );
/**
* Register scripts and styles for Elementor test widgets.
*/
function elementor_test_widgets_dependencies() {
/* Scripts */
wp_register_script( 'widget-script-1', plugins_url( 'assets/js/widget-script-1.js', __FILE__ ) );
wp_register_script( 'widget-script-2', plugins_url( 'assets/js/widget-script-2.js', __FILE__ ), [ 'external-library' ] );
wp_register_script( 'external-library', plugins_url( 'assets/js/libs/external-library.js', __FILE__ ) );
/* Styles */
wp_register_style( 'widget-style-1', plugins_url( 'assets/css/widget-style-1.css', __FILE__ ) );
wp_register_style( 'widget-style-2', plugins_url( 'assets/css/widget-style-2.css', __FILE__ ), [ 'external-framework' ] );
wp_register_style( 'external-framework', plugins_url( 'assets/css/libs/external-framework.css', __FILE__ ) );
}
add_action( 'wp_enqueue_scripts', 'elementor_test_widgets_dependencies' );
Then, each widgets should set its dependencies as follows:
class Elementor_Test_Widget_1 extends \Elementor\Widget_Base {
public function get_script_depends(): array {
return [ 'external-library' ];
}
public function get_style_depends(): array {
return [ 'external-framework' ];
}
}
class Elementor_Test_Widget_2 extends \Elementor\Widget_Base {
public function get_script_depends(): array {
return [ 'widget-script-1', 'widget-script-2' ];
}
public function get_style_depends(): array {
return [ 'widget-style-1', 'widget-style-2' ];
}
}
This way, Elementor can build the dependency tree and enqueue only dependencies for widgets used in the page.
使用 Elementor 资源
第三方开发者可以使用 Elementor 注册的资源,例如使用 Swiper 创建基于轮播的小部件。
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_style_depends(): array {
return [ 'swiper', 'widget-custom-style' ];
}
public function get_script_depends(): array {
return [ 'swiper', 'widget-custom-script' ];
}
}
Elementor 为其轮播小部件注册了 swiper,Elementor Pro 和许多其他 Elementor 插件都使用它,而不是注册自己的库版本。
使用 Elementor 脚本
要使用不同的 Elementor JS 方法,小部件需要声明 elementor-frontend 作为依赖项:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_script_depends(): array {
return [ 'elementor-frontend', 'widget-custom-script' ];
}
}
当第三方小部件注册自己的前端处理程序时,这会非常方便。在 controls frontend_available 参数 中了解更多信息。
Widget Information
Elementor widget need to have a unique ID used in the code, and an addition basic information used in the Elementor editor.
Widget Name/ID
To set a unique ID for the widget, use the get_name() method. This string is used in code and in the database. The name should include only lowercase letters and it should not contain spaces (use _ instead).
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_name(): string {
return 'widget_name';
}
}
Widget Title
Widget title is the label used in the Elementor editor. The end user will see this text when interacting with different panels. The title should use internalization functions to make the string translatable to other languages.
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_title(): string {
return esc_html__( 'My Widget Name', 'textdomain' );
}
}
Widget Icon
Each widget has not only a label but also an icon. This icons is displayed in different location in the Editor, like the elements panel and the navigator panel. It's not a required field, but very recommended.
Widgets can use any Elementor icons or FontAwesome icons, returning the icon CSS class. Custom icons can also be used.
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_icon(): string {
return 'eicon-code';
}
}
Widget DOM Optimization
Elementor widgets define their own markup in the render() method. However, Elementor wraps each widget in two <div> elements; the outer <div class="elementor-widget"> element, and the inner <div class="elementor-widget-container"> element. In the past, these additional wrappers allow Elementor to add additional styles and features.
However, two wrappers for each widget increases the overall DOM size, reducing page performance. To overcome this, developers can use the has_widget_inner_wrapper() method to control the number of wrapper elements the widget has.
By switching to a single wrapper, a widget can reduce the DOM size and optimize its footprint on the page. But, existing widgets that rely on the inner .elementor-widget-container wrapping element to style widgets, can maintain backwards compatibility.
小部件标记
旧的、未优化的部件标记包含两个包装元素:
<div class="elementor-widget elementor-widget-{widget-name}">
<div class="elementor-widget-container">
...
</div>
</div>
新的、优化的标记只有一个包装元素:
<div class="elementor-widget elementor-widget-{widget-name}">
...
</div>
Elementor 过去曾使用未优化的标记。如今,所有 Elementor 和 Elementor Pro 小部件都使用优化的标记。Elementor 为外部开发者提供了过渡期,以便采用优化的小部件标记。
包装元素
每个小部件所需的包装元素数量由小部件开发者决定。Elementor 为外部开发者提供了过渡期,以便采用优化后的小部件标记。
需要两个 <div> 包装器(包括内部的 .elementor-widget-container 包装器)的旧版小部件,在小部件中使用以下方法:
public function has_widget_inner_wrapper(): bool {
return true;
}
仅需外部 <div> 包装器(无需内部的 .elementor-widget-container 包装器)即可工作的新版小部件,在小部件中使用以下方法:
public function has_widget_inner_wrapper(): bool {
return false;
}
最后,未使用 has_widget_inner_wrapper() 函数的小部件将表现为未优化的、带有两个 <div> 包装元素的小部件。此行为在未来可能会改变,以优化剩余的小部件。
未来
开发者应提前规划未优化小部件停止渲染的情况。为避免兼容性和样式问题,每个小部件都应包含返回 false 的 has_widget_inner_wrapper() 方法。
Examples
Optimized Widget DOM
To reduce the DOM size, developers can use the has_widget_inner_wrapper() method in the widget class, as shown below:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function has_widget_inner_wrapper(): bool {
return false;
}
}
This implementation instructs Elementor to render the widget with a single <div> wrapper.
Retaining Unoptimized Widget DOM (for BC)
Legacy widgets that rely on the .elementor-widget-container class can continue using the unoptimized DOM by setting the method to return true:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function has_widget_inner_wrapper(): bool {
return true;
}
protected function register_controls(): void {
$this->add_control(
'color',
[
'label' => esc_html__( 'Color', 'textdomain' ),
'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} > .elementor-widget-container h3' => 'color: {{VALUE}};',
],
]
);
}
protected function render(): void {
?>
<h3>
...
</h3>
<?php
}
}
This widget can't use the optimized DOM capability as it uses the inner .elementor-widget-container CSS class to style the widget. Therefore, setting has_widget_inner_wrapper() to true will make sure that Elementor doesn't remove the inner wrapper for this widget.
注意事项
请注意,保留未优化的 DOM 结构是一种临时解决方案,旨在让插件开发者在更新代码时保持兼容性。最终目标是将所有小部件过渡到使用优化的单包装器结构。
小部件包装器的 DOM 优化不仅需要将 has_widget_inner_wrapper() 设置为 false,还需要从所有文件(包括 PHP、CSS 和 JS)中移除 .elementor-widget-container。
在上面的示例代码中,只需从选择器中移除 .elementor-widget-container 类:
- '{{WRAPPER}} > .elementor-widget-container h3' => 'color: {{VALUE}};',
+ '{{WRAPPER}} h3' => 'color: {{VALUE}};',
Widget Optimization
Elementor provides various methods to optimize widgets and enhance performance. To maintain backward compatibility, not all optimizations are applied to every widget. Additionally, each widget has unique characteristics, so certain optimizations may not be applicable in all cases.
Performance Optimization Methods
Widget developers can implement the following two optional methods in their widget classes to help Elementor handle widgets more efficiently:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function has_widget_inner_wrapper(): bool {}
protected function is_dynamic_content(): bool {}
}
-
DOM Optimization - The
has_widget_inner_wrapper()method lets you determine whether the widget uses optimized DOM structure or not. -
Element Output Caching - The
is_dynamic_content()method lets you determine whether the widget returns dynamic content, to cache the element HTML output or not.
Widget Output Caching
Widget Output Caching
Elementor offers a feature to minimize the impact of widgets on page performance. For widgets that generate static output, Elementor can cache the HTML, avoiding the need to render it each time the page loads.
By default, Elementor does not cache widget outputs and renders all widgets on the page with every page load. However, developers can enable HTML output caching for widgets to enhance loading speeds.
小部件渲染机制
在页面加载期间,Elementor 会渲染所有小部件以生成所需的标记。页面包含的小部件越多,渲染过程就越慢。
为了优化此过程,可以采用 Elementor 的元素缓存机制。"元素缓存"机制会渲染小部件一次,缓存输出结果,并在后续页面加载时使用缓存版本。此操作可将服务器内存使用量减少 99%,并改善前端的首字节时间(TTFB)。
内容类型
小部件可以返回两种类型的输出:
- 静态内容 - 每次为每个用户返回相同的内容。
- 动态内容 - 返回可能根据不同参数而变化的内容。
静态内容的一个例子是标题小部件,它始终返回来自控件的文本。由于所有用户的输出都相同,因此可以缓存。
相比之下,动态内容涉及根据不同条件改变输出的逻辑。例如,一个包含 PHP 函数来显示用户姓名的小部件,将为不同用户显示不同的结果,因此该小部件不应缓存输出。
动态内容的一个极端例子是每次页面加载时显示随机数的小部件。此类小部件不应缓存其输出。
Elementor 中的小部件缓存机制非常复杂,并包含多个例外情况以避免不适当的缓存。例如,如果小部件的某个控件使用了动态标签或具有显示条件,Elementor 将绕过缓存,完全重新渲染该小部件。
缓存输出
为通过缓存静态内容来提升小部件性能,请将以下方法应用于小部件类:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function is_dynamic_content(): bool {
return false;
}
}
使用上述代码,小部件会指示 Elementor 在其生成静态内容时缓存其输出。
默认情况下,所有小部件都被视为动态内容且不会被缓存。如果不确定,请避免使用此方法。
异常情况
Elementor 的小部件缓存机制非常精密,包含若干例外规则以避免不当缓存。例如,若小部件的某个控件使用了动态标签或设有显示条件,Elementor 将绕过缓存并完整渲染该部件。
示例
具有静态输出的小部件
假设您有一个包含单个控件的小部件,用户可以在其中设置“标题”。渲染函数将始终为所有用户渲染相同的 HTML,因此输出可以被缓存:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function is_dynamic_content(): bool {
return false;
}
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => esc_html__( 'Enter your title', 'textdomain' ),
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['title'] ) ) {
return;
}
?>
<h3>
<?php echo $settings['title']; ?>
</h3>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.title ) {
return;
}
#>
<h3>
{{{ settings.title }}}
</h3>
<?php
}
}
具有动态输出的小部件
假设您有相同的小部件,但渲染函数包含自定义代码,可能为不同用户生成完全不同的 HTML,因此输出无法被缓存:
<?php
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function register_controls(): void {
$this->start_controls_section(
'section_content',
[
'label' => esc_html__( 'Content', 'textdomain' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'title',
[
'label' => esc_html__( 'Title', 'textdomain' ),
'type' => \Elementor\Controls_Manager::TEXT,
'placeholder' => esc_html__( 'Enter your title', 'textdomain' ),
]
);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
if ( empty( $settings['title'] ) ) {
return;
}
if ( is_user_logged_in() ) {
$greeting = esc_html__( 'Hi logged in user!', 'textdomain' ) . ' ';
}
?>
<h3>
<?php echo $greeting . $settings['title']; ?>
</h3>
<?php
}
protected function content_template(): void {
?>
<#
if ( '' === settings.title ) {
return;
}
if ( document.body.classList.contains( 'logged-in' ) ) {
greeting = 'Hi logged in user! ';
}
#>
<h3>
{{{ greeting + settings.title }}}
</h3>
<?php
}
}
这个小部件为登录用户和匿名用户生成不同的 HTML 输出。我们无法缓存小部件的输出,因为缓存的 HTML 可能会显示给错误的用户。
测试
测试性能改进时,请确保使用不同类型的小部件——而非同一小部件的多个实例。页面包含的小部件越多、类型越丰富,性能提升效果越显著。接下来,请在 WordPress 后台 > Elementor > 工具 中点击“重新生成文件与数据”按钮。
然后,在您选择的测速工具中,对比首次运行(渲染数据)与第二次运行(缓存数据)的结果。若测量服务器性能,请关注对服务器内存的影响;若测量前端性能,请观察对首字节时间(TTFB)的影响。
小部件推广
Elementor 小部件在小部件面板中有两个内置位置用于推广和升级销售。
第一个选项是简单的“需要帮助?”链接,这是一个包含小部件通用信息的外部链接。
第二个选项是行动号召区域,提供升级到高级小部件/产品/服务的优惠。
小部件帮助链接
帮助链接显示在小部件面板底部所有部分的下方。这是一个内置功能,为用户在所有 Elementor 小部件中提供一致的用户体验。
每个小部件都可以设置一个外部链接,其中包含该特定小部件的通用信息和使用说明。
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_custom_help_url(): string {
return 'https://example.com/widget-name';
}
}
小部件推广
推广是免费增值插件提供升级销售以升级到高级小部件/产品/服务的一种方式。小部件推广显示在小部件面板的底部。
class Elementor_Test_Widget extends \Elementor\Widget_Base {
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 of the widget and grow your website capabilities.', 'textdomain' ),
'upgrade_url' => esc_url( 'https://example.com/upgrade-to-pro/' ),
'upgrade_text' => esc_html__( 'Upgrade Now', 'textdomain' ),
];
}
}
这里需要强调的是,推广是针对特定小部件设置的。它允许插件开发者创建自定义的行动号召来推广该小部件的高级版本。
如果满足某些条件,可以选择性地隐藏/显示此推广。例如,Elementor 仅在 Elementor Pro 未激活时使用小部件推广,因此付费用户不会看到小部件推广。
Widget Rendering
The last step in widget development is to display the output. Each widget needs to render the data returned from the controls, and generate the final HTML displayed in the frontend and the preview area.
Rendering Methods
Elementor has two rendering methods, both rely on the returned values from the control, but each method renders differently as one uses PHP and the other uses JS.
class Elementor_Test_Widget extends \Elementor\Widget_Base {
protected function render(): void {}
protected function content_template(): void {}
}
-
render()– Written as a PHP template that generates the frontend output. -
content_template()– Written as a JS template that generates the preview output in the editor.
Rendering Different Controls
Elementor offers a number of ways to use the returned value of a control. Widgets can simply print the value in the template, use the value to create a CSS rule in the stylesheet file, add a class to the element template wrapper, and more.
We're going to dive in and see how this is done using the different methods. We'll start with very simple methods and move on to more advanced ones.
- Widget Settings
- Rendering Text
- Rendering Style
- Rendering Media
- Rendering Repeater
- Rendering HTML Attribute
- Rendering Inline Editing
- Widget Output Caching
Widget Settings
Before the widget rendering function starts generating the final HTML output, it needs to retrieve data from the controls.
In Elementor terminology, "widget settings" are the "user data" retrieved from the widget controls.
Retrieving JS Settings
With JS templates we don’t need to retrieve the data using a special function, it's done by Elementor for us. Data from the controls is stored in the settings variable and can be retrieved like this:
<?php
protected function content_template(): void {
?>
<h3 class="{{ settings.class }}">{{{ settings.title }}}</h3>
<?php
}
Use double curly brackets {{ for escaped results and triple curly brackets {{{ for un-escaped results. The best practice is to use double curly brackets everywhere, unless you need to to use un-scaped values.
Retrieving PHP Settings
When retrieving data saved by the user, we can either retrieve all the data from all the controls or specific data from a specific control. Data retrieval is done using get_settings_for_display() method.
Use the following to retrieve data from a single control:
<?php
protected function render(): void {
?>
<h3>
<?php echo $this->get_settings_for_display( 'title' ); ?>
</h3>
<?php
}
When retrieving data from multiple controls, we can retrieve all the data from all the controls into a single parameter:
<?php
protected function render(): void {
$settings = $this->get_settings_for_display();
?>
<h3 class="<?php echo esc_attr( $settings['class'] ); ?>">
<?php echo $settings['title']; ?>
</h3>
<?php
}
Either way achieves the same result, however, in some cases the second method has performance benefits.
Widget Structure
Creating a custom Elementor Widget is not very different from creating a native WordPress widget. Start by creating a class that extends the \Elementor\Widget_Base class and fill in all the required methods.
Each widget needs to have a few basic settings - a unique name that will identify the widget in the code, a title that will be used as the widget label, and an icon. There are also advanced settings such as widget controls which are the fields where users select their custom data, and a render script that generates the final output based on user data from the widget controls.
Widget Class
First, we need to create a class that extends the \Elementor\Widget_Base class:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
}
Widget Methods
A simple widget skeleton class will look as follows:
class Elementor_Test_Widget extends \Elementor\Widget_Base {
public function get_name(): string {}
public function get_title(): string {}
public function get_icon(): string {}
public function get_categories(): array {}
public function get_keywords(): array {}
public function get_custom_help_url(): string {}
protected function get_upsale_data(): array {}
public function get_script_depends(): array {}
public function get_style_depends(): array {}
public function has_widget_inner_wrapper(): bool {}
protected function is_dynamic_content(): bool {}
protected function register_controls(): void {}
protected function render(): void {}
protected function content_template(): void {}
}
The \Elementor\Widget_Base class has many more methods, but the vast majority of your needs are covered by the methods mentioned above.
These methods can be divided into five groups: