How to Build Custom Elementor Widget

Elementor is one of the most popular page builders for WordPress. Building a WordPress website using Elementor is easy and you can save a ton of time using this popular plugin. Elementor provides widgets for creating different sections on your pages. You just need to pick up a widget, configure it and it will display the generated elements on the frontend.

It may happen you are not getting widgets of your choice. You might be looking for a different functionality which is not possible through the default widgets of Elementor. In such scenarios, you need a custom widget that fulfills your requirement. Fortunately, Elementor is easy to extend and you can build any kind of functionality you wish by creating an Elementor extension. Elementor extensions are the same as regular WordPress plugins, they extend the basic functionality.

In this article, I show you how to build a custom Elementor widget which is nothing but an Elementor extension.

For seeing it practically, I am taking an example of Bootstrap Carousel. We will build a WordPress plugin for the custom Elementor widget. This widget will give you the ability to add Bootstrap carousel on your pages.

The purpose of this tutorial is to get you familiarized with Elementor widget development. We are going to develop an Elementor widget for Bootstrap Carousel. Using the same approach, you can build your own widgets.

Creating an Extension for Elementor

For getting started, you must have installed and activated the Elementor plugin. After this, create a folder ‘artisansweb-elementor-add-on’ inside the ‘wp-content/plugins’ directory. Here to the folder name and in the next part of the code I use the term ‘artisansweb’ to keep unique references. You can change this term whichever you want.

Inside our plugin create a file artisansweb-elementor-add-on.php. This file will contain a code which creates an extension of Elementor.

You will get the boilerplate of creating the extension on the Elementor documentation.

By following the documentation, I wrote a below code which you should add in the artisansweb-elementor-add-on.php file.

<?php
/*
Plugin Name: Elementor Widget - Bootstrap Carousel
Plugin URI: https://artisansweb.net
Description: Creates a Bootstrap Carousel.
Author: Artisans Web
Version: 1.0
Author URI: https://artisansweb.net
*/

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

final class Artisansweb_Elementor_Extension {

    const VERSION = '1.0';
    const MINIMUM_ELEMENTOR_VERSION = '2.0.0';
    const MINIMUM_PHP_VERSION = '7.0';

    private static $_instance = null;

    public static function instance() {
        if ( is_null( self::$_instance ) ) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function __construct() {
        add_action( 'init', [ $this, 'i18n' ] );
        add_action( 'plugins_loaded', [ $this, 'init' ] );
        add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ], 11 );
    }

    public function init() {
        // Check if Elementor installed and activated
        if ( ! did_action( 'elementor/loaded' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_missing_main_plugin' ] );
            return;
        }
        
        // Check for required Elementor version
        if ( ! version_compare( ELEMENTOR_VERSION, self::MINIMUM_ELEMENTOR_VERSION, '>=' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_minimum_elementor_version' ] );
            return;
        }
        
        // Check for required PHP version
        if ( version_compare( PHP_VERSION, self::MINIMUM_PHP_VERSION, '<' ) ) {
            add_action( 'admin_notices', [ $this, 'admin_notice_minimum_php_version' ] );
            return;
        }

        // Add Plugin actions
        add_action( 'elementor/widgets/widgets_registered', [ $this, 'init_widgets' ] );
    }
    
    public function i18n() {
        load_plugin_textdomain( 'artisansweb-elementor-add-on' );
    }
    
    public function admin_notice_missing_main_plugin() {
        if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );

        $message = sprintf(
            /* translators: 1: Plugin name 2: Elementor */
            esc_html__( '"%1$s" requires "%2$s" to be installed and activated.', 'artisansweb-elementor-add-on' ),
            '<strong>' . esc_html__( 'Elementor', 'artisansweb-elementor-add-on' ) . '</strong>'
        );

        printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
    }
    
    public function admin_notice_minimum_elementor_version() {
        if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );

        $message = sprintf(
            /* translators: 1: Plugin name 2: Elementor 3: Required Elementor version */
            esc_html__( '"%1$s" requires "%2$s" version %3$s or greater.', 'artisansweb-elementor-add-on' ),
            '<strong>' . esc_html__( 'Elementor', 'artisansweb-elementor-add-on' ) . '</strong>',
             self::MINIMUM_ELEMENTOR_VERSION
        );

        printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
    }
    
    public function admin_notice_minimum_php_version() {
        if ( isset( $_GET['activate'] ) ) unset( $_GET['activate'] );

        $message = sprintf(
            /* translators: 1: Plugin name 2: PHP 3: Required PHP version */
            esc_html__( '"%1$s" requires "%2$s" version %3$s or greater.', 'artisansweb-elementor-add-on' ),
            '<strong>' . esc_html__( 'PHP 7.0', 'artisansweb-elementor-add-on' ) . '</strong>',
             self::MINIMUM_PHP_VERSION
        );

        printf( '<div class="notice notice-warning is-dismissible"><p>%1$s</p></div>', $message );
    }
    
    public function init_widgets() {

        // Include Widget files
        require_once( __DIR__ . '/widgets/artisansweb-testimonial-widget.php' );

        // Register widget
        \Elementor\Plugin::instance()->widgets_manager->register_widget_type( new \Artisansweb_Testmonial_Widget() );

    }

    public function enqueue_scripts() {
        wp_register_style( "bootstrap-css", "https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css", array(), false, "all" );
        wp_enqueue_style( "bootstrap-css" );

        wp_register_script("bootstrap-js", "https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js", array(), false, true);
        wp_enqueue_script("bootstrap-js");
    }
}
Artisansweb_Elementor_Extension::instance();

