mage-os / module-page-builder-widget

mage-os/module-page-builder-widget

PageBuilder cms widget module

  • Davide Lunardon
magento2-module Compatibility: 2.4.7-2.4.9 Code Quality: Fail Tests: N/A Security: Pass MIT

MageOS PageBuilder Widget Module for Magento

New page builder component named "CMS Widget".


🚀 Features

The PageBuilder Widget module allows the user to specify CMS widgets and relative configurations inside a dedicated page builder component named "CMS Widget".
As for all pagebuilder components this component is draggable and can be placed inside other components.

[image: plot]

If supported, the page builder will show widget content inside stage preview.

🔌 How it works

Widget Preview assignment

In order to create a widget preview you must create a new widget.xml file inside your module changing Magento_Widget xsd file inside "xsi:noNamespaceSchemaLocation" attribute of "widget" xml node.
Literally change

<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">

with that:

<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:MageOS_PageBuilderWidget:etc/widget.xsd">

Now you're able to specify new widget.xml nodes:

  • previewTemplates
  • previewCss
  • previewJs
  • previewBlock
  • previewBlockArguments

previewTemplates XML node

This is where all starts :) inside this node you must specify each phtml preview file and his relation to the widget frontend phtml view.
So, checking widget.xml inside this module:

<widget id="catalog_product_link">
    <previewTemplates>
        <previewTemplate name="product/widget/link/link_block.phtml" xsi:type="string">MageOS_PageBuilderWidget::widget-preview/product/widget/link/link_block.phtml</previewTemplate>
        <previewTemplate name="product/widget/link/link_inline.phtml" xsi:type="string">MageOS_PageBuilderWidget::widget-preview/product/widget/link/link_inline.phtml</previewTemplate>
    </previewTemplates>
</widget>

As you know xml files are all merged so here we need to specify the widget id and then the previewTemplates node.
The Magento_Widget widget.xml specify widget's parameters and, inside of them, a "template" parameter where multiple templates are specified:

<parameter name="template" type="select" visible="true" translate="label">
    <label>Template</label>
    <option name="default" value="product/widget/link/link_block.phtml" selected="true" translate="label">
        <label>Product Link Block Template</label>
    </option>
    <option name="link_inline" value="product/widget/link/link_inline.phtml" translate="label">
        <label>Product Link Inline Template</label>
    </option>
</parameter>

For each of these options we need to copy the value inside "previewsTemplate" child "previewTemplate" node "name" attribute and our phtml preview file inside his content.
So, specifying the template inside widget configurations pagebuilder will keep the relative phtml preview.

previewCss XML node

For every preview this module allow to specify a dedicated CSS file.
Inside this file you can style your previews.
Keep in mind that these files are included in each widget instance preview on pagebuilder.
Be sure to use enough specific css selectors avoiding conflicts with other components.

<widget id="products_list">
    <previewTemplates>
        <previewTemplate name="Magento_CatalogWidget::product/widget/content/grid.phtml" xsi:type="string">MageOS_PageBuilderWidget::widget-preview/product/widget/content/grid.phtml</previewTemplate>
    </previewTemplates>
    ...
    <previewCss>MageOS_PageBuilderWidget::css/widget/preview/products_list_and_grid.css</previewCss>
    ...
</widget>

ATTENTION: Remember to place this php snippet inside your phtml preview file for css inclusion:

<?= $block->getChildHtml("previewAssets"); ?>

previewJs XML node

For every preview this module allow to specify a dedicated Js file.
Inside this file you can add js actions and triggers to the preview.
Remember that mouse actions are not triggered on widgets preview elements so this JS is useful for animations only (ex: sliders scroll, ... )

<widget id="products_list">
    <previewTemplates>
        <previewTemplate name="Magento_CatalogWidget::product/widget/content/grid.phtml" xsi:type="string">MageOS_PageBuilderWidget::widget-preview/product/widget/content/grid.phtml</previewTemplate>
    </previewTemplates>
    ...
    <previewJs>MageOS_PageBuilderWidget/js/my-widget-preview-js-file</previewJS>
    ...
</widget>

previewBlock XML node

Sometimes you'll need to substitute the main Block class behind the preview choosing it instead of widget model inside "class" attribute.
You can specify this new PHP class in this node and it will be used replacing the original widget class:

<widget id="products_list">
    <previewTemplates>
        <previewTemplate name="Magento_CatalogWidget::product/widget/content/grid.phtml" xsi:type="string">MageOS_PageBuilderWidget::widget-preview/product/widget/content/grid.phtml</previewTemplate>
    </previewTemplates>
    <previewBlock>MageOS\PageBuilderWidget\Block\Adminhtml\Widget\Preview\ProductsList</previewBlock>
    ...
</widget>

ATTENTION: Remember to place this php snippet inside your phtml preview file for js inclusion:

<?= $block->getChildHtml("previewAssets"); ?>

previewBlockArguments XML node

