Token导航 LogoToken导航

Agent Skill · 前端设计

elementor-forms(元素形式)

elementor-forms 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

elementor-forms 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证信息还不明确,第三方扫描已通过,按安装量在前端设计类的 10,216 个 Skill 里排第 8,536。

总安装 279周安装 12GitHub Stars 3下载 98核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:elementor-forms(元素形式)
来源仓库:https://github.com/peixotorms/odinlayer-skills
仓库路径:skills/elementor-forms
安装命令:
npx skills add https://github.com/peixotorms/odinlayer-skills --skill elementor-forms
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/peixotorms/odinlayer-skills --skill elementor-forms

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

elementor-forms 提供 Elementor Pro 表单动作扩展的开发接口与使用指南。适用于注册自定义表单行为、集成第三方服务或处理提交逻辑。通过 npx skills add 命令从 GitHub 安装,需确认仓库权限与网络访问能力。使用前应核实维护状态及是否涉及文件读写、命令执行等敏感操作。

适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/elementor-forms

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/peixotorms/odinlayer-skills --skill elementor-…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

elementor-forms 怎么安装?

在终端执行 npx skills add https://github.com/peixotorms/odinlayer-skills --skill elementor-forms。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

elementor-forms 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

elementor-forms 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

elementor-forms 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

elementor-forms 用的人多吗?

公开数据是累计安装 279 次,近一周安装 12 次,下载 98 次,GitHub 3 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

elementor-forms 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
elementor-forms

元素形式 · 本页

2793接触敏感数据未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Elementor Forms Extension Reference

Elementor Pro only. All form APIs require Elementor Pro active.

1. Form Actions

Actions execute after form submission. Extend \ElementorPro\Modules\Forms\Classes\Action_Base.

Registration

add_action( 'elementor_pro/forms/actions/register', function ( $form_actions_registrar ) {
    require_once __DIR__ . '/form-actions/my-action.php';
    $form_actions_registrar->register( new \My_Custom_Action() );
});

Required Methods

MethodReturnsPurpose
get_name()stringUnique action ID used in code
get_label()stringDisplay label in editor
run($record, $ajax_handler)voidExecute on form submission
register_settings_section($widget)voidOptional: add action controls
on_export($element)arrayOptional: strip sensitive data on export

Action Controls

Always wrap in a section with submit_actions condition:

public function register_settings_section( $widget ): void {
    $widget->start_controls_section( 'section_my_action', [
        'label' => esc_html__( 'My Action', 'textdomain' ),
        'condition' => [ 'submit_actions' => $this->get_name() ],
    ]);
    $widget->add_control( 'my_api_key', [
        'label' => esc_html__( 'API Key', 'textdomain' ),
        'type' => \Elementor\Controls_Manager::TEXT,
    ]);
    $widget->end_controls_section();
}

Record Data ($record) and AJAX Handler

public function run( $record, $ajax_handler ): void {
    $settings = $record->get( 'form_settings' );    // Editor control values
    $raw_fields = $record->get( 'fields' );          // All submitted fields
    // Normalize: $fields[ $id ] = $field['value']
    $fields = [];
    foreach ( $raw_fields as $id => $field ) {
        $fields[ $id ] = $field['value'];
    }
    // AJAX handler methods:
    $ajax_handler->add_error( $field_id, 'Error message' );
    $ajax_handler->add_success_message( 'Success!' );
}

On Export -- strip sensitive settings

public function on_export( $element ): array {
    unset( $element['my_api_key'], $element['my_secret'] );
    return $element;
}

Simple Example: Webhook Ping Action

class Ping_Action_After_Submit extends \ElementorPro\Modules\Forms\Classes\Action_Base {
    public function get_name(): string { return 'ping'; }
    public function get_label(): string { return esc_html__( 'Ping', 'textdomain' ); }

    public function run( $record, $ajax_handler ): void {
        wp_remote_post( 'https://api.example.com/', [
            'headers' => [ 'Content-Type' => 'application/json' ],
            'body' => wp_json_encode([
                'site' => get_home_url(),
                'action' => 'Form submitted',
            ]),
            'timeout' => 60,
        ]);
    }

    public function register_settings_section( $widget ): void {}
    public function on_export( $element ): array { return $element; }
}

Advanced Example: Sendy Subscriber Action

class Sendy_Action_After_Submit extends \ElementorPro\Modules\Forms\Classes\Action_Base {
    public function get_name(): string { return 'sendy'; }
    public function get_label(): string { return esc_html__( 'Sendy', 'textdomain' ); }