In the above code inside init_widgets() method, I included a artisansweb-testimonial-widget.php from the ‘widgets’ directory. It means, you have to create a ‘widgets’ folder and inside it make a artisansweb-testimonial-widget.php file.

I added the JS and CSS files of Bootstrap from the enqueue_scripts function. Notice, I have given a CDN path of those files directly. The user can keep these files in the plugin folder and include it by replacing the above CDN path.

At this stage, you should see the plugin name appear on the Plugins->Installed Plugins page.

Plugin

Don’t activate the plugin. We have to write more code in order to get it working.

Elementor Widget Structure

We are done with including the required files for our widget. The next part is creating an actual Elementor widget. The Elementor website provided a widget structure which we have to follow.

Add the basic structure to the artisansweb-testimonial-widget.php file as follows.

<?php
class Artisansweb_Testmonial_Widget extends \Elementor\Widget_Base {

    public function get_name() {}

    public function get_title() {}

    public function get_icon() {}

    public function get_categories() {}

    protected function _register_controls() {}

    protected function render() {}

    protected function _content_template() {}

}

All methods defined in the above class have their own responsibility. You have to add you widget name in the method get_name(), widget icon will go inside get_icon(), frontend part will display from the render() method and so on. The descriptions of all methods are available on their documentation.

Note: Elementor allows to use font-awesome icons, simply return the class name as a string. I’ll add the icon ‘fa fa-sliders’ for our widget.

Let’s fill up the code for all the methods except the render(). As we have to take a reference from Bootstrap carousel, we will add the code for render() function in the later part of the tutorial.

<?php
class Artisansweb_Testmonial_Widget extends \Elementor\Widget_Base {

    public function get_name() {
        return 'artisansweb-carousel';
    }

    public function get_title() {
        return __( 'Artisansweb Carousel', 'artisansweb-elementor-add-on' );
    }

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

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

    protected function _register_controls() {

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

        $repeater = new \Elementor\Repeater();

        $repeater->add_control(
            'list_title', [
                'label' => __( 'Title', 'artisansweb-elementor-add-on' ),
                'type' => \Elementor\Controls_Manager::TEXT,
                'default' => __( 'List Title' , 'artisansweb-elementor-add-on' ),
                'label_block' => true,
            ]
        );

        $repeater->add_control(
            'list_image',
            [
                'label' => __( 'Choose Image', 'artisansweb-elementor-add-on' ),
                'type' => \Elementor\Controls_Manager::MEDIA,
                'default' => [
                    'url' => \Elementor\Utils::get_placeholder_image_src(),
                ],
            ]
        );

        $this->add_control(
            'list',
            [
                'label' => __( 'Repeater List', 'artisansweb-elementor-add-on' ),
                'type' => \Elementor\Controls_Manager::REPEATER,
                'fields' => $repeater->get_controls(),
                'default' => [
                    [
                        'list_title' => __( 'Title #1', 'artisansweb-elementor-add-on' ),
                        'list_image' => __( 'Item image.', 'artisansweb-elementor-add-on' ),
                    ],
                    [
                        'list_title' => __( 'Title #2', 'artisansweb-elementor-add-on' ),
                        'list_image' => __( 'Item image.', 'artisansweb-elementor-add-on' ),
                    ],
                ],
                'title_field' => '{{{ list_title }}}',
            ]
        );

        $this->end_controls_section();

    }
    
