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.

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

    Widget not appearing:

    • Clear cache: bin/magento cache:flush
    • Verify module is enabled
    • Check widget.xml syntax
    • Confirm block class path matches widget configuration

    Parameters not showing:

    • Check visible="true" attribute
    • Verify source model exists for select fields
    • Review parameter type definitions
    • Clear configuration cache

    Template not rendering:

    • Confirm template path in block class
    • Check file permissions
    • Verify template syntax
    • Enable developer mode for error details

    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.