# Introduction
This part explains the Elementor widget base class, required methods and lifecycle. We’ll use these concepts to build the Collection Products widget in the next part.
# Learning Objectives
By the end of this tutorial, you will understand:
-
- The structure of an Elementor widget class
- Required methods and their purposes
- How widgets are registered with Elementor
- The widget lifecycle from registration to rendering
- Widget controls and how they create the settings panel
- How widgets render content on the frontend
- Best practices for widget development
# The Elementor Widget Base Class
All Elementor widgets extend the \Elementor\Widget_Base abstract class. This base class provides the foundation and structure that Elementor expects from every widget.
# Key Concept: Object-Oriented Programming
Elementor uses Object-Oriented Programming (OOP) principles. Your widget is a PHP class that extends (inherits from) the base widget class.
class My_Custom_Widget extends \Elementor\Widget_Base {
// Your widget code here
}
# Required Methods
Every Elementor widget must implement certain methods. Let’s examine each one:
# 1. get_name()
Purpose: Returns a unique identifier for your widget.
public function get_name() {
return 'collection_products';
}
Important Points:
- Must be unique across all widgets
- Use lowercase letters, numbers, and underscores only
- No spaces or special characters
- This name is used internally by Elementor
# 2. get_title()
Purpose: Returns the human-readable title shown in the widget panel.
public function get_title() {
return __( 'Collection Products', 'hello-biz-child' );
}
Important Points:
- This is what users see in the Elementor editor
- Use
__()for translation support - Keep it clear and descriptive
# 3. get_icon()
Purpose: Returns the icon class that appears next to the widget name.
public function get_icon() {
return 'eicon-products';
}
Important Points:
- Uses Elementor’s icon library
- Format:
eicon-{icon-name} - Browse available icons in Elementor’s icon library
- Common icons:
eicon-posts-grid,eicon-products,eicon-gallery-grid
# 4. get_categories()
Purpose: Defines which category panel the widget appears in.
public function get_categories() {
return [ 'woocommerce-elements' ];
}
Available Categories:
basic– Basic widgetsgeneral– General elementswoocommerce-elements– WooCommerce widgets (we’ll use this)theme-elements– Theme-specific widgets- You can also create custom categories
# 5. register_controls() (Optional but Essential)
Purpose: Defines the widget’s settings panel in the Elementor editor.
protected function register_controls() {
// Define control sections and controls here
}
Important Points:
- This method is
protected(notpublic) - Controls are settings users can modify in the Elementor panel
- Controls are organized into sections
- This is where you define all user-configurable options
# 6. render()
Purpose: Outputs the HTML for the frontend display.
protected function render() {
$settings = $this->get_settings_for_display();
// Output your HTML here
echo '
‘; }
Important Points:
- This method is
protected - Use
$this->get_settings_for_display()to access user settings - Output sanitized HTML
- This code runs on the frontend when the page loads
# Widget Lifecycle
Understanding when methods are called helps you structure your code effectively:
- Widget Registration
- WordPress loads
- Elementor initializes
- Your widget class is registered via
elementor/widgets/registerhook
- Editor Load
- User opens Elementor editor
get_name(),get_title(),get_icon(),get_categories()are called- Widget appears in the panel
- Widget Inserted
- User drags widget onto page
register_controls()is called- Control panel appears in the editor
- Settings Changed
- User modifies controls
- Widget preview updates in editor
render()is called for preview
- Page Saved
- Settings are saved to the database
- Widget configuration is stored
- Frontend Display
- Visitor loads the page
render()is called- HTML is output to the page
# Understanding Controls
Controls are the building blocks of your widget’s settings panel. Let’s break down how they work:
# Control Sections
Controls are organized into sections. A section is a collapsible panel in the editor.
protected function register_controls() {
// Start a new section
$this->start_controls_section(
'section_content', // Section ID (must be unique within widget)
[
'label' => __( 'Content', 'hello-biz-child' ), // Section title
]
);
// Add controls here
// End the section
$this->end_controls_section();
}
# Adding Controls
Between start_controls_section() and end_controls_section(), you add individual controls:
$this->add_control(
'products_per_page', // Control ID (must be unique within widget)
[
'label' => __( 'Products Per Page', 'hello-biz-child' ),
'type' => \Elementor\Controls_Manager::NUMBER,
'default' => 9,
'min' => 3,
]
);
# Common Control Types
NUMBER – Numeric input
'type' => \Elementor\Controls_Manager::NUMBER,
'default' => 9,
'min' => 1,
'max' => 100,
'step' => 3,
SELECT – Dropdown menu
'type' => \Elementor\Controls_Manager::SELECT,
'default' => 'date',
'options' => [
'date' => __( 'Date', 'hello-biz-child' ),
'title' => __( 'Title', 'hello-biz-child' ),
'price' => __( 'Price', 'hello-biz-child' ),
],
SELECT2 – Multi-select dropdown
'type' => \Elementor\Controls_Manager::SELECT2,
'multiple' => true,
'options' => $this->get_categories(),
'label_block' => true,
SWITCHER – Toggle switch (yes/no)
'type' => \Elementor\Controls_Manager::SWITCHER,
'label_on' => __( 'Yes', 'hello-biz-child' ),
'label_off' => __( 'No', 'hello-biz-child' ),
'return_value' => 'yes',
'default' => 'yes',
SLIDER – Range slider
'type' => \Elementor\Controls_Manager::SLIDER,
'size_units' => [ 'px' ],
'range' => [
'px' => [
'min' => 0,
'max' => 50,
'step' => 1,
],
],
'default' => [
'unit' => 'px',
'size' => 10,
],
TEXT – Text input
'type' => \Elementor\Controls_Manager::TEXT,
'default' => __( 'Default text', 'hello-biz-child' ),
'placeholder' => __( 'Enter text', 'hello-biz-child' ),
# Style Controls
For styling options, use the TAB_STYLE tab:
$this->start_controls_section(
'section_style',
[
'label' => __( 'Style', 'hello-biz-child' ),
'tab' => \Elementor\Controls_Manager::TAB_STYLE, // Style tab
]
);
# Using Selectors
Selectors allow controls to directly affect CSS:
$this->add_control(
'gap',
[
'label' => __( 'Gap', 'hello-biz-child' ),
'type' => \Elementor\Controls_Manager::SLIDER,
'selectors' => [
'{{WRAPPER}} .my-grid' => 'gap: {{SIZE}}{{UNIT}};',
],
]
);
Key Points:
{{WRAPPER}}is replaced with the widget’s unique wrapper selector{{SIZE}}is replaced with the slider value{{UNIT}}is replaced with the selected unit (px, %, em, etc.)
# Accessing Settings in render()
To use the settings in your widget:
protected function render() {
// Get settings
$settings = $this->get_settings_for_display();
// Access individual settings
$products_per_page = $settings['products_per_page'];
$orderby = $settings['orderby'];
$show_filters = $settings['show_filters'];
// Use in your code
if ( $show_filters === 'yes' ) {
// Display filters
}
}
# Widget Registration
To make your widget available in Elementor, you must register it:
function register_my_widget( $widgets_manager ) {
require_once( __DIR__ . '/my-widget.php' );
$widgets_manager->register( new \My_Custom_Widget() );
}
add_action( 'elementor/widgets/register', 'register_my_widget' );
Important Points:
- Hook into
elementor/widgets/register - Require/include your widget file
- Instantiate and register your widget class
# Best Practices
# 1. Namespace Your Widget
Avoid naming conflicts by using a unique class name:
// Good
class Collection_Products_Widget extends \Elementor\Widget_Base {
// Better (with namespace)
namespace MyTheme\Widgets;
class Collection_Products extends \Elementor\Widget_Base {
# 2. Translation Ready
Always use translation functions:
// Good
'label' => __( 'Products Per Page', 'hello-biz-child' ),
// Bad
'label' => 'Products Per Page',
# 3. Sanitize Output
Always escape output in render():
// Good
echo '<div class="' . esc_attr( $class ) . '">';
echo esc_html( $title );
// Bad
echo '<div class="' . $class . '">';
echo $title;
# 4. Organize Controls
Group related controls into sections:
// Query settings section
$this->start_controls_section( 'section_query', [...] );
// Display settings section
$this->start_controls_section( 'section_display', [...] );
// Style settings section
$this->start_controls_section( 'section_style', [...] );
# 5. Provide Defaults
Always provide sensible default values:
'default' => 9, // Good default for products per page
'default' => 'date', // Reasonable sort option
# Example: Simple Widget Structure
Here’s a complete example of a minimal widget:
<?php
class Simple_Widget extends \Elementor\Widget_Base {
// Required: Unique widget name
public function get_name() {
return 'simple_widget';
}
// Required: Widget title in panel
public function get_title() {
return __( 'Simple Widget', 'hello-biz-child' );
}
// Required: Widget icon
public function get_icon() {
return 'eicon-posts-grid';
}
// Required: Widget category
public function get_categories() {
return [ 'general' ];
}
// Optional: Widget keywords for search
public function get_keywords() {
return [ 'simple', 'example' ];
}
// Define settings controls
protected function register_controls() {
// Content Section
$this->start_controls_section(
'content_section',
[
'label' => __( 'Content', 'hello-biz-child' ),
]
);
$this->add_control(
'title',
[
'label' => __( 'Title', 'hello-biz-child' ),
'type' => \Elementor\Controls_Manager::TEXT,
'default' => __( 'Hello World', 'hello-biz-child' ),
]
);
$this->end_controls_section();
}
// Render widget output
// Render widget output
protected function render() {
$settings = $this->get_settings_for_display();
?>
<div class="simple-widget">
<h2><?php echo esc_html( $settings['title'] ); ?></h2>
</div>
<?php }
}
# Understanding the Data Flow
Let’s trace how data flows through a widget:
- User Interaction: User sets “Products Per Page” to 12 in editor
- Setting Saved: Value stored as
['products_per_page' => 12] - Render Called:
render()method executes - Settings Retrieved:
$settings = $this->get_settings_for_display() - Value Accessed:
$settings['products_per_page']returns 12 - Value Used: Used in WP_Query to limit products
# Common Mistakes to Avoid
# Mistake 1: Forgetting Required Methods
// Bad - Missing required methods
class My_Widget extends \Elementor\Widget_Base {
protected function render() {
echo 'Hello';
}
}
// Good - All required methods present
class My_Widget extends \Elementor\Widget_Base {
public function get_name() { return 'my_widget'; }
public function get_title() { return 'My Widget'; }
public function get_icon() { return 'eicon-posts-grid'; }
public function get_categories() { return ['general']; }
protected function render() { echo 'Hello'; }
}
# Mistake 2: Not Escaping Output
// Bad - No escaping
echo '<div class="' . $class . '">' . $content . '</div>';
// Good - Properly escaped
echo '<div class="' . esc_attr( $class ) . '">' . esc_html( $content ) . '</div>';
# Mistake 3: Using echo in register_controls()
// Bad - Don't output in register_controls()
protected function register_controls() {
echo 'Adding controls'; // Wrong!
$this->add_control(...);
}
// Good - Only define controls
protected function register_controls() {
$this->add_control(...);
}
# Testing Your Understanding
To verify you understand these concepts, try answering:
- What happens if you don’t implement
get_name()? - Which method outputs HTML to the frontend?
- Where do you define the widget’s settings panel?
- How do you access user settings in the
render()method? - What’s the difference between
protectedandpublicmethods?
Answers:
- PHP will throw a fatal error – it’s a required abstract method
- The
render()method - In the
register_controls()method - Using
$this->get_settings_for_display() publicmethods can be called from outside the class,protectedonly from within the class or child classes
# Summary
You now understand:
- The Elementor widget base class structure
- Required methods and their purposes
- How to define widget controls
- The widget lifecycle
- How settings flow from editor to frontend
- Best practices for widget development
# What’s Next?
In Part 3: Building the Basic Widget Structure, we’ll apply this knowledge to create the foundation of our Collection Products widget. We’ll:
- Create the widget PHP files
- Implement the required methods
- Register the widget with Elementor
- Add basic controls
- Create a simple render method
- Test the widget in Elementor
# Additional Resources
- Elementor Developers – Widget Structure
- Elementor Controls Reference
- PHP Object-Oriented Programming
Previous: ← Part 1: Setting Up the Development Environment
Next: Part 3: Building the Basic Widget Structure →