    protected function render() {
        // generate the final HTML on the frontend using PHP
    }
}

I have used an Elementor repeater control which allows you to build repeatable blocks of fields. As we are creating a carousel, it will have multiple fields. Here, I gave the options for adding an image and caption using a repeater control.

Along with repeater control, I also used the Text and Media control. Click here to read more about Elementor controls.

Activate the plugin and try to edit your page with Elementor. Search for ‘Artisansweb Carousel’, add this widget to the page. You will see the options to add caption and images as shown in the screenshot below.

Elementor Widget

Bootstrap Carousel using Custom Elementor Widget

We all set out to build a carousel using the Elementor widget. If you take a look at the Bootstrap carousel documentation, they have provided the HTML code for carousel. I am taking an example of a carousel with captions. For this type of carousel, you have to use the below HTML.

<div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
    <ol class="carousel-indicators">
        <li data-target="#carouselExampleIndicators" data-slide-to="0" class="active"></li>
        <li data-target="#carouselExampleIndicators" data-slide-to="1"></li>
    </ol>
      <div class="carousel-inner">
        <div class="carousel-item active">
              <img class="d-block w-100" src=".../800x400?auto=yes&bg=777&fg=555&text=First slide" alt="First slide">
              <h3>Caption here...</h3>
        </div>
        <div class="carousel-item">
              <img class="d-block w-100" src=".../800x400?auto=yes&bg=666&fg=444&text=Second slide" alt="Second slide">
              <h3>Caption here...</h3>
        </div>
      </div>
      <a class="carousel-control-prev" href="#carouselExampleIndicators" role="button" data-slide="prev">
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="sr-only">Previous</span>
      </a>
      <a class="carousel-control-next" href="#carouselExampleIndicators" role="button" data-slide="next">
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="sr-only">Next</span>
      </a>
</div>

The above one is static HTML. When it comes to the Elementor widget, we have to make it dynamic by using the values added for title and image.

So, our render() method will have the code as follows.

<?php
protected function render() {
    // generate the final HTML on the frontend using PHP
    $settings = $this->get_settings_for_display();

    if ( $settings['list'] ) {
        ?>
        <div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
            <ol class="carousel-indicators">

                <?php for($i=0; $i<count($settings['list']); $i++) { ?>
                    <li data-target="#carouselExampleIndicators" data-slide-to="0" class="<?php echo ($i==0) ? 'active':''; ?>"></li>
                <?php } ?>
            </ol>
            <div class="carousel-inner">
                <?php $i = 0; ?>
                <?php foreach (  $settings['list'] as $item ) { ?>
                    <div class="carousel-item <?php echo ($i==0) ? 'active':''; ?>">
                        <img class="d-block w-100" src="<?php echo $item['list_image']['url']; ?>" alt="<?php echo $item['list_title']; ?>" />
                        <div class="carousel-caption d-none d-md-block">
                            <h3><?php echo $item['list_title']; ?></h3>
                        </div>
                    </div>
                    <?php $i++; ?>
                <?php } ?>
            </div>
            <a class="carousel-control-prev" href="#carouselExampleIndicators" role="button" data-slide="prev">
                <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                <span class="sr-only">Previous</span>
            </a>
            <a class="carousel-control-next" href="#carouselExampleIndicators" role="button" data-slide="next">
                <span class="carousel-control-next-icon" aria-hidden="true"></span>
                <span class="sr-only">Next</span>
            </a>
        </div>
        <?php
    }
}

That’s it! Add your images and captions and you should now see the Bootstrap carousel appears on your page.

Carousel

It’s all about widget development in Elementor. In a similar way, you can customize the code to use different Elementor controls and generate the custom widgets as per your requirements.

I hope you understand how to build a custom Elementor widget. Please share your thoughts and suggestions in the comment section below.

Related Articles

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

1 thought on “How to Build Custom Elementor Widget

Leave a Reply

Your email address will not be published. Required fields are marked *