Разработка сайтов – заказать разработку сайта

Create custom Elementor Widget – Image Comparison step by step guide

Image Comparison Elementor widget

Welcome to this tutorial where we’ll delve into the process of crafting your own custom Elementor widget. In real-world projects, there are often instances where the standard set of widgets in Elementor, whether in the Free or Pro version, might not fully meet your design or functional requirements. This is where the ability to create custom widgets becomes invaluable, empowering you to design layouts or blocks precisely tailored to your needs.

Let’s explore how to develop custom Elementor widgets, equipping you with the knowledge to navigate such situations effectively and enhance your website-building capabilities.

Read this tutorial, and I will show you exactly how. Trust me, it is very easy.

Table of Contents

Create an Elementor Widget — a Step by step guide

Before we start, there are a few things you’ll need to have:

  1. Basic knowledge of PHP and JavaScript: While there are tools that make it easier to create Elementor widgets, having a basic understanding of these two languages will make the process much smoother.
  2. Testing website: You’ll need a place to test your widgets as you create them. I prefer to use InstaWp as it simple and easy. You can create testing wordpress website absolutely free. Its better to test your coding overe there rather than on your website, as things can go wrong.
  3. Elementor plugin installed: Pretty self-explanatory, right?
  4. A text editor: You’ll need something to write your code in. I’d recommend something like VSCode, or Notepad++.

Custom Elementor widget development

We’ll be creating a custom plugin to hold our widget. Why a plugin, you ask? Well, because Elementor reads from the plugins directory when looking for widgets to add to its library.

In your WordPress plugins directory (wp-content/plugins), create a new folder for your plugin. You can name it anything you like. I’ll call mine image-comparison.

In your new plugin directory, create a new PHP file with the same name as your folder (e.g., image-comparison.php). This will be the main plugin file where we’ll write the initial code.

Inside this, let’s put the plugin declaration so WordPress can recognize this plugin.

				
					<?php
/**
 * Plugin Name: Before | After picture slider
 * Description: Slider that show before and after on a picture
 * Plugin URI:  https://standigital.lv
 * Version: 1.0
 * Author: StanDigital
 * Author URI: https://standigital.lv
 * Text Domain: image-comparison-elementor-widget
 *
 * Elementor tested up to: 3.19.3
 * Elementor Pro tested up to: 3.19.3
 */
				
			

Now, let’s break down what this code does. First, it sets up the basic information for the plugin, such as its name, description, version, author, and more. This information is important for identifying and managing the plugin within the WordPress ecosystem.

So now, in the dashboard, if you go to Plugins, you see, our plugin is here.

We made a custom WordPress Elementor widgets plugin
We made a custom WordPress Elementor widgets plugin

We made a custom WordPress Elementor widgets plugin

Cool, right. We just created a plugin. Now it is time to write our code.

First, I am applying a very basic check, so that, no one access the plugin directly, it is for security.

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

Now, moving to the main things.

We will now register our custom Elementor widget. I am going to follow this documentation from the Elementor website.

So let’s put this.

				
					// Register Widget
function register_image_comparison_widget( $widgets_manager ) {
    require_once( __DIR__ . '/widgets/image-comparison-widget.php' );
    $widgets_manager->register( new \Elementor_Image_Comparison_Widget() );
}
add_action( 'elementor/widgets/register', 'register_image_comparison_widget' );

// Enqueue Scripts and Styles
function enqueue_image_comparison_widget_scripts() {
    wp_enqueue_style( 'image-comparison-widget-style', plugins_url( 'style.css', __FILE__ ) );
    wp_enqueue_script( 'image-comparison-widget-script', plugins_url( 'script.js', __FILE__ ), array('jquery'), false, true );
}
add_action( 'wp_enqueue_scripts', 'enqueue_image_comparison_widget_scripts' );
				
			

This code snippet serves two main purposes:

  • Register Widget: The first part of the code registers a custom Elementor widget called “Image Comparison Widget”. This is achieved through the register_image_comparison_widget function hooked into the elementor/widgets/register action. Inside this function:

