Un widget personnalisé pour Elementor

Connaissez-vous le constructeur de page Elementor ?

 

Si non, testez-le vite, il vaut le détour. Je ne vais pas faire ici une présentation détaillée de cet outil, ça a déjà été fait par GeekPress, et bien d’autres.

En bref, Elementor vous permet de construire des pages, avec des sections, des colonnes, et des widgets – tous les « éléments » sont des widgets.

J’avoue que j’ai un peu du mal à me faire à son interface « full front-end », mais mis à part cela le rendu est vraiment bon, et contrairement à certains de ses concurrents, Elementor rend un code plutôt propre, et surtout, il est orienté développeurs.

En effet, je vous invite à parcourir le code qui est très lisible, bien commenté, on se l’approprie facilement, et bien sûr on l’étend !

C’est l’objet de cet article : créer un widget personnalisé pour Elementor afin d’étendre ses fonctionnalités.

Les possibilités sont infinies, on peut faire ce que l’on veut avec un widget, et d’ailleurs il en existe déjà beaucoup dans la version gratuite, et encore plus dans la version payante du constructeur de page.

 

Dans la pratique… un bouton fixe

 

Pour cet article j’ai créé un widget bouton « fixe » : il reprend toutes les fonctionnalités du bouton natif proposé par Elementor, sauf qu’en plus il peut être fixé à droite ou à gauche de l’écran, et restera toujours visible au défilement. Ce sera utile pour un bouton d’appel d’action par exemple.

Ils sont sympas chez Elementor, ils ont créé un « starter plugin », que vous pouvez trouver ici. On peut ainsi comprendre facilement que notre architecture de fichiers dans notre extension se composera ainsi :

 

/elementor-button-fixed
 /assets // tous nos CSS et JS
 /widgets // le dossier contenant notre widget
    - button-fixed.php // la classe du widget
 - elementor-button-fixed.php // chargement du plugin
 - plugin.php // la classe principale

(Gardez en tête que la grande majorité des fonctions utilisées ci-dessous, dans les extraits de codes, sont natives à Elementor, pour plus de détails sur celles-ci je vous invite à faire quelques recherches dans son code source).

Commençons par le fichier elementor-button-fixed.php qui charge l’extension :

<?php

/**
 * Plugin Name: Elementor Button Fixed
 * Description: Fixed button for Elementor page builder
 * Plugin URI: https://github.com/MarieComet/Elementor-Button-Fixed/
 * Version: 0.0.1
 * Author: Marie Comet
 * Author URI: https://mariecomet.fr
 * Text Domain: elementor-button-fixed
 */

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

define( 'ELEMENTOR_MC_CUSTOM__FILE__', __FILE__ );

/**
 * Load Hello World
 *
 * Load the plugin after Elementor (and other plugins) are loaded.
 *
 * @since 1.0.0
 */
function mc_custom_widgets_load() {
    // Load localization file
    load_plugin_textdomain( 'mc-custom-widgets' );

    // Notice if the Elementor is not active
    if ( ! did_action( 'elementor/loaded' ) ) {
        add_action( 'admin_notices', 'mc_custom_widgets_fail_load' );
        return;
    }

    // Check version required
    $elementor_version_required = '1.0.0';
    if ( ! version_compare( ELEMENTOR_VERSION, $elementor_version_required, '>=' ) ) {
        add_action( 'admin_notices', 'mc_custom_widgets_fail_load_out_of_date' );
        return;
    }

    // Require the main plugin file
    require( __DIR__ . '/plugin.php' );
}
add_action( 'plugins_loaded', 'mc_custom_widgets_load' );

Rien de particulier à signaler ici, on déclare notre extension via l’entête, on fait quelques vérifications sur la présence d’Elementor et sa version, notez qu’en ligne 42 on charge le fichier plugin.php, le tout hooké sur `plugins_loaded`.

 


 

Passons au fichier suivant : plugin.php dans lequel on va déclarer notre classe principale et appeler notre classe propre de notre widget :

