To implement a new widget you need to make changes both in Magento and ScandiPWA:
<widget>
tag with its attributes.<aside>
⚠️ You may need to make additional changes to allow the widget component to access the attributes defined in the <widget>
tag as props.
</aside>
Normally, to implement widget rendering, you'd have to define a widget, its block class as well as the Magento template. However, for ScandiPWA, all widgets are rendered the same way – as a single <widget>
element with various attributes.
Hence, you need to:
Define the widget - This is done in the etc/widget.xml
file:
<widgets xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
<widget class="<YOUR VENDOR>\\<YOUR MODULE>\\Block\\Widget\\<WIDGET NAME>" id="your_widget">
<label>Your Widget</label>
<description>A description of your widget</description>
<parameters>
<parameter name="foo" xsi:type="text" required="true" visible="true" sort_order="10">
<label>Foo Parameter</label>
</parameter>
</parameters>
</widget>
</widgets>
Configuration options:
widget
defines a new widget, rendered using the specified block class
.
<aside> ➡️ In this tutorial, you do not need to create the block class. You only need to ensure that it is unique.
</aside>
label
- the name of the widget visible in the Admin panel.description
- additional information that will be visible in the Admin panel.parameters
define a set of attributes that the widget will be configured with when adding it to the page. These will be passed on as props to the <widget>
tag.(learn more about widget parameters)<aside>
❗ To make the foo
attribute available in the widget component in ScandiPWA, you need to make sure it’s allowed. (What can be accessed in the widget component?)
</aside>
Update GraphQL filter
Normally, to implement widget rendering, you'd have to define a block class as well as a Magento template. However, for ScandiPWA, all widgets are rendered the same way – as a single <widget>
element with various attributes.
This rendering logic is already implemented for widgets in ScandiPWA. All you need to do is configure it to render your widget as well. You can do this by adding an argument to ScandiPWA\\CmsGraphQl\\Model\\Template\\VirtualFilter
for your widget in the /etc/graphql/di.xml
file:
<?xml version="1.0"?>
<config xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="ScandiPWA\\CmsGraphQl\\Model\\Template\\VirtualFilter" type="ScandiPWA\\CmsGraphQl\\Model\\Template\\Filter">
<arguments>
<argument name="availableFilters" xsi:type="array">
<item name="<TYPE OF WIDGET>" xsi:type="string"><YOURVENDOR>\\<YOURMODULE>\\Block\\Widget\\<WIDGETNAME></item>
</argument>
</arguments>
</virtualType>
</config>
You only need to modify the item
tag:
name
attribute defines the type of widget that will be shown in the widget tag.This code is responsible for making the block you defined in the widget available when a GraphQL request is made. This block process a tag <widget>
with the attributes defined in the widget.
For example, a processed widget with the previous example would look like this:
<widget type="<TYPE OF WIDGET>" foo="data">
<aside> ➡️ You could also create a block and template for the widget (how to create a block?). However, be sure to meet the requirements for the ScandiPWA widget component.
</aside>
ScandiPWA will only use widget components on pages of type CMS_PAGE
.
Therefore, widgets will not apply to product pages, category pages, etc. To confirm the page type, make a GraphQL query for the URL and send it to <your_host>/graphql
(How to work with requests?).
query{
urlResolver(url:"<YOUR URL>"){
type
}
}
An example of a query and its response:
query{
urlResolver(url:"/"){
type
}
}
{
"data": {
"urlResolver": {
"type": "CMS_PAGE"
}
}
}
To implement a widget component in ScandiPWA you need to determine what component you want to render and the widget type it must implement (how to create a component?).
For example, when the type of widget is Slider
, the HomeSlider
component is rendered by the WidgetFactory
component(how to implement a widget in Magento?).
The recommended way of adding a widget component is through the use of a plugin to include the widget in the renderMap
variable from the WidgetFactory
component. (learn more about how to create a plugin)
For that you just need to create a file src/plugin/WidgetFactory.plugin.js
with:
export const YourWidgetComponent = lazy(() => import(
/* webpackMode: "lazy", webpackChunkName: "<EXTENSION NAME>" */
'../route/YourWidgetComponent'
));
export const WIDGET_TYPE = "<YOUR WIDGET TYPE>";
const renderMap = (originalMember) => ({
...originalMember,
[WIDGET_TYPE]: {
component: YourWidgetComponent
}
});
export default {
"Component/WidgetFactory/Component": {
'member-property': {
renderMap
}
}
}
webpackChunkName
. Make sure to substitute YourWidgetComponent
with the name of your actual widget component.<YOUR WIDGET TYPE>
with the widget type you want to implement.This will include your component in the renderMap
variable of the WidgetFactory
component, which is responsible for storing the components associated with a type.
<aside> ➡️ A widget is a component, remember to follow the best practices:
Often, you'll need to request additional data for your widget:
</aside>
What can be accessed in the widget component?
By default, ScandiPWA does not allow you to access all attributes defined in the <widget>
tag.
Here is a list of attributes that are allowed and available to be accessed:
In the example:
<widget type="test" foo="foo text" title="widget title"></widget>
In this example, you can only access the type
and title
attribute values in the widget component as props. To access other attributes, such as foo
, you need to allow the WidgetFactory
component to pass it as a prop to your custom widget component.
Generally, this is done by using a plugin to update the renderContent
method of the WidgetFactory
component.
WidgetFactory