{"id":166544,"date":"2025-07-14T09:00:00","date_gmt":"2025-07-14T07:00:00","guid":{"rendered":"https:\/\/gtechgroup.it\/blog\/creare-widget-personalizzati-elementor-guida-sviluppatori\/"},"modified":"2026-05-25T10:00:00","modified_gmt":"2026-05-25T08:00:00","slug":"creare-widget-personalizzati-elementor-guida-sviluppatori","status":"publish","type":"post","link":"https:\/\/gtechgroup.it\/blog\/creare-widget-personalizzati-elementor-guida-sviluppatori\/","title":{"rendered":"Creare Widget Personalizzati per Elementor: Guida Sviluppatori"},"content":{"rendered":"<h2>Creare Widget Personalizzati per Elementor: Guida Sviluppatori<\/h2>\n<p>Elementor offre decine di widget predefiniti, ma in alcuni casi le esigenze specifiche di un progetto richiedono funzionalita che nessun widget standard puo fornire. In questi casi, la soluzione e <strong>creare un widget personalizzato<\/strong>. Elementor mette a disposizione una API solida e ben documentata che permette agli sviluppatori PHP di estendere il page builder con widget su misura, perfettamente integrati nel pannello di controllo visuale.<\/p>\n<p>Questa guida e rivolta a sviluppatori con conoscenze di <strong>PHP, HTML e CSS<\/strong>. Se non sei uno sviluppatore ma hai bisogno di widget personalizzati per il tuo progetto, il nostro team di <a href=\"https:\/\/gtechgroup.it\/realizzazione-siti-web\/\">realizzazione siti web<\/a> puo creare soluzioni su misura per le tue esigenze.<\/p>\n<h2>Architettura dei Widget di Elementor<\/h2>\n<p>Ogni widget di Elementor e una <strong>classe PHP<\/strong> che estende la classe base <code>Widget_Base<\/code>. La struttura segue un pattern chiaro e prevedibile:<\/p>\n<ul>\n<li><strong>Metadati del widget<\/strong>: nome, titolo, icona, categoria<\/li>\n<li><strong>Controlli<\/strong>: i campi di configurazione che appaiono nel pannello laterale (testo, colore, tipografia, immagine, ecc.)<\/li>\n<li><strong>Rendering<\/strong>: la funzione che genera il codice HTML visibile nel frontend<\/li>\n<li><strong>Template di anteprima<\/strong>: il JavaScript che genera la anteprima in tempo reale nel builder (opzionale)<\/li>\n<\/ul>\n<h3>File System<\/h3>\n<p>La struttura consigliata per un plugin che contiene widget personalizzati:<\/p>\n<pre><code>my-elementor-widgets\/\n\u251c\u2500\u2500 my-elementor-widgets.php       (file principale del plugin)\n\u251c\u2500\u2500 widgets\/\n\u2502   \u251c\u2500\u2500 cta-box.php                (widget CTA Box)\n\u2502   \u251c\u2500\u2500 team-member.php            (widget Team Member)\n\u2502   \u2514\u2500\u2500 pricing-table.php          (widget Pricing Table)\n\u251c\u2500\u2500 assets\/\n\u2502   \u251c\u2500\u2500 css\/\n\u2502   \u2502   \u2514\u2500\u2500 widgets.css            (stili dei widget)\n\u2502   \u2514\u2500\u2500 js\/\n\u2502       \u2514\u2500\u2500 widgets.js             (script dei widget)\n\u2514\u2500\u2500 readme.txt<\/code><\/pre>\n<h2>Registrare il Plugin e i Widget<\/h2>\n<p>Il file principale del plugin deve registrare i widget con Elementor attraverso il hook appropriato:<\/p>\n<pre><code>&lt;?php\n\/**\n * Plugin Name: My Elementor Widgets\n * Description: Widget personalizzati per Elementor\n * Version: 1.0.0\n * Requires PHP: 7.4\n *\/\n\nif ( ! defined( 'ABSPATH' ) ) exit;\n\nfunction register_custom_widgets( $widgets_manager ) {\n    require_once __DIR__ . '\/widgets\/cta-box.php';\n    $widgets_manager-&gt;register( new CTA_Box_Widget() );\n}\nadd_action( 'elementor\/widgets\/register', 'register_custom_widgets' );<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/gtechgroup.it\/blog\/wp-content\/uploads\/2026\/05\/editor-widgets.png\" alt=\"Pannello widget di Elementor che mostra i widget personalizzati nella categoria dedicata\" \/><\/p>\n<h2>La Classe Widget_Base: Metodi Fondamentali<\/h2>\n<p>Ogni widget personalizzato deve implementare almeno questi metodi:<\/p>\n<h3>get_name()<\/h3>\n<p>Restituisce il <strong>nome tecnico<\/strong> del widget (slug unico, senza spazi, in minuscolo). Questo identificativo viene usato internamente da Elementor:<\/p>\n<pre><code>public function get_name() {\n    return 'cta_box';\n}<\/code><\/pre>\n<h3>get_title()<\/h3>\n<p>Restituisce il <strong>titolo leggibile<\/strong> del widget come appare nel pannello:<\/p>\n<pre><code>public function get_title() {\n    return 'CTA Box Personalizzato';\n}<\/code><\/pre>\n<h3>get_icon()<\/h3>\n<p>Restituisce la <strong>classe della icona<\/strong> visualizzata nel pannello widget. Puoi usare qualsiasi classe Eicons (il set di icone di Elementor) o Font Awesome:<\/p>\n<pre><code>public function get_icon() {\n    return 'eicon-call-to-action';\n}<\/code><\/pre>\n<h3>get_categories()<\/h3>\n<p>Definisce in quale <strong>categoria<\/strong> del pannello appare il widget. Puoi usare categorie esistenti o crearne di personalizzate:<\/p>\n<pre><code>public function get_categories() {\n    return [ 'general' ];\n}<\/code><\/pre>\n<p>Categorie predefinite disponibili: <code>basic<\/code>, <code>pro-elements<\/code>, <code>general<\/code>, <code>theme-elements<\/code>, <code>woocommerce-elements<\/code>.<\/p>\n<h2>register_controls(): Creare i Campi di Configurazione<\/h2>\n<p>Il metodo <code>register_controls()<\/code> definisce tutti i campi che appaiono nel pannello laterale quando il widget viene selezionato. Elementor offre decine di tipi di controllo:<\/p>\n<h3>Controlli di Base<\/h3>\n<ul>\n<li><strong>TEXT<\/strong>: campo di testo singola riga<\/li>\n<li><strong>TEXTAREA<\/strong>: area di testo multiriga<\/li>\n<li><strong>WYSIWYG<\/strong>: editor visuale completo (TinyMCE)<\/li>\n<li><strong>NUMBER<\/strong>: campo numerico con min\/max\/step<\/li>\n<li><strong>URL<\/strong>: campo URL con opzioni per target e nofollow<\/li>\n<li><strong>SWITCHER<\/strong>: toggle on\/off<\/li>\n<li><strong>SELECT<\/strong>: menu a discesa con opzioni predefinite<\/li>\n<li><strong>SELECT2<\/strong>: menu a discesa con ricerca e selezione multipla<\/li>\n<\/ul>\n<h3>Controlli di Stile<\/h3>\n<ul>\n<li><strong>COLOR<\/strong>: selettore colore con supporto per i Global Colors<\/li>\n<li><strong>SLIDER<\/strong>: cursore numerico con unita di misura (px, em, %, vw)<\/li>\n<li><strong>DIMENSIONS<\/strong>: quattro campi collegati per padding\/margin\/border-radius<\/li>\n<li><strong>TYPOGRAPHY<\/strong>: controllo completo della tipografia (font family, size, weight, transform, line-height, letter-spacing)<\/li>\n<li><strong>TEXT_SHADOW<\/strong>: ombra del testo<\/li>\n<li><strong>BOX_SHADOW<\/strong>: ombra del box<\/li>\n<li><strong>BORDER<\/strong>: tipo, larghezza e colore del bordo<\/li>\n<li><strong>BACKGROUND<\/strong>: sfondo classico o gradiente<\/li>\n<\/ul>\n<h3>Controlli Media<\/h3>\n<ul>\n<li><strong>MEDIA<\/strong>: selettore immagine dalla libreria media<\/li>\n<li><strong>GALLERY<\/strong>: selettore galleria di immagini<\/li>\n<li><strong>ICONS<\/strong>: selettore icona (Font Awesome, Eicons, SVG)<\/li>\n<\/ul>\n<h3>Esempio Completo di register_controls()<\/h3>\n<pre><code>protected function register_controls() {\n    \/\/ SEZIONE CONTENUTO\n    $this-&gt;start_controls_section(\n        'content_section',\n        [\n            'label' =&gt; 'Contenuto',\n            'tab'   =&gt; ElementorControls_Manager::TAB_CONTENT,\n        ]\n    );\n\n    $this-&gt;add_control(\n        'title',\n        [\n            'label'       =&gt; 'Titolo',\n            'type'        =&gt; ElementorControls_Manager::TEXT,\n            'default'     =&gt; 'Titolo CTA',\n            'placeholder' =&gt; 'Inserisci il titolo',\n        ]\n    );\n\n    $this-&gt;add_control(\n        'description',\n        [\n            'label'   =&gt; 'Descrizione',\n            'type'    =&gt; ElementorControls_Manager::TEXTAREA,\n            'default' =&gt; 'Descrizione della call to action.',\n            'rows'    =&gt; 5,\n        ]\n    );\n\n    $this-&gt;add_control(\n        'button_text',\n        [\n            'label'   =&gt; 'Testo Pulsante',\n            'type'    =&gt; ElementorControls_Manager::TEXT,\n            'default' =&gt; 'Scopri di piu',\n        ]\n    );\n\n    $this-&gt;add_control(\n        'button_url',\n        [\n            'label'       =&gt; 'Link Pulsante',\n            'type'        =&gt; ElementorControls_Manager::URL,\n            'placeholder' =&gt; 'https:\/\/tuosito.it',\n            'default'     =&gt; [ 'url' =&gt; '#' ],\n        ]\n    );\n\n    $this-&gt;add_control(\n        'image',\n        [\n            'label'   =&gt; 'Immagine',\n            'type'    =&gt; ElementorControls_Manager::MEDIA,\n            'default' =&gt; [\n                'url' =&gt; ElementorUtils::get_placeholder_image_src(),\n            ],\n        ]\n    );\n\n    $this-&gt;end_controls_section();\n\n    \/\/ SEZIONE STILE\n    $this-&gt;start_controls_section(\n        'style_section',\n        [\n            'label' =&gt; 'Stile',\n            'tab'   =&gt; ElementorControls_Manager::TAB_STYLE,\n        ]\n    );\n\n    $this-&gt;add_control(\n        'title_color',\n        [\n            'label'     =&gt; 'Colore Titolo',\n            'type'      =&gt; ElementorControls_Manager::COLOR,\n            'selectors' =&gt; [\n                '{{WRAPPER}} .cta-title' =&gt; 'color: {{VALUE}}',\n            ],\n        ]\n    );\n\n    $this-&gt;add_group_control(\n        ElementorGroup_Control_Typography::get_type(),\n        [\n            'name'     =&gt; 'title_typography',\n            'label'    =&gt; 'Tipografia Titolo',\n            'selector' =&gt; '{{WRAPPER}} .cta-title',\n        ]\n    );\n\n    $this-&gt;end_controls_section();\n}<\/code><\/pre>\n<h2>render(): Generare il Codice HTML<\/h2>\n<p>Il metodo <code>render()<\/code> genera il codice HTML che viene visualizzato nel frontend del sito. Qui accedi ai valori impostati nei controlli tramite <code>$this-&gt;get_settings_for_display()<\/code>:<\/p>\n<pre><code>protected function render() {\n    $settings = $this-&gt;get_settings_for_display();\n    $target   = $settings['button_url']['is_external'] ? ' target=\"_blank\"' : '';\n    $nofollow = $settings['button_url']['nofollow'] ? ' rel=\"nofollow\"' : '';\n\n    echo '&lt;div class=\"cta-box\"&gt;';\n    if ( ! empty( $settings['image']['url'] ) ) {\n        echo '&lt;img src=\"' . esc_url( $settings['image']['url'] ) . '\" alt=\"\" class=\"cta-image\" \/&gt;';\n    }\n    echo '&lt;h3 class=\"cta-title\"&gt;' . esc_html( $settings['title'] ) . '&lt;\/h3&gt;';\n    echo '&lt;p class=\"cta-desc\"&gt;' . esc_html( $settings['description'] ) . '&lt;\/p&gt;';\n    if ( ! empty( $settings['button_url']['url'] ) ) {\n        echo '&lt;a href=\"' . esc_url( $settings['button_url']['url'] ) . '\"' . $target . $nofollow . ' class=\"cta-btn\"&gt;';\n        echo esc_html( $settings['button_text'] );\n        echo '&lt;\/a&gt;';\n    }\n    echo '&lt;\/div&gt;';\n}<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/gtechgroup.it\/blog\/wp-content\/uploads\/2026\/05\/settings-features.png\" alt=\"Funzionalita avanzate di Elementor per lo sviluppo di widget personalizzati\" \/><\/p>\n<h2>content_template(): Anteprima Live nel Builder<\/h2>\n<p>Il metodo <code>content_template()<\/code> e opzionale ma fortemente consigliato. Genera la anteprima in tempo reale nel builder usando la sintassi <strong>Backbone.js<\/strong> (template JavaScript). Senza questo metodo, Elementor deve fare una chiamata AJAX al server per ogni modifica, rallentando la esperienza di editing:<\/p>\n<pre><code>protected function content_template() {\n    ?&gt;\n    &lt;div class=\"cta-box\"&gt;\n        &lt;# if ( settings.image.url ) { #&gt;\n            &lt;img src=\"{{ settings.image.url }}\" alt=\"\" class=\"cta-image\" \/&gt;\n        &lt;# } #&gt;\n        &lt;h3 class=\"cta-title\"&gt;{{{ settings.title }}}&lt;\/h3&gt;\n        &lt;p class=\"cta-desc\"&gt;{{{ settings.description }}}&lt;\/p&gt;\n        &lt;# if ( settings.button_url.url ) { #&gt;\n            &lt;a href=\"{{ settings.button_url.url }}\" class=\"cta-btn\"&gt;\n                {{{ settings.button_text }}}\n            &lt;\/a&gt;\n        &lt;# } #&gt;\n    &lt;\/div&gt;\n    &lt;?php\n}<\/code><\/pre>\n<p>Nota la differenza di sintassi: <code>{{ }}<\/code> per i valori con escape e <code>{{{ }}}<\/code> per i valori senza escape (HTML grezzo).<\/p>\n<h2>Caricare CSS e JavaScript<\/h2>\n<p>Se il tuo widget richiede fogli di stile o script personalizzati, registrali nei metodi dedicati:<\/p>\n<pre><code>public function get_style_depends() {\n    return [ 'my-widget-styles' ];\n}\n\npublic function get_script_depends() {\n    return [ 'my-widget-scripts' ];\n}<\/code><\/pre>\n<p>Registra gli asset nel file principale del plugin:<\/p>\n<pre><code>function register_widget_assets() {\n    wp_register_style( 'my-widget-styles', plugins_url( 'assets\/css\/widgets.css', __FILE__ ) );\n    wp_register_script( 'my-widget-scripts', plugins_url( 'assets\/js\/widgets.js', __FILE__ ), [ 'jquery' ], '1.0.0', true );\n}\nadd_action( 'wp_enqueue_scripts', 'register_widget_assets' );<\/code><\/pre>\n<h2>Categorie Personalizzate<\/h2>\n<p>Per organizzare i tuoi widget in una categoria dedicata nel pannello:<\/p>\n<pre><code>function add_custom_widget_category( $elements_manager ) {\n    $elements_manager-&gt;add_category(\n        'my-custom-widgets',\n        [\n            'title' =&gt; 'I Miei Widget',\n            'icon'  =&gt; 'fa fa-plug',\n        ]\n    );\n}\nadd_action( 'elementor\/elements\/categories_registered', 'add_custom_widget_category' );<\/code><\/pre>\n<h2>Pacchettizzare come Plugin<\/h2>\n<p>Una volta sviluppati e testati i widget, pacchettizza il tutto come un <strong>plugin WordPress standard<\/strong>:<\/p>\n<ol>\n<li>Aggiungi le intestazioni corrette nel file principale del plugin<\/li>\n<li>Verifica che Elementor sia attivo prima di registrare i widget (controlla <code>did_action( 'elementor\/loaded' )<\/code>)<\/li>\n<li>Gestisci la compatibilita con le versioni di Elementor (controlla <code>ELEMENTOR_VERSION<\/code>)<\/li>\n<li>Aggiungi un file <code>readme.txt<\/code> se intendi distribuirlo<\/li>\n<li>Crea un file ZIP per la distribuzione<\/li>\n<\/ol>\n<h2>Conclusione<\/h2>\n<p>Creare widget personalizzati per Elementor e un processo strutturato che richiede conoscenze di PHP e comprensione della architettura del page builder. Una volta padroneggiata la API, le possibilita sono <strong>praticamente illimitate<\/strong>: puoi creare widget per qualsiasi esigenza, da semplici box informativi a integrazioni complesse con API esterne.<\/p>\n<p>Se hai bisogno di widget personalizzati per il tuo progetto ma non hai le competenze di sviluppo necessarie, <a href=\"https:\/\/gtechgroup.it\/contatti\/\">contattaci<\/a> per una consulenza tecnica.<\/p>\n<h2>Guide Correlate della Serie Elementor<\/h2>\n<ul>\n<li><a href=\"https:\/\/gtechgroup.it\/blog\/elementor-css-personalizzato\/\">CSS Personalizzato in Elementor: Guida Completa<\/a><\/li>\n<li><a href=\"https:\/\/gtechgroup.it\/blog\/elementor-sezioni-container-flexbox-migrazione\/\">Da Sezioni a Container Flexbox: Migrazione<\/a><\/li>\n<li><a href=\"https:\/\/gtechgroup.it\/blog\/elementor-theme-builder-header-footer\/\">Theme Builder: Header, Footer e Template Globali<\/a><\/li>\n<li><a href=\"https:\/\/gtechgroup.it\/blog\/elementor-role-manager-accessi-permessi\/\">Role Manager: Gestire Accessi e Permessi<\/a><\/li>\n<li><a href=\"https:\/\/gtechgroup.it\/blog\/guida-completa-elementor-come-funziona\/\">Guida Completa a Elementor: Come Funziona<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Creare Widget Personalizzati per Elementor: Guida Sviluppatori Elementor offre decine di widget predefiniti, ma in alcuni casi le esigenze specifiche di un progetto richiedono funzionalita&hellip;<\/p>\n","protected":false},"author":2,"featured_media":166404,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"","_seopress_titles_title":"Creare Widget Personalizzati per Elementor [2026]","_seopress_titles_desc":"Come creare widget personalizzati per Elementor con PHP e JavaScript. Struttura, controlli, rendering e best practice.","_seopress_robots_index":"","footnotes":""},"categories":[61],"tags":[2643,2645,2560,2644],"class_list":["post-166544","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-wordpress","tag-elementor-custom-widget","tag-elementor-developer","tag-sviluppo-elementor","tag-widget-personalizzati"],"_links":{"self":[{"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/posts\/166544","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/comments?post=166544"}],"version-history":[{"count":0,"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/posts\/166544\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/media\/166404"}],"wp:attachment":[{"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/media?parent=166544"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/categories?post=166544"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gtechgroup.it\/blog\/wp-json\/wp\/v2\/tags?post=166544"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}