<?php
namespace MCCustomWidget;

use MCCustomWidget\Widgets\MC_Button_Fixed;

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

/**
 * Main Plugin Class
 *
 * Register new elementor widget.
 *
 * @since 1.0.0
 */
class Plugin {

    /**
     * Constructor
     *
     * @since 1.0.0
     *
     * @access public
     */
    public function __construct() {
        $this->add_actions();
    }

    /**
     * Add Actions
     *
     * @since 1.0.0
     *
     * @access private
     */
    private function add_actions() {
        add_action( 'elementor/widgets/widgets_registered', [ $this, 'on_widgets_registered' ] );

        add_action( 'elementor/frontend/after_register_styles', function() {
            wp_register_style( 'button-fixed-css', plugins_url( '/assets/css/button-fixed-css.css', ELEMENTOR_MC_CUSTOM__FILE__ ) );
        } );

        add_action( 'elementor/frontend/after_enqueue_styles', function() {
            wp_enqueue_style( 'button-fixed-css' );
        } );
    }

    /**
     * On Widgets Registered
     *
     * @since 1.0.0
     *
     * @access public
     */
    public function on_widgets_registered() {
        $this->includes();
        $this->register_widget();
    }

    /**
     * Includes
     *
     * @since 1.0.0
     *
     * @access private
     */
    private function includes() {
        require __DIR__ . '/widgets/button-fixed.php';
    }

    /**
     * Register Widget
     *
     * @since 1.0.0
     *
     * @access private
     */
    private function register_widget() {
        \Elementor\Plugin::instance()->widgets_manager->register_widget_type( new MC_Button_Fixed() );
    }
}

new Plugin();

Vous remarquerez que j’utilise des espaces de noms (lignes 2 et 4), si besoin vous pouvez lire cet excellent tuto sur Open Class Room.

Décortiquons la classe Plugin :

  • – La fonction add_actions sert à charger notre fichier CSS, qui selon votre projet ne sera pas indispensable. Cette fonction est appelée dans la fonction __construct.

– La fonction includes, comme son nom l’indique, inclue le fichier de notre widget : /widgets/button-fixed.php

  • – La fonction register_widget indique à Elementor qu’il doit ajouter notre widget aux siens.
  • – Ces deux dernières fonctions sont lancées dans la fonction on_widgets_registered qui elle même est hookée sur elementor/widgets/widgets_registered.

 

Maintenant que nous avons indiqué à Elementor qu’on a un nouveau widget pour lui, il faut le créer, passons au fichier /widgets/button-fixed.php :

<?php
namespace MCCustomWidget\Widgets;

use Elementor\Widget_Base;
use Elementor\Controls_Manager;
use Elementor\Group_Control_Typography;
use Elementor\Scheme_Typography;
use Elementor\Scheme_Color;
use Elementor\Group_Control_Border;
use Elementor\Group_Control_Box_Shadow;


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

/**
 * Elementor Button fixed
 *
 * Elementor widget for fixed button.
 *
 * @since 1.0.0
 */
class MC_Button_Fixed extends Widget_Base {

    /**
     * Retrieve button widget name.
     *
     * @access public
     *
     * @return string Widget name.
     */
    public function get_name() {
        return 'button-fixed';
    }

    /**
     * Retrieve button widget title.
     *
     * @access public
     *
     * @return string Widget title.
     */
    public function get_title() {
        return __( 'Button Fixed', 'elementor' );
    }