    public function register_settings_section( $widget ): void {
        $widget->start_controls_section( 'section_sendy', [
            'label' => esc_html__( 'Sendy', 'textdomain' ),
            'condition' => [ 'submit_actions' => $this->get_name() ],
        ]);
        $widget->add_control( 'sendy_url', [
            'label' => esc_html__( 'Sendy URL', 'textdomain' ),
            'type' => \Elementor\Controls_Manager::TEXT,
            'placeholder' => 'https://your_sendy_installation/',
        ]);
        $widget->add_control( 'sendy_list', [
            'label' => esc_html__( 'Sendy List ID', 'textdomain' ),
            'type' => \Elementor\Controls_Manager::TEXT,
        ]);
        $widget->add_control( 'sendy_email_field', [
            'label' => esc_html__( 'Email Field ID', 'textdomain' ),
            'type' => \Elementor\Controls_Manager::TEXT,
        ]);
        $widget->add_control( 'sendy_name_field', [
            'label' => esc_html__( 'Name Field ID', 'textdomain' ),
            'type' => \Elementor\Controls_Manager::TEXT,
        ]);
        $widget->end_controls_section();
    }

    public function run( $record, $ajax_handler ): void {
        $settings = $record->get( 'form_settings' );
        if ( empty( $settings['sendy_url'] ) || empty( $settings['sendy_list'] ) || empty( $settings['sendy_email_field'] ) ) {
            return;
        }
        $raw_fields = $record->get( 'fields' );
        $fields = [];
        foreach ( $raw_fields as $id => $field ) { $fields[ $id ] = $field['value']; }
        if ( empty( $fields[ $settings['sendy_email_field'] ] ) ) { return; }

        $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'] : '',
        ];
        if ( ! empty( $fields[ $settings['sendy_name_field'] ] ) ) {
            $sendy_data['name'] = $fields[ $settings['sendy_name_field'] ];
        }
        wp_remote_post( $settings['sendy_url'] . 'subscribe', [ 'body' => $sendy_data ] );
    }

    public function on_export( $element ): array {
        unset( $element['sendy_url'], $element['sendy_list'], $element['sendy_email_field'], $element['sendy_name_field'] );
        return $element;
    }
}

2. Form Fields

Custom field types. Extend \ElementorPro\Modules\Forms\Fields\Field_Base.

Registration

add_action( 'elementor_pro/forms/fields/register', function ( $form_fields_registrar ) {
    require_once __DIR__ . '/form-fields/my-field.php';
    $form_fields_registrar->register( new \My_Custom_Field() );
});

Required Methods

MethodReturnsPurpose
get_type()stringUnique field type ID
get_name()stringDisplay label in editor dropdown
render($item, $item_index, $form)voidOutput field HTML on frontend
validation($field, $record, $ajax_handler)voidOptional: validate submitted value
update_controls($widget)voidOptional: add field-specific controls
get_script_depends()arrayOptional: JS dependency handles
get_style_depends()arrayOptional: CSS dependency handles

Render -- use add_render_attribute

public function render( $item, $item_index, $form ): void {
    $form->add_render_attribute( 'input' . $item_index, [
        'type'  => 'text',
        'class' => 'elementor-field-textual',
        'placeholder' => esc_html__( 'Placeholder', 'textdomain' ),
    ]);
    echo '<input ' . $form->get_render_attribute_string( 'input' . $item_index ) . '>';
}

Access field control values from $item: $item['my-control-name'].

Field Validation

public function validation( $field, $record, $ajax_handler ): void {
    if ( empty( $field['value'] ) ) { return; }
    if ( ! preg_match( '/^[0-9]+$/', $field['value'] ) ) {
        $ajax_handler->add_error( $field['id'], esc_html__( 'Only numbers.', 'textdomain' ) );
    }
}

Field Controls (update_controls)

Inject into the form field repeater. Requires condition, tab, inner_tab, tabs_wrapper:

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 = [
        'my-placeholder' => [
            'name' => 'my-placeholder',
            'label' => esc_html__( 'Placeholder', '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 );
}

Content Template (JS Editor Preview)

Workaround for live preview. Do NOT name your method content_template() (reserved for future use):

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 fieldId    = `form_field_${i}`;
                const fieldClass = `elementor-field-textual elementor-field ${item.css_classes}`;
                return `<input id="${fieldId}" class="${fieldClass}" type="text">`;
            }, 10, 3
        );
    });
    </script>
    <?php
}

Field Dependencies

// Register in plugin main file
add_action( 'wp_enqueue_scripts', function () {
    wp_register_script( 'my-field-js', plugins_url( 'assets/js/field.js', __FILE__ ) );
    wp_register_style( 'my-field-css', plugins_url( 'assets/css/field.css', __FILE__ ) );
});
// Declare in field class
public function get_script_depends(): array { return [ 'my-field-js' ]; }
public function get_style_depends(): array { return [ 'my-field-css' ]; }
// Backward compat (Elementor < 3.28): also set public properties
public $depended_scripts = [ 'my-field-js' ];
public $depended_styles = [ 'my-field-css' ];