It includes the file containing the widget class (image-comparison-widget.php) using require_once.

Then it registers an instance of the Elementor_Image_Comparison_Widget class using $widgets_manager->register(). This class should be defined in the included PHP file.

  • Enqueue Scripts and Styles: The second part of the code enqueues the necessary styles and scripts required for the widget to function properly. This is handled by the enqueue_image_comparison_widget_scripts function, hooked into the wp_enqueue_scripts action. Inside this function:

It enqueues a CSS file (style.css) using wp_enqueue_style. This file contains the styling specific to the custom widget.

It enqueues a JavaScript file (script.js) using wp_enqueue_script. This file contain necessary JavaScript functionalities for the widget, and it’s dependent on jQuery, as indicated by array(‘jquery’).

The last parameter of wp_enqueue_script being true indicates that the script should be loaded in the footer of the page, which is often recommended for better performance.

Elementor custom widget plugin full code

Now the plugin main file’s “image-comparison.php” complete codes are

				
					<?php
/**
 * Plugin Name: Before | After picture slider
 * Description: Slider that show before and after on a picture
 * Plugin URI:  https://standigital.lv
 * Version: 1.0
 * Author: StanDigital
 * Author URI: https://standigital.lv
 * Text Domain: image-comparison-elementor-widget
 *
 * Elementor tested up to: 3.19.3
 * Elementor Pro tested up to: 3.19.3
 */
 
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

// Register Widget
function register_image_comparison_widget( $widgets_manager ) {
    require_once( __DIR__ . '/widgets/image-comparison-widget.php' );
    $widgets_manager->register( new \Elementor_Image_Comparison_Widget() );
}
add_action( 'elementor/widgets/register', 'register_image_comparison_widget' );

// Enqueue Scripts and Styles
function enqueue_image_comparison_widget_scripts() {
    wp_enqueue_style( 'image-comparison-widget-style', plugins_url( 'style.css', __FILE__ ) );
    wp_enqueue_script( 'image-comparison-widget-script', plugins_url( 'script.js', __FILE__ ), array('jquery'), false, true );
}
add_action( 'wp_enqueue_scripts', 'enqueue_image_comparison_widget_scripts' );
				
			

Build custom Elementor widget

Let’s now create our Elementor widget.

Let’s create the folder “widgets” and then inside this, create the widget file we have included, that is “image-comparison-widget.php”.

We are creating the widget file inside the “widgets” folder because we wrote this ‘/widgets/card-widget.php‘ in the Plugin main file “image-comparison.php“.

Now start writing our widget code inside the file.

First, we will write, the very basic check for security, so no one can access the file directly.

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