    /**
     * Retrieve button widget icon.
     *
     * @access public
     *
     * @return string Widget icon.
     */
    public function get_icon() {
        return 'eicon-button';
    }

Tout d’abord remarquez la déclaration de mon espace de nom, et également l’appel aux espaces de noms d’Elementor (use). Ils sont importants car j’indique que je vais les utiliser, sans cela nous aurions des erreurs fatales.

En ligne 22 nous lançons notre classe qui étend la classe Widget_Base (elementor/includes/base/widget-base.php).

En ligne 31 la fonction get_name sert à enregistrer notre « identifiant » de widget.

En ligne 42 la fonction get_title sert à enregistrer notre « titre » de widget, c’est celui qui sera visible en back-office.

En ligne 53 la fonction get_icon sert à indiquer quel icône nous souhaitons utiliser pour notre widget.

Plus complexe, la fonction _register_controls sert à déclarer toutes les sections, paramètres et options que nous souhaitons rendre disponibles pour notre widget :

    protected function _register_controls() {
        $this->start_controls_section(
            'section_button',
            [
                'label' => __( 'Button Fixed', 'elementor' ),
            ]
        );

        $this->add_control(
            'button_type',
            [
                'label' => __( 'Type', 'elementor' ),
                'type' => Controls_Manager::SELECT,
                'default' => '',
                'options' => [
                    '' => __( 'Default', 'elementor' ),
                    'info' => __( 'Info', 'elementor' ),
                    'success' => __( 'Success', 'elementor' ),
                    'warning' => __( 'Warning', 'elementor' ),
                    'danger' => __( 'Danger', 'elementor' ),
                ],
                'prefix_class' => 'elementor-button-',
            ]
        );

        $this->add_control(
            'text',
            [
                'label' => __( 'Text', 'elementor' ),
                'type' => Controls_Manager::TEXT,
                'default' => __( 'Click me', 'elementor' ),
                'placeholder' => __( 'Click me', 'elementor' ),
            ]
        );

        $this->add_control(
            'link',
            [
                'label' => __( 'Link', 'elementor' ),
                'type' => Controls_Manager::URL,
                'placeholder' => 'http://your-link.com',
                'default' => [
                    'url' => '#',
                ],
            ]
        );

        $this->add_responsive_control(
            'align_fixed',
            [
                'label' => __( 'Alignment', 'elementor' ),
                'type' => Controls_Manager::CHOOSE,
                'options' => [
                    'left_fixed'    => [
                        'title' => __( 'Left', 'elementor' ),
                        'icon' => 'fa fa-align-left',
                    ],
                    'right_fixed' => [
                        'title' => __( 'Right', 'elementor' ),
                        'icon' => 'fa fa-align-right',
                    ],
                ],
                'prefix_class' => 'elementor%s-align-fixed',
                'default' => 'left_fixed',
            ]
        );

Plusieurs fonctions nous seront utiles :

  • start_controls_section ouvre une nouvelle section (ce sont les onglets en haut dans le panneau d’Elementor lorsqu’on édite un widget)
  • add_control créé un nouveau contrôle, c’est à dire une option, par exemple en ligne 90 un sélecteur qui permet de choisir le type de notre bouton. Je vous invite à parcourir les widgets natifs d’Elementor pour tous les découvrir.
  • add_responsive_control fait la même chose que add_control, avec une gestion du responsive en plus. En ligne 129 je défini que je veux un choix « droite » ou « gauche » pour l’alignement de mon bouton.
  • – end_controls_section sert à fermer la section que l’on a ouverte.

 

Pour le rendu en back-office, lors de l’édition d’une page, c’est la fonction _content_template qui se charge de l’affichage, et on utilise une variable JavaScript ‘settings‘ :

    protected function _content_template() {
        ?>
        <div class="elementor-button-wrapper button-fixed-wrapper {{ settings.align_fixed }}">
            <a class="elementor-button elementor-size-{{ settings.size }} elementor-animation-{{ settings.hover_animation }}" href="{{ settings.link.url }}">
                <span class="elementor-button-content-wrapper">
                    <# if ( settings.icon ) { #>
                    <span class="elementor-button-icon elementor-align-icon-{{ settings.icon_align }}">
                        <i class="{{ settings.icon }}"></i>
                    </span>
                    <# } #>
                    <span class="elementor-button-text">{{{ settings.text }}}</span>
                </span>
            </a>
        </div>
        <?php
    }

 


 

Nous avons donc définis les paramètres qui seront rendus en administration, place à la partie front-office, toujours dans le même fichier :

    protected function render() {
        $settings = $this->get_settings();

        $this->add_render_attribute( 'wrapper', 'class', 'elementor-button-wrapper '.  $settings['align_fixed']);

        if ( ! empty( $settings['link']['url'] ) ) {
            $this->add_render_attribute( 'button', 'href', $settings['link']['url'] );
            $this->add_render_attribute( 'button', 'class', 'elementor-button-link' );

            if ( $settings['link']['is_external'] ) {
                $this->add_render_attribute( 'button', 'target', '_blank' );
            }

            if ( $settings['link']['nofollow'] ) {
                $this->add_render_attribute( 'button', 'rel', 'nofollow' );
            }
        }

        $this->add_render_attribute( 'button', 'class', 'elementor-button' );

        if ( ! empty( $settings['size'] ) ) {
            $this->add_render_attribute( 'button', 'class', 'elementor-size-' . $settings['size'] );
        }

        if ( $settings['hover_animation'] ) {
            $this->add_render_attribute( 'button', 'class', 'elementor-animation-' . $settings['hover_animation'] );
        }

        if ( $settings['align_fixed'] ) {
            $this->add_render_attribute( 'button', 'class', 'elementor-fixed-pos-' . $settings['align_fixed'] );
        }

        ?>
        <div <?php echo $this->get_render_attribute_string( 'wrapper' ); ?>>
            <a <?php echo $this->get_render_attribute_string( 'button' ); ?>>
                <?php $this->render_text(); ?>
            </a>
        </div>
        <?php
    }

La fonction render contrôle l’affichage du « markup » (html) de notre widget en front-office :

  • get_settings sert à récupérer tous nos paramètres précédemment déclarés dans l’administration.
  • add_render_attribute ajoute une valeur à un attribut de l’élément : le premier paramètre est l’élément à cibler, le deuxième son attribut (class, ID, etc), le troisième la valeur à ajouter.
  • get_render_attributes sert à récupérer la valeur d’un attribut, elle prend en paramètre le nom de cet attribut.
  • render_text est l’appel à la fonction qui affiche le contenu (ligne 452), je ne la détaillerai pas ici car le fonctionnement est sensiblement le même que render.

 

Voilà ! Vous pouvez retrouver l’extension sur mon compte Github.

Bouton fixé
Bouton fixé dans le constructeur de page

 

Vous êtes maintenant prêt à créer vos widgets personnalisés directement dans Elementor.

 

Crédit photo : pixel2013 / Pixabay

Vous avez des questions ?
Contactez-moi :
Me contacter

4 thoughts on “Un widget personnalisé pour Elementor

  1. Bonjour,

    article très intéressant.
    Peut-être pouvez-vous m’aider en tant que pro d’elementor.

    Est-il possible d’ajouter un method= »POST » dans les formulaires générés par elementor (pro)

    Merci
    Jeanson

    1. Bonjour Jeanson,
      Désolée mais je ne sais pas si c’est possible.
      Vous pouvez poser la question au support d’Elementor, ils auront surement la réponse.

      1. Bonjour Marie,

        merci pour votre réponse.
        En fait, je me suis rendu compte que le form est déjà en method POST. Du coup, ma question est caduque.
        Cependant, je ne comprends pas pourquoi lorsque je fais un traitement_formulaire avec add_action(‘template_redirect’, ‘traitement_formulaire’); et que je fais un print_r($_POST) ; j’ai un Array() vide.
        Si jamais vous avez une idée…

        Jeanson

        1. Bonjour Jeanson,
          Ce retour vide peut être causé par énormément de facteurs, c’est difficile de vous aider avec seulement ces informations.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nom *

8e3aa2a16040f963ae8ee29c0b6847a3mmmmmmmmmm