Creating a Magento Widget

Since widgets are created in the admin panel, we first need to write some Magento logic for the backend part of the widget.

The Magento Developer Docs have a great guide for creating a widget. Lets walk through what you need to do to create a new widget to later make it work with Scandi.

Create the Widget Block

Create a Block class for the widget. It needs to extend Template and implement the BlockInterface. Other than that, the only thing we need to do is specify the _template the widget uses.

app/code/ScandiTutorials/CustomWidget/Block/Widget/NewsletterWidget.php
<?php declare(strict_types=1);
​
namespace ScandiTutorials\\CustomWidget\\Block\\Widget;
​
use Magento\\Framework\\View\\Element\\Template;
use Magento\\Widget\\Block\\BlockInterface;
​
class NewsletterWidget extends Template implements BlockInterface
{
protected $_template = "widget/newsletter_widget.phtml";
}

But we haven't created the template yet! So let's do that next. If you were writing the template for Magento, you would need to render all the elements needed for the widget.

However, since all the Scandi rendering logic happens on the frontend using React, the template can be much simpler. The template merely needs to render a single element to specify the widget type.

This is also where we "send" all the widget parameters to the frontend. Let's say our widget will have a single String parameter, the title. We can get that parameter with $block->escapeHtml($block->getData('title')) and assign it to the data-title attribute:

app/code/ScandiTutorials/CustomWidget/view/frontend/templates/widget/newsletter_widget.phtml
<?php
/** ScandiTutorials\\CustomWidget\\Block\\Widget\\NewsletterWidget $block */
?>
<widget type="newsletter" data-title="<?= $block->escapeHtml($block->getData('title')) ?>"></widget>

You may realize that widget is not a real element type, and both attributes are custom too. This is ok, because all the HTML will get parsed on the frontend to render a custom React element.

For now, we haven't implemented any rendering on the frontend yet. So if you create a test page with this widget and view it, you won't see it. However, if you check the CMS content response received from the server, you'll see that the widget is there!

{
"data": {
"cmsPage": {
"title": "test",
"content": "<widget type=\\"newsletter\\" data-title=\\"hello world\\"></widget>\\n",
"page_width": "default",
"content_heading": "",
"meta_title": "",
"meta_description": "",
"meta_keywords": ""
}
}
}