Next, we will write our widget class.

				
					class Elementor_Image_Comparison_Widget extends Widget_Base {

    public function get_name() {
        return 'image-comparison-widget';
    }

    public function get_title() {
        return __( 'Image Comparison', 'image-comparison-widget' );
    }

    public function get_icon() {
        return 'eicon-image-before-after';
    }

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

  • Class Declaration: The class Elementor_Image_Comparison_Widget is defined, extending the Widget_Base class provided by Elementor. This means it inherits functionalities and properties from Widget_Base, which is essential for creating custom Elementor widgets.
  • get_name() Method: This method returns the name of the widget. In this case, it returns ‘image-comparison-widget’. This name will be used to identify the widget internally within Elementor.
  • get_title() Method: This method returns the title of the widget, which is displayed in the Elementor editor when adding new widgets. Here, it returns ‘Image Comparison’. The second parameter (‘image-comparison-widget’) is a text domain used for translation purposes.
  • get_icon() Method: This method returns the icon for the widget. The icon is displayed alongside the widget title in the Elementor editor. Here, it returns ‘eicon-image-before-after’, which is an Elementor icon representing an image before-and-after comparison. Elementor icons can be found here
  • get_categories() Method: This method returns an array of categories to which the widget belongs. Categories are used to organize widgets in the Elementor editor. Here, the widget is assigned to the ‘basic’ category. All widgets category view here.

Control function for Elementor custom widget

Okay, so, now the most interesting part, where we will start coding our widget fields.

So, we will write the protected function “register_controls()”.

				
					   protected function _register_controls() {
        $this->start_controls_section(
            'content_section',
            [
                'label' => __( 'Content', 'plugin-name' ),
                'tab' => Controls_Manager::TAB_CONTENT,
            ]
        );

        $this->add_control(
            'background_image',
            [
                'label' => __( 'Background Image', 'plugin-name' ),
                'type' => Controls_Manager::MEDIA,
                'default' => [
                    'url' => \Elementor\Utils::get_placeholder_image_src(),
                ],
            ]
        );

        $this->add_control(
            'foreground_image',
            [
                'label' => __( 'Foreground Image', 'plugin-name' ),
                'type' => Controls_Manager::MEDIA,
                'default' => [
                    'url' => \Elementor\Utils::get_placeholder_image_src(),
                ],
            ]
        );

        $this->add_control(
            'slider_position',
            [
                'label' => __( 'Slider Position', 'plugin-name' ),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [ '%' ],
                'range' => [
                    '%' => [
                        'min' => 0,
                        'max' => 100,
                        'step' => 1,
                    ],
                ],
                'default' => [
                    'unit' => '%',
                    'size' => 50,
                ],
            ]
        );

        $this->end_controls_section();
    }
				
			

On the Elementor website, you will find all the controls, like text fields, text area fields, etc. you can declare.

  • $this->start_controls_section(): This function starts a new controls section. It takes two parameters:
  • ‘content_section’: This is the ID of the section. It’s used to identify the section internally.

An array with settings for the section:

  • ‘label’: The label displayed for the section. Here, it’s set to ‘Content’.
  • ‘tab’: Specifies which tab the section belongs to. In this case, it’s set to Controls_Manager::TAB_CONTENT, which places it in the Content tab.
  • $this->add_control(): This function adds a new control (setting) to the current section. It takes two parameters:
  • ‘background_image’, ‘foreground_image’, and ‘slider_position’: These are the IDs of the controls. They’re used to identify the controls internally.

An array with settings for the control:

  • ‘label’: The label displayed for the control. It describes what the control is for.
  • ‘type’: The type of control. Here, ‘MEDIA’ and ‘SLIDER’ are used, indicating that users can select media (images) and adjust a slider, respectively.
  • ‘default’: The default value for the control. For the images, a placeholder image source is set using \Elementor\Utils::get_placeholder_image_src().

Additional settings specific to each control type, such as ‘size_units‘, ‘range‘, and ‘default‘, are provided to customize the behavior and appearance of the controls.

  • $this->end_controls_section(): This function ends the current controls section
Elementor widget content section under content tab when it is final

Elementor widget content section under content tab when it is final

Render function for custom Elementor widget

Let’s dive into crafting the code that will bring our widget to life on the front end. We’re about to create the render() function, which is responsible for generating the widget’s visual output on the front end of your website.

				
					protected function render() {
        $settings = $this->get_settings_for_display();
        ?>
        <div class="acontainer">
            <div id="comparison">
                <figure data-bg="" class="rocket-lazyload" style=" ?>');">
                    <div id="handle"></div>
                    <div data-bg="" class="rocket-lazyload" id="divisor" style=" ?>');"></div>
                </figure>
                <input type="range" min="0" max="100" value="<?php echo esc_attr($settings['slider_position']['size']); ?>" id="slider" oninput="moveDivisor()">
            </div>
        </div>
        <?php
    }

    protected function _content_template() {
        ?>
        <#
        var bgImage = settings.background_image.url;
        var fgImage = settings.foreground_image.url;
        var sliderPos = settings.slider_position.size;
        #>
        <div class="acontainer">
            <div id="comparison">
                <figure data-bg="http://%20bgImage%20" class="rocket-lazyload" style="">
                    <div id="handle"></div>
                    <div data-bg="http://%20fgImage%20" class="rocket-lazyload" id="divisor" style=""></div>
                </figure>
                <input type="range" min="0" max="100" value="{{ sliderPos }}" id="slider" oninput="moveDivisor()">
            </div>
        </div>
        <?php
    }
}
				
			
  1. render() Function:
  • This function is responsible for generating the output of the widget on the front end.
  • It starts by retrieving the settings configured by the user in the Elementor editor using $this->get_settings_for_display().
  • Then, it outputs the HTML markup for the widget using PHP echo statements.
  • Inside the HTML markup:
    • A container <div> with the class acontainer is created.
    • Inside this container, there’s another <div> with the id comparison.
    • Within the comparison <div>, a <figure> element is used to display the background image.
    • Inside the <figure>, two <div> elements are added:
      • One with the id handle, which represents the slider handle.
      • Another with the id divisor, representing the foreground image.
    • Additionally, an <input> element of type range is included to allow users to adjust the slider position.
    • Inline styles are used to set the background images for the figure and divisor <div>s based on the user-configured settings.
  1. _content_template() Function:
  • This function defines the content template for the widget in the Elementor editor.
  • It’s written in a mix of JavaScript (using Underscore.js templating) and PHP.
  • Inside the template:
    • JavaScript variables (bgImage, fgImage, sliderPos) are assigned values from the widget settings.
    • These variables are then used within the HTML markup to dynamically generate the widget preview in the Elementor editor.
    • Note that the values from the settings are accessed using settings.property_name.
				
					<?php
