red line

How to Create a Custom Elementor Widget

Elementor is one of the best page builders out there! Learn how you can take it to a new level by creating your own custom widget inside Elementor.
elementor widget

Using Existing Widgets

Elementor is one of the best page builders to design your website out there. If you’re just starting out with Elementor, spend some time getting familiar with it before going off and creating your own widgets.

As a general rule if there is an easy way to accomplish a task without creating a new widget then for goodness sakes, go with the easy option and use the default functionality. If that doesn’t work your next best bet would be to try and customize an existing widget using styles and scripts.

If you’ve exhausted the first two options and are ready to create an Elementor widget, we’ll walk you through how to go about doing it.

The principle reason you’d want to create a custom Elementor widget is that the functionality you want is not available in an existing widget. To figure whether this is true, take a look at the widgets available in the Elementor Elements sidebar. Also, spend some time looking for the functionality you want in existing plugins. If you cannot find the widget you need, it’s time to create a custom widget.

Creating Your Own Widget

Dev Environment

To make this post easy to understand, we’ve provided a github repo and development environment, so you can follow along: https://github.com/pajtai/elementor-widgets-tutorial

At Solid Digital when we develop WordPress websites, we use Vagrant boxes provisioned by Ansible for local development. In this way, once we have a local environment set up for a client, we can use the same Ansible provisioning roles to setup the clients staging and production environments. We have a custom box we use, but we wanted something easy to setup and public for this demo. We tried Local by Flywheel and VVV, but they both had setups with too many steps. After more research we settled on VCCW, since it can be incorporated into an existing repo. To get going to follow this post, simply clone the demo repo, run vagrant up, and open http://192.168.33.10/. You’ll have to make sure you have Vagrant installed, and note that Vagrant depends on Virtualbox:

				
					git clone git@github.com:pajtai/elementor-widgets-tutorial.git
cd elementor-widgets-tutorial
vagrant up
bin/open
				
			

Let’s create a dropdown as a custom widget. A dropdown is a good example for a custom widget, since the HTML desired for a dropdown can be a highly personal choice, so it makes sense to customize it as a widget. We’ll also show you how to make the choices in the dropdown configurable.

Login to http://192.168.33.10/wp-admin/plugins.php using admin:admin, and activate the Elementor plugin. You can use bin/open to quickly get to the wp-admin page.

Getting Started

The first decision to make is whether to add the widget to a plugin or your current theme. In general putting the widget into a plugin allows you to reuse your widget later. It also allows you to separate your widget code, styling, and scripts from the theme. If you are creating a widget that only makes sense for your current project, then puting it in the theme might be a good idea.

In our case, we’ll create a plugin called elementor-dropdown in wp-content/plugins/elementor-dropdown.

In order to be able to concentrate on the items unique to an elementor plugin, we’re going to go with a very simple single file structure. In reality you will want to add all the standard goodies to your plugin. These would include thing like internationalization, verifying that Elementor is activated, verifying the PHP version, etc. In our case, this extra boiler plate would obscure the functionality we’re interested in.

We want to keep the plugin as simple as possible, but the Elementor namespace is not available until after Elementor is loaded. If you try to access the Widget_Base class too early, you’ll get a Class 'Elementor\Widget_Base' not found. error. So let’s move our class to a separate file and only load it after Elementor is loaded.

This issue is not documented on Elementor’s Widget Creation Page, so I had to do a little trial an error to find the correct action to hook into. plugins_loaded still produces the error, but elementor/widgets/widgets_registered seems to work:

				
					<?php
/**
 * Plugin Name: Elementor Dropdown
 * Description: A simple Elementor Widget that creates an HTML Select "dropdown"
 * Plugin URI:  https://www.soliddigital.com/blog/...
 * Version:     1.0.0
 * Author:      Peter Ajtai
 * Author URI:  https://pajtai.github.io/
 * Text Domain: elementor-dropdown
 */
namespace Solid_Dropdown;
use Elementor\Plugin;

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

// The Widget_Base class is not available immediately after plugins are loaded, so
// we delay the class' use until Elementor widgets are registered
add_action( 'elementor/widgets/widgets_registered', function() {
	require_once('widget.php');

	$drop_down_widget =	new Dropdown_Widget();

	// Let Elementor know about our widget
	Plugin::instance()->widgets_manager->register_widget_type( $drop_down_widget );
});
				
			

Once the widgets_registered action runs, we can register our own widget using Plugin::instance()->widgets_manager->register_widget_type.

To create an Elementor widget, we’ll use an OOP approach, since Elementor has a base Class we can extend.

				
					<?php
namespace Solid_Dropdown;

