Build Custom Widgets in Magento 2: Complete Development Guide

Build Custom Widgets in Magento 2: Complete Development Guide
Creating a custom widget in Magento 2 lets you add dynamic content to CMS pages, blocks, and template files. This guide walks you through building a product slider widget with configurable options that admin users can manage without touching code.
Table Of Content
Understanding Magento 2 Widgets
A widget generates dynamic content on your store through a user-friendly admin interface. You can display product listings, affiliate links, third-party content like reviews, or any custom functionality you need.
Magento 2 custom widgets are reusable content blocks configured via the admin panel and rendered on frontend pages. Store administrators can add interactive features to the front-end without programming knowledge.
Widget vs Block: Key Differences
Both serve content management purposes but have distinct roles:
Widgets:
- Configurable through admin UI with custom parameters
- Placed in multiple page sections via backend
- Map to code with parameter sets
- Reusable across different pages with varying settings
Blocks:
- Static content pieces containing text or child elements
- Primarily used by developers in layout XML files
- Limited placement options compared to widgets
- Can contain widgets (and vice versa)
You can place widgets in various sections across different pages using the backend UI, while static blocks have fewer placement options.
Required Files for Widget Development
File Type | Location / Purpose |
---|---|
module.xml | etc/ - Declares module and dependencies |
registration.php | Root directory - Registers module with Magento |
widget.xml | etc/ - Defines widget configuration and parameters |
Block Class | Block/Widget/ - Handles widget logic and data processing |
Template File | view/frontend/templates/widget/ - Renders HTML output |
Source Model | Model/Config/Source/ - Provides dropdown options (optional) |
Tip
To enhance your eCommerce store’s performance with Magento, focus on optimizing site speed by utilizing Emmo themes and extensions. These tools are designed for efficiency, ensuring your website loads quickly and provides a smooth user experience. Start leveraging Emmo's powerful solutions today to boost customer satisfaction and drive sales!
Step-by-Step Widget Creation
Configure widget.xml
Define your widget's properties and admin panel parameters:
<?xml version="1.0" ?>
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
<widget class="Vendor\Module\Block\Widget\ProductSlider" id="vendor_product_slider">
<label>Product Slider Widget</label>
<description>Display products based on filters like best sellers, most viewed, or recently added items.</description>
<parameters>
<parameter name="title" sort_order="10" visible="true" xsi:type="text">
<label translate="true">Title</label>
</parameter>
<parameter name="product_count" sort_order="20" visible="true" xsi:type="text">
<label translate="true">Number of Products</label>
</parameter>
<parameter name="display_type" sort_order="30" visible="true" xsi:type="select" source_model="Vendor\Module\Model\Config\Source\DisplayType">
<label translate="true">Display Type</label>
</parameter>
</parameters>
</widget>
</widgets>
The id
attribute creates a unique widget identifier. The class
attribute maps to your block file path.
Build the Block Class
Create the main logic that retrieves and processes data:
<?php
namespace Vendor\Module\Block\Widget;
use Magento\Framework\View\Element\Template;
use Magento\Widget\Block\BlockInterface;
class ProductSlider extends Template implements BlockInterface
{
protected $_template = 'Vendor_Module::widget/product_slider.phtml';
protected $productCollection;
protected $bestSellersFactory;
public function __construct(
Template\Context $context,
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollection,
\Magento\Sales\Model\ResourceModel\Report\Bestsellers\CollectionFactory $bestSellersFactory,
array $data = []
) {
$this->productCollection = $productCollection;
$this->bestSellersFactory = $bestSellersFactory;
parent::__construct($context, $data);
}
public function getProductCollection() {
$displayType = $this->getData('display_type');
if ($displayType == "best_sellers") {
return $this->getBestSellers();
} elseif ($displayType == "most_viewed") {
return $this->getMostViewed();
} else {
return $this->getRecentProducts();
}
}
protected function getBestSellers() {
$collection = $this->productCollection->create();
$collection->addAttributeToSelect('*')
->setPageSize($this->getProductLimit())
->addStoreFilter($this->getStoreId());
return $collection;
}
protected function getProductLimit() {
return (int) $this->getData("product_count");
}
protected function getStoreId() {
return $this->_storeManager->getStore()->getId();
}
}
The block class must implement BlockInterface
. Extend Magento\Framework\View\Element\Template
for most widgets.
Create the Template File
Build the HTML structure in view/frontend/templates/widget/product_slider.phtml
:
<?php
$products = $block->getProductCollection();
if ($products->getSize() <= 0) { return; }
?>
<div class="custom-product-slider">
<h2><?php echo $block->escapeHtml($block->getData("title")); ?></h2>
<div class="products-wrapper">
<?php foreach($products as $product): ?>
<div class="product-item">
<a href="<?php echo $product->getProductUrl(); ?>">
<img src="<?php echo $product->getImage(); ?>" alt="<?php echo $block->escapeHtml($product->getName()); ?>">
<span><?php echo $block->escapeHtml($product->getName()); ?></span>
</a>
</div>
<?php endforeach; ?>
</div>
</div>
Add Source Model for Dropdown Options
Create Model/Config/Source/DisplayType.php
for select field options:
<?php
namespace Vendor\Module\Model\Config\Source;
class DisplayType implements \Magento\Framework\Data\OptionSourceInterface
{
public function toOptionArray()
{
return [
['value' => 'best_sellers', 'label' => __('Best Selling Products')],
['value' => 'most_viewed', 'label' => __('Most Viewed Products')],
['value' => 'recent_products', 'label' => __('Recently Added Products')]
];
}
}
Adding Widgets to Your Store
Insert Widget in CMS Pages
- Navigate to Content → Pages in admin
- Edit or create a page
- Click "Insert Widget" in the content editor
- Select your custom widget type
- Configure parameters (title, product count, display type)
- Click "Insert Widget"
Click "Insert Widget"
Add Widget to Static Blocks
Follow the same process in Content → Blocks. Widgets can be added to any CMS block to showcase various content elements.
Insert Widget Programmatically
Add widgets directly in template files:
<?php
echo $this->getLayout()
->createBlock("Vendor\\Module\\Block\\Widget\\ProductSlider")
->setTitle("New Arrivals")
->setProductCount(6)
->setDisplayType("recent_products")
->toHtml();
?>
Built-in Magento Widgets
Magento includes several default widget types for common functionality:
Widget Type | Function |
---|---|
CMS Static Block | Insert existing static blocks into pages |
CMS Page Link | Create links to specific CMS pages |
Catalog Product Link | Link to individual products |
Catalog New Products | Display recently added products |
Recently Viewed Products | Show products customers viewed |
Recently Compared Products | Display compared products |
Orders and Returns | Guest order status checking |
Widget Parameter Types
Configure different input types in widget.xml:
- text: Single-line text input
- textarea: Multi-line text input
- select: Dropdown with source model
- multiselect: Multiple selection dropdown
- block: Block chooser
- page_id: CMS page selector
- conditions: Product condition builder
Example with multiple parameter types:
<parameter name="description" xsi:type="textarea" visible="true">
<label>Description</label>
</parameter>
<parameter name="categories" xsi:type="multiselect" source_model="Vendor\Module\Model\Source\Categories">
<label>Select Categories</label>
</parameter>
Advanced Widget Features
Dependent Parameters
Make parameters conditional based on other selections:
<parameter name="custom_option" xsi:type="text" visible="true">
<label>Custom Option</label>
<depends>
<parameter name="display_type" value="custom" />
</depends>
</parameter>
The custom_option
field only appears when display_type
equals "custom".
Widget Caching
Multiple widgets on a page can negatively impact first load performance when not cached. Implement caching in your block class:
protected function _construct()
{
parent::_construct();
$this->addData([
'cache_lifetime' => 86400,
'cache_tags' => ['VENDOR_MODULE_WIDGET'],
]);
}
public function getCacheKeyInfo()
{
return [
'VENDOR_MODULE_WIDGET',
$this->_storeManager->getStore()->getId(),
$this->getData('display_type'),
$this->getData('product_count'),
];
}
Best Practices
Performance Optimization:
- Limit product collections with proper page sizes
- Add store filters to collections
- Implement widget-level caching
- Use lazy loading for images
Code Quality:
- Follow Magento coding standards
- Validate and sanitize admin inputs
- Use dependency injection properly
- Escape output in templates
User Experience:
- Provide clear parameter labels and descriptions
- Set sensible default values
- Group related parameters logically
- Test widgets across different themes
Troubleshooting Common Issues
- Clear cache:
bin/magento cache:flush
- Verify module is enabled
- Check
widget.xml
syntax - Confirm block class path matches widget configuration
- Check
visible="true"
attribute - Verify source model exists for select fields
- Review parameter type definitions
- Clear configuration cache
- Confirm template path in block class
- Check file permissions
- Verify template syntax
- Enable developer mode for error details
Widget not appearing:
Parameters not showing:
Template not rendering:
Conclusion
Developer communities like Magento Stack Exchange offer discussions, insights, and troubleshooting tips for widget development. The official Magento documentation at docs.adobe.com provides comprehensive guides on advanced widget features.
Custom widgets enhance store functionality, improve user experience, and give you control over dynamic content without modifying core files. Start with simple widgets and gradually add complexity as you become comfortable with the architecture.
FAQs
What is a Magento 2 widget?
A Magento 2 widget is a reusable content block that allows you to display dynamic data or features (like products, banners, or forms) on CMS pages, blocks, and layouts without writing code each time.
Why should I create a custom widget in Magento 2?
Building a custom widget lets you add tailored functionality to your store — such as special promotions, custom product sliders, or featured categories — while maintaining full control over its design and behavior.
Where do I define a custom widget in Magento 2?
You define custom widgets in the etc/widget.xml
file of your module or theme. This file includes parameters, labels, and block class references that determine how your widget functions and appears.
Which files are essential to create a Magento 2 widget?
Key files include widget.xml
for widget configuration, a PHP block class that contains logic, and a .phtml
template file that handles frontend rendering.
How do I register a widget in Magento 2?
You register a widget by placing the widget.xml
file under your module’s etc/
directory, then running bin/magento setup:upgrade
to update the system configuration.
Can I use custom parameters in my widget?
Yes. You can define custom parameters in widget.xml
— such as dropdowns, text inputs, or boolean toggles — to allow flexible widget configuration directly from the Magento admin panel.
How do I render a custom widget template?
Reference your template file in the block class using protected $_template
, or dynamically load it through layout XML. Ensure the template path matches your theme structure.
What if my widget is not appearing on the frontend?
Check for syntax errors in widget.xml
, confirm your block class path, and clear cache using bin/magento cache:flush
. Also verify that your module is enabled.
Can I control where my widget appears?
Yes. Widgets can be added to specific CMS pages, static blocks, or layout handles. You can assign display conditions and parameters when inserting the widget through the admin panel.
What’s the best practice for maintaining custom widgets?
Keep widget logic modular in the block class, follow Magento coding standards, use proper namespaces, and document your parameters. Regularly test after version upgrades to ensure compatibility.