EP01. "elementor-widget-create 自定义 Widget 搭建"
🔒 登录后可标记已读- 自己写一个 Elementor widget,是要继承
Widget_Base还是新的 4.0 atomic 架构?两套东西控件写法完全不一样,选错架构等于重写一次——elementor-widget-create就是帮你判断该走哪条路、把骨架搭对 - 这是
mekko-digital/elementor-skills这个开源 skill 包里的其中一个,覆盖经典(3.x~4.x 非 atomic)、4.0 atomic、Pro 专用基类三种 widget 架构的脚手架 - 核心特色:skill 本体故意压在 80 行以内,控件类型清单、Repeater/Skin 写法、Pro 基类模式这些细节全部另外放在
resources/widget-create-examples.md,真的要深入才读,不占日常对话的上下文 - 前置知识:先看过 Overview 系列的「Claude Code 是什么与新手上手」「进阶功能:Skills、Plugins 与 Routines」两篇,知道 Skill 是什么、怎么装;也建议知道 Elementor 后台的基本操作(Widget 面板、编辑器)
重点内容
这个 Skill 是做什么的
elementor-widget-create 是脚手架型 skill,不是审查型——不是拿代码去找漏洞,而是根据你要做的功能,直接生成一个符合 Elementor 架构规范的 widget 骨架(控件注册、渲染逻辑、Skin、Pro 基类继承)。同一个 skill 包里另外还有 elementor-deploy-verify,专门负责把这个 skill 生出来的代码部署到 staging 站点、确认真的注册成功。
适合用在:
- 要新增一个自定义 Elementor widget(不管经典架构还是 4.0 atomic)
- 要给 widget 加 Skin(可切换的渲染层)、Repeater 控件(可重复的列表项)
- 要继承 Pro 专用基类(
Posts_Base、Carousel_Base、WooCommerce 变体等)做电商/文章列表类 widget
不适合用在:
- 单纯排查一个已存在的 widget 为什么渲染不出来或坏了——那是
elementor-debug-render的工作 - 不确定某个功能是免费版还是 Pro 版才有——先查
elementor-feature-lookup - 做整页排版(把好几个 widget 组合成一个页面)——那是
elementor-design-to-page的工作,这个 skill 只管单一 widget 怎么写
三种架构怎么选
| 架构 | 继承的基类 | 什么时候用 |
|---|---|---|
| 经典 Widget_Base | Elementor\Widget_Base | 3.x~4.x 非 atomic 站点,目前市面上大多数自定义 widget 走这条路 |
| 4.0 Atomic Widget | Elementor\Modules\AtomicWidgets\Elements\Base\Atomic_Widget_Base | 目标站点已经在用 Elementor 4.0 的新 atomic 编辑器,需要类型化的 props schema |
| Pro 专用基类 | Base_Widget/Posts_Base/Carousel_Base/Products_Base 等 | 要做文章列表、轮播、WooCommerce 商品展示这类 Pro 才有的现成能力,直接继承对应基类比从零写省事很多 |
📌 两种架构(经典 / atomic)的控件写法、渲染方式完全不同,不要混用——先确认目标站点 Elementor 版本和是否启用 atomic 编辑器,再动手选架构。
实操示例:经典架构的骨架
// ✅ GOOD:经典 Widget_Base 必须实现的方法
class My_Custom_Widget extends \Elementor\Widget_Base {
public function get_name() { return 'my-custom-widget'; }
public function get_title() { return __( 'My Custom Widget' ); }
public function get_icon() { return 'eicon-code'; }
public function get_categories() { return [ 'general' ]; }
protected function register_controls() {
// 用 Controls Manager API 定义控件 section
$this->start_controls_section( 'content_section', [
'label' => __( 'Content' ),
] );
$this->add_control( 'title', [
'type' => \Elementor\Controls_Manager::TEXT,
'default' => 'Hello',
] );
$this->end_controls_section();
}
protected function render() {
// get_settings_for_display() 会自动解析动态标签
$settings = $this->get_settings_for_display();
echo esc_html( $settings['title'] );
}
protected function content_template() {
// Underscore.js 模板,给编辑器即时预览用
?><#= settings.title #><?php
}
}
// 注册要挂在这个 hook 上
add_action( 'elementor/widgets/register', function( $widgets_manager ) {
$widgets_manager->register( new \My_Custom_Widget() );
} );
实操示例:Repeater 控件(可重复列表项)
// ✅ GOOD:Repeater 的标准写法
$repeater = new \Elementor\Repeater();
$repeater->add_control( 'item_text', [ 'type' => \Elementor\Controls_Manager::TEXT ] );
$this->add_control( 'list', [
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => $repeater->get_controls(),
'title_field' => '{{{ item_text }}}',
] );
// render() 里遍历
foreach ( $settings['list'] as $item ) {
echo esc_html( $item['item_text'] );
}
// content_template() 对应的 Underscore.js 写法(不是 PHP):
<# _.each( settings.list, function( item ) { #>
<?= item.item_text ?>
<# } ); #>
4.0 Atomic 架构要点
- 继承
Atomic_Widget_Base,get_element_type()要回传一个e-开头的字符串(例如e-my-widget) - 用
define_props_schema()定义类型化的属性 schema,不是像经典架构那样逐个add_control() - Prop Type 常用的有
String_Prop_Type、Number_Prop_Type、Color_Prop_Type、Image_Prop_Type、Link_Prop_Type等,默认值用Prop_Type::make()->default($value),必填用->required() - 渲染走
Has_Templatetrait + Twig 模板,或者自己覆盖render()——📌 两者选一个,用了Has_Template就不要再覆盖render()
Skin(可切换渲染层,只有经典架构才有)
Skin 让同一个 widget 在编辑器里可以切换好几种排版方式,继承 Elementor\Skin_Base:
// ✅ GOOD:注册 Skin 要放在 _register_skins() 里
protected function _register_skins() {
$this->add_skin( new \My_Plugin\Skins\Skin_Cards( $this ) );
}
Elementor Pro 自带的 Posts widget(elementor-pro/modules/posts/widgets/posts.php)是官方参考实现,想抄写法可以直接对照那个文件。
Pro 基类怎么选
| Pro 基类 | 提供什么 | 典型用途 |
|---|---|---|
ElementorPro\Base\Base_Widget | 基础 Pro 功能封装 | 所有 Pro 风格 widget 的起点 |
Posts_Base | 查询控件、分页 | 文章/自定义文章类型列表 |
ElementorPro\Modules\Carousel\Widgets\Base | Swiper 整合 | 轮播类 widget |
ElementorPro\Modules\ThemeElements\Widgets\Base | Pro 分类支持 | Theme Builder 相关 widget |
Products_Base / WooCommerce 变体 | 商店整合 | 商品列表/展示类 widget |
Posts_Base 提供 elementor/query/{query_id} 这个 filter hook 可以自定义 WP_Query;只有数据源不是标准 WP_Query 时才需要覆盖 query_posts()。
怎么安装
这个 skill 是 mekko-digital/elementor-skills 这个开源仓库打包的 8 个技能之一,用 Claude Code 的插件市场机制安装,装一次全部到位:
Claude Code(推荐:走插件市场):
claude plugin marketplace add mekko-digital/elementor-skills
claude plugin install elementor-skills@elementor-skills-marketplace
Claude Code(手动方式): 把 skills/elementor-widget-create 这个文件夹复制到 ~/.claude/skills/(所有项目都能用)或专案底下的 ./.claude/skills/(只想在这个项目用)。
Claude Desktop / claude.ai: 走 Settings → Capabilities → Skills,上传 skills/elementor-widget-create 这个文件夹(打包成 zip,内含 SKILL.md)——插件市场机制是 Claude Code 专属的,Desktop 端目前只能手动上传单个 skill。
常见错误
- ❌ 经典架构和 4.0 atomic 架构的控件写法混着用——两套设置形状(settings shape)不一样,混用会直接坏掉,动手前先确认目标站点用哪一套
- ❌ 用了
Has_Templatetrait 又同时覆盖render()——两者是二选一的渲染路径,同时用会冲突 - ❌ Pro 基类的 license 检查照抄到自己的自定义 widget 上——
API::is_licence_has_feature()这类检查只有 Elementor 官方核心团队的 widget 才需要,自己写的 Pro 风格 widget 不用管这个 - 💡 widget 写完不代表结束——用同一个 skill 包里的
elementor-deploy-verify部署到 staging 站确认真的注册成功、渲染正常,再交给别人用 - 💡 不确定某个功能算免费版还是 Pro 版,先查
elementor-feature-lookup,不要凭印象猜
Sources
官方文档:
- elementor-skills(GitHub 仓库)— https://github.com/Mekko-Digital/elementor-skills
- elementor-widget-create SKILL.md — https://github.com/Mekko-Digital/elementor-skills/blob/main/skills/elementor-widget-create/SKILL.md