use Elementor\Widget_Base;
use Elementor\Controls_Manager;

class Elementor_Image_Comparison_Widget extends Widget_Base {

    public function get_name() {
        return 'image-comparison-widget';
    }

    public function get_title() {
        return __( 'Image Comparison', 'image-comparison-widget' );
    }

    public function get_icon() {
        return 'eicon-image-before-after';
    }

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

    protected function _register_controls() {
        $this->start_controls_section(
            'content_section',
            [
                'label' => __( 'Content', 'plugin-name' ),
                'tab' => Controls_Manager::TAB_CONTENT,
            ]
        );

        $this->add_control(
            'background_image',
            [
                'label' => __( 'Background Image', 'plugin-name' ),
                'type' => Controls_Manager::MEDIA,
                'default' => [
                    'url' => \Elementor\Utils::get_placeholder_image_src(),
                ],
            ]
        );

        $this->add_control(
            'foreground_image',
            [
                'label' => __( 'Foreground Image', 'plugin-name' ),
                'type' => Controls_Manager::MEDIA,
                'default' => [
                    'url' => \Elementor\Utils::get_placeholder_image_src(),
                ],
            ]
        );

        $this->add_control(
            'slider_position',
            [
                'label' => __( 'Slider Position', 'plugin-name' ),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [ '%' ],
                'range' => [
                    '%' => [
                        'min' => 0,
                        'max' => 100,
                        'step' => 1,
                    ],
                ],
                'default' => [
                    'unit' => '%',
                    'size' => 50,
                ],
            ]
        );

        $this->end_controls_section();
    }

    protected function render() {
        $settings = $this->get_settings_for_display();
        ?>
        <div class="acontainer">
            <div id="comparison">
                <figure data-bg="" class="rocket-lazyload" style=" ?>');">
                    <div id="handle"></div>
                    <div data-bg="" class="rocket-lazyload" id="divisor" style=" ?>');"></div>
                </figure>
                <input type="range" min="0" max="100" value="<?php echo esc_attr($settings['slider_position']['size']); ?>" id="slider" oninput="moveDivisor()">
            </div>
        </div>
        <?php
    }

    protected function _content_template() {
        ?>
        <#
        var bgImage = settings.background_image.url;
        var fgImage = settings.foreground_image.url;
        var sliderPos = settings.slider_position.size;
        #>
        <div class="acontainer">
            <div id="comparison">
                <figure data-bg="http://%20bgImage%20" class="rocket-lazyload" style="">
                    <div id="handle"></div>
                    <div data-bg="http://%20fgImage%20" class="rocket-lazyload" id="divisor" style=""></div>
                </figure>
                <input type="range" min="0" max="100" value="{{ sliderPos }}" id="slider" oninput="moveDivisor()">
            </div>
        </div>
        <?php
    }
}
				
			

Create CSS style.css in main plugin folder

Now lets create style.css in the main plugin folder. This file will hold all the essential styles for our Image Comprasion widget

				
					.acontainer {
  max-width: 800px;
}

#comparison {
  width: 100%;
  padding-bottom: 100%;
  overflow: hidden;
  position: relative;
}

figure {
  position: absolute;
  background-size: cover;
  font-size: 0;
  width: 100%;
  height: 100%;
  margin: 0;
}

#divisor {
  background-size: cover;
  position: absolute;
  width: 50%;
  box-shadow: 0 5px 10px -2px rgba(0, 0, 0, 0.3);
  bottom: 0;
  height: 100%;

 &::before,
  &::after {
    content: "";
    position: absolute;
    right: -2px;
    width: 4px;
    height: calc(50% - 25px);
    background: white;
    z-index: 3;
  }
  &::before {
    top: 0;
    box-shadow: 0 -3px 8px 1px rgba(0, 0, 0, 0.3);
  }
  &::after {
    bottom: 0;
    box-shadow: 0 3px 8px 1px rgba(0, 0, 0, 0.3);
  }
}
#handle {
  position: absolute;
  height: 50px;
  width: 50px;
  top: 50%;
  left: 50%;
  transform: translateY(-50%) translateX(-50%);
  z-index: 1;

 &::before,
  &::after {
    content: "";
    width: 0;
    height: 0;
    border: 6px inset transparent;
    position: absolute;
    top: 50%;
    margin-top: -6px;
  }
  &::before {
    border-right: 6px solid white;
    left: 50%;
    margin-left: -17px;
  }
  &::after {
    border-left: 6px solid white;
    right: 50%;
    margin-right: -17px;
  }
}
input[type="range"] {
  -webkit-appearance: none;
  -moz-appearance: none;
  position: absolute;
  top: 50%;
  left: -25px;
  transform: translateY(-50%);
  background-color: transparent;
  width: calc(100% + 50px);
  z-index: 2;
&:focus,
  &:active {
    border: none;
    outline: none;
  }
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  border: none;
  height: 50px;
  width: 50px;
  border-radius: 50%;
  background: transparent;
  border: 4px solid white;
  box-shadow: 0 0 8px 1px rgba(0, 0, 0, 0.3);
}

input[type="range"]::-moz-range-track {
  -moz-appearance: none;
  height: 15px;
  width: 100%;
  background-color: transparent;
  position: relative;
  outline: none;
}
				
			

Create script.js in main plugin folder

Its time to add last part of our code. For widget to run we need to insert JavaScript code, so when the user drag our slider it changes image. The file should be created in the main plugin folder.

				
					document.addEventListener('DOMContentLoaded', function() {
    var divisor = document.getElementById("divisor"),
        handle = document.getElementById("handle"),
        slider = document.getElementById("slider");

    function moveDivisor() {
        handle.style.left = slider.value + "%";
        divisor.style.width = slider.value + "%";
    }

    slider.addEventListener('input', moveDivisor);
    moveDivisor();
});
				
			

Final output. After | Before Image comparison slider

Download Image Comparsion widget for Elementor

Download our Image Comparison plugin for Elementor now and elevate your website’s visual appeal! With this powerful tool, you can effortlessly create stunning before-and-after image comparisons to captivate your audience. Enhance user engagement and showcase your work like never before. Get started today and unleash the full potential of your Elementor-powered website!

Read More

Scroll to Top