use Elementor\Repeater;
use Elementor\Widget_Base;

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class Dropdown_Widget extends Widget_Base {

	public static $slug = 'elementor-dropdown';

	public function get_name() { return self::$slug; }

	public function get_title() { return __('Elementor Dropdown', self::$slug); }

	public function get_icon() { return 'fa fa-caret-down'; }

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

With the class, you can define a widgets name and title. The icon is the icon that will be shown in the left hand sidebar of the Elementor editor, and the category is the category or categories that will be shown under it in the left hand sidebar. The default categories are “basic,” “general,” and “wordpress.”

At this point you should activate the Elementor Dropdown plugin. Now you’ll be able to see it when you edit a post.

Controls

Next we want to add the value and name for each dropdown. Elementor calls the inputs an admin uses to customize a widget “controls.” So we want to register some controls. First we’ll register just enough controls for one option, then we’ll add the ability for the admin user to dynamically add, remove, and reorder the dropdown options.

Available controls are listed here. We’ll start by using two text controls to capture the value attribute and content of one  element:

				
					<?php

	protected function _register_controls() {

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

		$this->add_control(
			'widget_value',
			[
				'label' => __( 'value', self::$slug ),
				'type' => \Elementor\Controls_Manager::TEXT,
				'default' => __( 'value', self::$slug ),
				'placeholder' => __( 'Value Attribute', self::$slug ),
			]
		);

		$this->add_control(
			'widget_contents',
			[
				'label' => __( 'contents', self::$slug ),
				'type' => \Elementor\Controls_Manager::TEXT,
				'default' => __( 'contents', self::$slug ),
				'placeholder' => __( 'Option Contents', self::$slug ),
			]
		);
    
		$this->end_controls_section();
	}
				
			

Now when you add an Elementor Dropdownor click on an existing one, you’ll see an “Options” section in the left hand sidebar, and you’ll see textboxes to add a Value and Contents. With this code, Elementor will save updates to these values for you. You’ll notice that the values show up neither in the Elementor preview on the right or on the front end. We’ll get to that soon, but first let’s add the ability to add more than one option.

To add multiple options, we’ll use the repeater control. An example of the repeater control in the existing widgets is the Tabs Widget.

The concept of repeaters is a general and useful one. Repeaters allow you to reuse a set of items by creating and managing multiple copies of the set. Usual options for management of the repeated items are the ability to reorder them, add more sets, and delete sets. Another example of the usage of a repeater is in the popular Advanced Custom Fields Plugin.
To use an Elemntor repeater, we have to first define what one set looks like. Then we can allow that set to be repeated.

We can use the \Elementor\Repeater class to define what we want to be able to repeat. Note that basically the only change is that we add the controls to the $repeater instead of to the Widget instance:

				
					<?php
		$repeater = new Repeater();

		$repeater->add_control(
			'option_value',
			[
				'label' => __( 'Option Value', self::$slug ),
				'type' => \Elementor\Controls_Manager::TEXT,
				'default' => __( "The Option's Value", self::$slug ),
				'placeholder' => __( 'Value Attribute', self::$slug ),
			]
		);

		$repeater->add_control(
			'option_contents',
			[
				'label' => __( 'Option Contents', self::$slug ),
				'type' => \Elementor\Controls_Manager::TEXT,
				'default' => __( "The Option's Contents", self::$slug ),
				'placeholder' => __( 'Option Contents', self::$slug ),
			]
		);
				
			

The above defines the tab_title and tab_contents as the set of items that we can repeat. To add the $repeater to the widget we then do:

				
					<?php
		$this->add_control(
			'options_list',
			[
				'label' => __( 'Repeater List', self::$slug ),
				'type' => \Elementor\Controls_Manager::REPEATER,
				'fields' => $repeater->get_controls(),
				'default' => [
					[]
				],
				'title_field' => '{{{ option_contents }}}'
			]
		);
				
			

The default field above means that when we add a new Dropdown, it will be populated with one option using the default values defined on a single option. If we wanted the default to be, say, three options we would use:

				
					<?php
[
'default' => [
  [], [], []
]
				
			

If you don’t want to use the defaults from the original definition of option_value and option_contents, you can define them here:

				
					<?php
[
'default' => [
  [
    'option_value' => 'new-value',
    'option_contents' => 'Overriding the original defaults'
  ]
]
				
			

If you play around with the above, you’ll notice that the label for each set is the Option Contents for that set. This is enabled with templating. While the templating is not explained in the repeater documentation, it is demontrated there. So {{{ option_contents }}} has a context of the current set. We could be more explicit by using Contents: {{{ option_contents }}}, or we could add both the contents and the value by writing: {{{ option_contents }}} : {{{ option_value }}}.

Rendering

The final step is to render the element. This is what the element will look like both on the front end and in the wp-admin’s Elementor preview.

Rendering a repeater entails usage of the get_settings_for_display method. In Elementor speak, “settings” are the admin input to controls. In our case, we’re interested in the options_list setting:

				
					<?php
	protected function render() {
		$options_list = $this->get_settings_for_display('options_list');
		echo "<select>";
		foreach ($options_list as $option_item) {
			echo "<option value='{$option_item['option_value']}'>{$option_item['option_contents']}</option>";
		}
		echo "<select>";
	}
				
			

Wrapping up

… and with that we’re done with our basic custom Elementor widget. Of course if you wanted to add such a widget to your Elementor plugin library, you’d have to make a few modifications. You’d have to think about how to incorporate the dropdown into either a form or add JavaScript functionality to it. You’d probably want to add some styling. Since styling select elements is difficult you might want to do this via JavaScript with something like Select2 or Vue. The solutions to these are not very Elementor dependent. If you’re familiar with Wordpress and JavaScript, you should be able to figure it out!

The syntax highlights in this post were created using our own custom Elementor syntax highlighting widget.

References

Related resources
Authentication
code to dismiss alerts in Elementor