Skip to main content

Command Palette

Search for a command to run...

Build a Fully Working Elementor Addon (Custom Widget Plugin)

Updated
•5 min read•View as Markdown
N
Global tech creator.

1. Overview

An Elementor addon is essentially a WordPress plugin that registers custom widgets into Elementor’s editor panel.

At a minimum, your addon must:

  • Register itself with WordPress

  • Hook into Elementor lifecycle

  • Define one or more widget classes

  • Register controls (inputs)

  • Render output (frontend + editor preview)

2. Plugin Structure

Create this folder:

/wp-content/plugins/my-elementor-addon/

Inside:

my-elementor-addon/
│
├── my-elementor-addon.php
├── widgets/
│   └── hello-widget.php
└── assets/
    ├── css/
    │   └── style.css
    └── js/
        └── script.js

3. Main Plugin File

📄 File: my-elementor-addon.php

✅ Purpose

Bootstraps plugin, checks Elementor, registers widgets.

<?php
/**
 * Plugin Name: My Elementor Addon
 * Description: Custom Elementor widgets
 * Version: 1.0
 * Author: Your Name
 */

if (!defined('ABSPATH')) exit;

// Check if Elementor is loaded
function mea_check_elementor_loaded() {
    if (!did_action('elementor/loaded')) {
        add_action('admin_notices', function() {
    echo '<div class="notice notice-warning"><p>Elementor not installed.</p></div>';
        });
        return;
    }
}
add_action('plugins_loaded', 'mea_check_elementor_loaded');

// Register Widget
function mea_register_widgets($widgets_manager) {
    require_once(__DIR__ . '/widgets/hello-widget.php');
$widgets_manager->register(new \MEA_Hello_Widget()); } add_action('elementor/widgets/register', 'mea_register_widgets');

// Register Assets
function mea_register_assets() {
wp_register_style('mea-style', plugins_url('/assets/css/style.css', FILE)); wp_register_script('mea-script', plugins_url('/assets/js/script.js', FILE), ['jquery'], false, true); } 
add_action('wp_enqueue_scripts', 'mea_register_assets');

🔍 Explanation

Section Role
Plugin header Required for WordPress recognition
did_action() Ensures Elementor is active
elementor/widgets/register Hook to register widgets
wp_register_style/script Prepares frontend assets

4. Create Your First Widget

📄 File: widgets/hello-widget.php

<?php
if (!defined('ABSPATH')) exit;

class MEA_Hello_Widget extends \Elementor\Widget_Base {

    // Widget internal name
  public function get_name() {
        return 'hello_widget';
    }

    // Widget display title
   public function get_title() {
        return 'Hello Widget';
    }

    // Widget icon in Elementor panel
    public function get_icon() {
        return 'eicon-code';
    }

  // Widget category
    public function get_categories() {
        return ['general'];
    }

🎛️ Controls (User Inputs)

📌 Purpose

Defines editable UI fields in Elementor panel.

 protected function register_controls() {

        $this->start_controls_section(
            'content_section',
  [
                'label' => 'Content',
                'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
            ]
        );

        // Text Input
   $this->add_control(
            'title',
            [
                'label' => 'Title',
                'type' => \Elementor\Controls_Manager::TEXT,
                'default' => 'Hello World',
            ]
        );

        // Color Picker
  $this->add_control(
            'color',
            [
                'label' => 'Text Color',
                'type' => \Elementor\Controls_Manager::COLOR,
                'default' => '#000000',
            ]
        );

    $this->end_controls_section();
    }

🖥️ Frontend Rendering

📌 Purpose

Outputs HTML seen on the live website.

   protected function render() {
        \(settings = \)this->get_settings_for_display();

        echo '<h2 style="color:' . esc_attr($settings['color']) . ';">';
        echo esc_html($settings['title']);
        echo '</h2>';
    }

⚡ Editor Live Preview (JS Template)

📌 Purpose

Shows real-time preview inside Elementor editor.

 protected function content_template() {
        ?>
        <#
        var color = settings.color;
        var title = settings.title;
        #>

        <h2 style="color: {{ color }}">{{{ title }}}</h2>
        <?php
    }
}

5. Add Styling

📄 File: assets/css/style.css

.mea-widget {
    padding: 20px;
    border: 1px solid #ddd;
    text-align: center;
}

6. Add Script (Optional)

📄 File: assets/js/script.js

jQuery(document).ready(function($) {
    console.log("Elementor addon loaded");
});

7. Enqueue Assets in Widget (Best Practice)

Modify widget class:

public function get_style_depends() {
    return ['mea-style'];
}

public function get_script_depends() {
    return ['mea-script'];
}

8. Final Result

After activating plugin:

  • Go to Elementor editor

  • Search: Hello Widget

  • Drag & drop

  • Edit text + color live

9. Advanced Enhancements

🔧 Add More Controls

$this->add_control(
    'alignment',
    [
   'label' => 'Alignment',
        'type' => \Elementor\Controls_Manager::CHOOSE,
        'options' => [
            'left' => ['title' => 'Left', 'icon' => 'eicon-text-align-left'],
            'center' => ['title' => 'Center', 'icon' => 'eicon-text-align-center'],
            'right' => ['title' => 'Right', 'icon' => 'eicon-text-align-right'],
        ],
   'default' => 'center',
    ]
);

🧩 Add Repeater (Dynamic Lists)

$repeater = new \Elementor\Repeater();

$repeater->add_control(
    'list_text',
    [
        'label' => 'Item Text',
        'type' => \Elementor\Controls_Manager::TEXT,
    ]
);

$this->add_control(
    'list',
    [
        'label' => 'List Items',
        'type' => \Elementor\Controls_Manager::REPEATER,
        'fields' => $repeater->get_controls(),
    ]
);

🎨 Add Style Tab Controls

$this->start_controls_section(
    'style_section',
 [
        'label' => 'Style',
        'tab' => \Elementor\Controls_Manager::TAB_STYLE,
    ]
);

$this->add_control(
    'bg_color',
    [
        'label' => 'Background',
        'type' => \Elementor\Controls_Manager::COLOR,
        'selectors' => [
            '{{WRAPPER}}' => 'background-color: {{VALUE}};',
        ],
    ]
);

$this->end_controls_section();

10. Common Pitfalls

Issue Cause
Widget not showing Wrong hook (elementor/widgets/register)
Fatal error Missing use Elementor\Widget_Base namespace
No styles Not enqueued properly
Live preview broken Missing content_template()

11. Production Best Practices

  • Use PSR-4 autoloading instead of manual require

  • Split widgets into multiple files

  • Use namespaces:

namespace MEA\Widgets;
  • Add security escaping:

    • esc_html()

    • esc_attr()

  • Use translatable strings:

__('Hello Widget', 'mea')

12. Scaling Your Addon

Once basics work, you can evolve into:

  • Widget packs (10–50 widgets)

  • Dynamic data integrations (API, AI, etc.)

  • Custom Elementor controls

  • WooCommerce widgets

13. Mental Model (Important)

Think of Elementor widgets as:

Controls (UI config)
        ↓
Settings array
        ↓
Render() → HTML output
        ↓
Styled via CSS + dynamic selectors

14. Minimal Working Summary

If you strip everything down:

  • Plugin file loads widget

  • Widget defines:

    • name

    • controls

    • render()

That alone = fully working Elementor addon.