AI TOOLS

EP01. "elementor-widget-create 自定义 Widget 搭建"

首页 AI 工具 Claude · Skills · Elementor Skills · EP01
约 18 分钟· #EP01#Claude#Elementor Skills
🔒 登录后可标记已读
  • 自己写一个 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_BaseCarousel_Base、WooCommerce 变体等)做电商/文章列表类 widget

不适合用在:

  • 单纯排查一个已存在的 widget 为什么渲染不出来或坏了——那是 elementor-debug-render 的工作
  • 不确定某个功能是免费版还是 Pro 版才有——先查 elementor-feature-lookup
  • 做整页排版(把好几个 widget 组合成一个页面)——那是 elementor-design-to-page 的工作,这个 skill 只管单一 widget 怎么写

三种架构怎么选

架构继承的基类什么时候用
经典 Widget_BaseElementor\Widget_Base3.x~4.x 非 atomic 站点,目前市面上大多数自定义 widget 走这条路
4.0 Atomic WidgetElementor\Modules\AtomicWidgets\Elements\Base\Atomic_Widget_Base目标站点已经在用 Elementor 4.0 的新 atomic 编辑器,需要类型化的 props schema
Pro 专用基类Base_WidgetPosts_BaseCarousel_BaseProducts_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_Baseget_element_type() 要回传一个 e- 开头的字符串(例如 e-my-widget
  • define_props_schema() 定义类型化的属性 schema,不是像经典架构那样逐个 add_control()
  • Prop Type 常用的有 String_Prop_TypeNumber_Prop_TypeColor_Prop_TypeImage_Prop_TypeLink_Prop_Type 等,默认值用 Prop_Type::make()->default($value),必填用 ->required()
  • 渲染走 Has_Template trait + 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\BaseSwiper 整合轮播类 widget
ElementorPro\Modules\ThemeElements\Widgets\BasePro 分类支持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_Template trait 又同时覆盖 render()——两者是二选一的渲染路径,同时用会冲突
  • ❌ Pro 基类的 license 检查照抄到自己的自定义 widget 上——API::is_licence_has_feature() 这类检查只有 Elementor 官方核心团队的 widget 才需要,自己写的 Pro 风格 widget 不用管这个
  • 💡 widget 写完不代表结束——用同一个 skill 包里的 elementor-deploy-verify 部署到 staging 站确认真的注册成功、渲染正常,再交给别人用
  • 💡 不确定某个功能算免费版还是 Pro 版,先查 elementor-feature-lookup,不要凭印象猜

Sources

官方文档:

  1. elementor-skills(GitHub 仓库)— https://github.com/Mekko-Digital/elementor-skills
  2. elementor-widget-create SKILL.md — https://github.com/Mekko-Digital/elementor-skills/blob/main/skills/elementor-widget-create/SKILL.md