Simple Example: Local Tel Field with Pattern

class Elementor_Local_Tel_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
    public function get_type(): string { return 'local-tel'; }
    public function get_name(): string { return esc_html__( 'Local Tel', 'textdomain' ); }

    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', 'textdomain' ),
        ]);
        echo '<input ' . $form->get_render_attribute_string( 'input' . $item_index ) . '>';
    }

    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 must be "123-456-7890" format.', 'textdomain' ) );
        }
    }

    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 ) {
                    return `<input id="form_field_${i}" class="elementor-field-textual elementor-field ${item.css_classes}" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}">`;
                }, 10, 3 );
        });
        </script>
    <?php }
}

Advanced Example: Credit Card Field with Controls and Validation

class Elementor_Credit_Card_Number_Field extends \ElementorPro\Modules\Forms\Fields\Field_Base {
    public function get_type(): string { return 'credit-card-number'; }
    public function get_name(): string { return esc_html__( 'Credit Card Number', 'textdomain' ); }

    public function render( $item, $item_index, $form ): void {
        $form->add_render_attribute( 'input' . $item_index, [
            'class' => 'elementor-field-textual', '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 ) . '>';
    }

    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__( 'Card number must be "XXXX XXXX XXXX XXXX".', 'textdomain' ) );
        }
    }

    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', 'textdomain' ),
                '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 );
    }

    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 ) {
                    return `<input type="tel" id="form_field_${i}" class="elementor-field-textual elementor-field ${item.css_classes}" inputmode="numeric" maxlength="19" placeholder="${item['credit-card-placeholder']}" autocomplete="cc-number">`;
                }, 10, 3 );
        });
        </script>
    <?php }
}

Removing Built-in Fields

add_filter( 'elementor_pro/forms/field_types', function ( $fields ) {
    unset( $fields['upload'] ); // Remove file upload field
    return $fields;
});

3. Form Validation

Global validation hook fires before form processing:

add_action( 'elementor_pro/forms/validation', function ( $record, $ajax_handler ) {
    $fields = $record->get( 'fields' );

    // Single field validation
    if ( ! empty( $fields['my_field']['value'] ) && strlen( $fields['my_field']['value'] ) < 5 ) {
        $ajax_handler->add_error( 'my_field', esc_html__( 'Min 5 characters.', 'textdomain' ) );
    }

    // Cross-field validation
    if ( ! empty( $fields['password']['value'] ) && ! empty( $fields['confirm']['value'] ) ) {
        if ( $fields['password']['value'] !== $fields['confirm']['value'] ) {
            $ajax_handler->add_error( 'confirm', esc_html__( 'Passwords do not match.', 'textdomain' ) );
        }
    }
}, 10, 2 );

Any add_error() call halts submission and returns errors to the client.


4. Form Processing Hooks

HookParamsWhen
elementor_pro/forms/validation$record, $ajax_handlerBefore processing -- validate fields
elementor_pro/forms/process$record, $ajax_handlerDuring form processing
elementor_pro/forms/new_record$record, $ajax_handlerAfter successful submission
elementor_pro/forms/mail_sent$settings, $recordAfter email action sends

Email Filters

add_filter( 'elementor_pro/forms/wp_mail_headers', function ( $headers ) {
    return $headers . "Cc: copy@example.com\r\n";
});
add_filter( 'elementor_pro/forms/wp_mail_message', function ( $message ) {
    return $message . "\n\n-- Sent via My Site";
});

Webhook Filter

add_filter( 'elementor_pro/forms/webhooks/response', function ( $response, $record ) {
    if ( is_wp_error( $response ) ) {
        error_log( 'Webhook failed: ' . $response->get_error_message() );
    }
    return $response;
}, 10, 2 );

5. Common Mistakes

MistakeFix
Missing condition on action controls sectionSet 'condition' => ['submit_actions' => $this->get_name()]
Hardcoding HTML attributes in render()Use $form->add_render_attribute() / get_render_attribute_string()
Not checking empty($field['value']) in validationAlways return early if empty (required check is separate)
Naming a method content_template() on field classReserved for future use -- use content_template_script() workaround
Exporting sensitive control dataImplement on_export() with unset() for all sensitive keys
Not escaping labels and attributesUse esc_html__() for labels, esc_attr() for attributes
Missing is_wp_error() check in update_controls()Always guard get_control_from_stack() result
Missing tab/inner_tab/tabs_wrapper on field controlsRequired for controls to appear in the correct repeater tab
Wrong registration hookActions: elementor_pro/forms/actions/register. Fields: elementor_pro/forms/fields/register
Not calling parent::__construct() in field constructorRequired when overriding __construct() for editor preview

平台分布

Codex

35.43%
按下载量换算35

Claude

33.2%
按下载量换算33

Cursor

18.53%
按下载量换算18

Gemini CLI

10.29%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills