Elementor is a great Page Builder for WordPress sites. It is really developer friendly and that is why I have decided to give it a try and use it for a client of mine. In this tutorial, I will show you how to add a custom button field and a skin.

While I am refactoring the whole theme and I am using Elementor to replicate hard-coded elements, I am learning a lot. I will also see to write more on this topic so you can learn how to extend Elementor.

Let’s get started. Open the file where you will add the code. That can be in your plugin or theme (I would recommend to put it in a plugin).

Adding a new Button Field in Elementor

To add a new field, I will hook my own function to an action in Elementor. Elementor fields are placed in sections. You can see almost in all elements (widgets) there is a layout or content section, then a style section and maybe an advanced section.

This is the hook name:

'elementor/element/' . $this->get_name() . '/' . $section_id . '/after_section_start'

If we are to target our Button element and a Style section, we will need to hook our function here:

'elementor/element/button/section_style/after_section_start'

When hooking to that location, we are placing our field at the beginning. If you want to place your field at the end of the section, you can use the suffix before_section_end. Let’s now add this code:

The action hooks mentioned before, are passing the current object ($thisand arguments of that section. To add a new field, we will use the method add_control and pass the parameters to define our field.

When defining a field type, you will need to call that from the Elementor namespacephp.net. If you’re not familiar with namespaces, you can read about them on php.net. The values of our dropdown will be used as new classes.

Rendering the Field value

To manipulate the rendering of Elementor elements such as widgets, you can use two general hooks:

  • elementor/widget/before_render_content – Action hook before the rendering started
  • elementor/widget/render_content – Filter hook to change the rendered HTML

If elements have other hooks or filters within their rendering methods, you can also use those. For our example, we are adding a class, so we will just use the action hook before the rendering started. Within that hook we will use a method add_render_attribute which will queue our attribute until the button rendering starts.

The first thing we do here is to check if the element which is passed is a button. That is done by using the method get_name(). If the current element is not a button, we won’t do anything.

If it is a button, then we will get the settings, check the custom field value and then add it as a class attribute to button. We need to pass button because the whole button is wrapped around an elementor wrapper. If we want to add that attribute to the wrapper instead, we would put wrapper instead of button.

When rendering, Elementor will check all the attribute values passed to the button and class and add those values as classes.

Now, if you have a style defined for the selected class, your button output will change. But, your button style won’t change as you change that value. 

That is because the button has a print template defined which is a JavaScript Backbone.js template that is used to perform live updates on the element.

How to do that? We will learn that as we learn how to add a new Skin. You don’t have to use a Skin for that, but I’ll explain it there so I don’t repeat myself.

Adding a Custom Elementor Skin

To add a skin, we will need to use the abstract class Skin_Base which is also under the namespace Elementor, so we will have to use a full path Elementor\Skin_Base. To register a skin for an element, we need to use the hook:

elementor/widget/' . $this->get_name() . '/skins_init

Since we are talking about a Button element, we will use:

elementor/widget/button/skins_init

Let’s do that now:

Simple as that. But, it won’t work. We don’t have the class Custom_Button_Skin defined. We need to define that classs before that hook. Otherwise it won’t find that class definition.

But, we can’t just define that class in our file. What if Elementor is deactivated? Our code will break. We will define that class once Elementor has been initialized. It might seem like a big one, but bear with me.

The part that we actually need to understand is the render() method. Inside that method, we are making almost an exact copy of the button element. But with a big difference.

The difference happens when adding attributes. Since Skin is just an overlay of our Button, we don’t have such methods there. But we do have a class attribute $parent which references our Button. That’s why we are using $this->parent->add_render_attribute(). The method render_text() is not required. That is just a helper method used inside the Button element so I have just copied it out and changed $this->add_render_attribute() to $this->parent->add_render_attribute().

Now, within the render() method, I have full control of the output. On line 42, I am defining a $button_type. If that variable has a value of no then I won’t add it as a class.

And I have also made another change (on line 55) and that is removing the Elementor size class if we have our own custom button type. That’s how I am removing any styles inherited by the Elementor size class.

Changing the Live Preview Template

Both of the scenarios above will work, but only if we refresh the page. We won’t see those changes appear as we change them. That is done through a method print_template() which is not available through Skins. So we can’t change them just by defining the method print_template() inside our Skins. That is why, you can easily change the live preview templates without Skins (they are not required).

But, let’s now add that option in our Skin. In our __construct() method, we will add a filter and we will also define a new method.

As you might have read, if we just return an empty string, Elementor will use our render() method instead and do a page reload on each change. But let’s be a bit more advanced and learn about Backbone.js templating :).

Again, since this is a generic filter and not a filter where we could just target our button, we need to change if the current element is the Button element. Let’s now define our _content_template() method!

Our method is just a copy of the method inside the Button element with a simple adjustment. Everything remains the same except the classes. I will break the change in lines so it’s easier to read.

<# if( 'no' === settings.custom_button_type ) { #>
 elementor-size-{{ settings.size }}
<# } else { #>
 {{ settings.custom_button_type }}
<# } #>

So, what are we doing here? You can feel about the <# and #> as PHP tags <?php and ?>. We are opening them so we can type JavaScript inside of them. We are then checking if the value of our field is no. If it is, then we are just using the default sizing class from Elementor. If it’s something else, we are putting that as a class. The parentheses {{ and }} are the same as saying echo in PHP. If you have HTML tags inside of your variable, then you should use {{{ and }}}.

Conclusion

Elementor is a great page builder and with so many actions and filters, you can really do a lot of them. The next step which I would like to teach you about is how to create your own custom elements in Elementor.

We could have escaped the custom rendering method and so on if we could also have a way to remove such attributes. Maybe the folks from Elementor, if they read this, will consider adding that 😀

Have you tried building custom elements in Elementor or extending it in any way? Please share in the comments below so I can also learn even more;)

Posted by Igor Benic

Web Developer who mainly uses WordPress for projects. Working on various project through Codeable & Toptal. Author of several ebooks at https://leanpub.com/u/igorbenic.

Leave a reply

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