As for previewBlock sometimes widget previews need to have specific methods for content retrieval and other stuff.
So, instead of specifying a new previewBlock node you can add a previewBlockArguments node.
Similar to view model pattern (but no need to implement ArgumentInterface there) you can specify an object that will be initialized for your preview:

 <widget id="products_list">
    <previewTemplates>
        <previewTemplate name="Magento_CatalogWidget::product/widget/content/grid.phtml" xsi:type="string">MageOS_PageBuilderWidget::widget-preview/product/widget/content/grid.phtml</previewTemplate>
    </previewTemplates>
    ...
    <previewBlockArguments>
        <argument name="viewModel" xsi:type="object">MageOS\PageBuilderWidget\ViewModel\Adminhtml\Widget\Preview\ProductImagePreview</argument>
    </previewBlockArguments>
</widget>

Then call his public methods inside your phtml preview:

<?php
...
/**  @var ProductImagePreview $productImagePreview */
$productImagePreview = $block->getData('viewModel');
...
<img src="<?= $productImagePreview->getProductImage($_item) ?>" width="75" height="75" />
...

🔧 Installation

  1. Install it into your Mage-OS/Magento 2 project with composer:

    composer require mage-os/module-page-builder-widget
    
  2. Enable module

    bin/magento module:enable MageOS_PageBuilderWidget
    bin/magento setup:upgrade
    

🤝 Changelog

Please see CHANGELOG for more information on what has changed recently.

📄 License

The MIT License (MIT). Please see License File for more information.

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog
and this project adheres to Semantic Versioning.

1.5.0 - 2026-05-14

Added

  • Declare PHP 8.5 compatibility in composer.json (now explicitly supports PHP 8.1 through 8.5)

Fixed

  • Fix previewTemplates xml node merge adding reference to xml config reader
  • Guard preg_replace_callback in WidgetContentSettingsCleanup against null/empty content to avoid PHP 8.5 deprecation on null subjects
  • Harden Build::sanitizeWidgetParams so preg_replace/escapeHtml never receive non-string values (centralized in sanitizeStringValue)
  • Loosen Build::isTypeValid signature to accept mixed input from the request and validate type safely
  • Add missing getCacheKey(): string / getCacheKeyInfo(): array return types on Block\Adminhtml\Widget\Preview\NewWidget to match parent contracts
  • Consolidate use imports across Block\Adminhtml\Widget\Preview\* and related files

1.4.1

Fixed

  • Fix getCacheKey() return type from array to string matching parent contract

1.4.0

Updated

  • Update composer JSON making the module installable for Magento Opensource also

1.3.2

Fixed

  • Fix CSS issue hiding other modal form labels by @melindash (#10)

1.3.1

Fixed

  • Improve security and avoid script injection through admin widget preview builder controller

1.3.0

Fixed

  • Fix minor code syntax issues and dependencies declaration, add control on widget_type parameter passed for widget preview on adminhtml

1.2.0

Fixed

  • Fix not useful and broken validation on pagebuilder widget form ui component

1.1.1

Updated

  • Remove content_settings attribute on frontend for pages and blocks widgets placed into content

1.1.0

Fixed

  • Fix error for xml compilation on developer mode

1.0.0

Added

  • First Commit, now is possible to use CMS widgets with own previews inside pagebuilder with a dedicated component!
Versions
Version Stability QA Status Compatibility Released
1.5.0 stable Fail Magento 2.4.7-2.4.9 Details 2026-05-15 00:45:13
1.4.1 stable Not tested Not yet tested Details 2026-04-19 20:46:05
1.4.0 stable Not tested Not yet tested Details 2026-03-10 11:04:38
1.3.3 stable Not tested Not yet tested Details 2026-01-20 13:48:43
1.3.2 stable Not tested Not yet tested Details 2025-12-28 04:19:44
1.3.1 stable Not tested Not yet tested Details 2025-10-08 14:21:48
1.3.0 stable Not tested Not yet tested Details 2025-10-04 16:55:14
1.2.0 stable Not tested Not yet tested Details 2025-09-15 06:37:15
1.1.1 stable Not tested Not yet tested Details 2025-07-27 15:53:33
1.1.0 stable Not tested Not yet tested Details 2025-07-23 09:58:02
1.0.0 stable Not tested Not yet tested Details 2025-05-13 14:12:37

Requires 3

Package Constraint
php ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0
magento/module-widget *
magento/module-page-builder ^2.0

Compatibility

Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.

Compatibility matrix (Magento × PHP)
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 Pass Pass
2.4.8 Pass Pass
2.4.9 Pass Pass

Code Quality

Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge — a phpcs finding can't make a module incompatible.

Static analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

Static analysis results
Tool Status Findings Summary
PHPCS Fail 252 13 errors, 239 warnings (ruleset: Magento2) — 170 auto-fixable with phpcbf
PHPMD Warning 12 12 rule violations (UnusedFormalParameter:5, CyclomaticComplexity:2, ExcessiveParameterList:1, NPathComplexity:1, UnusedLocalVariable:1)
Cpd Pass 0
Composer validate Info 1 valid; 1 advisory note (composer validate --strict)

PHPStan

Type-checks the module's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases. Cell → details modal.

PHPStan results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 21 21
2.4.8 20 20
2.4.9 16 16

Tests

Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.

Unit tests

Unit tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Integration tests

Integration tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Security

Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.

Security results
Tool Status Findings Summary
Composer audit Pass 0
Malware scan Pass 0
License
MIT
Authors

More from mage-os

View vendor
Make it pay

Turn an existing module into recurring revenue.

If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.