Is there a way to create a custom widget with WYSIWYG fields? I followed this tutorial here but when I enter data, they are not saved.
4 Answers
You follow the this url for creating custom widgets. Now as per your requirement for WYSIWYG editor.
Open widget.xml file and add new parameter, the code is below.
etc/widget.xml
<?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="Toptal\CustomWidget\Block\Widget\Samplewidget" id="toptal_customwidget_samplewidget">
<label>Toptal Sample Widget</label>
<description></description>
<parameters>
<parameter name="widgettitle" sort_order="10" visible="true" xsi:type="text">
<label>Title</label>
</parameter>
<parameter name="widgetcontent" sort_order="20" visible="true" xsi:type="textarea">
<label>Content</label>
</parameter>
<parameter name="contentnew" xsi:type="block" visible="true" required="true" sort_order="20" >
<label>Custom Content</label>
<block class="Toptal\CustomWidget\Block\Widget\Editor" />
</parameter>
</parameters>
</widget>
</widgets>
Also, create Editor.php class file
Block/Widget/Editor.php
<?php
/**
* @copyright Copyright (c) 2016 www.magebuzz.com
*/
namespace Toptal\CustomWidget\Block\Widget;
Class Editor extends \Magento\Backend\Block\Template
{
protected $wysiwygConfig;
protected $factoryElement;
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Data\Form\Element\Factory $factoryElement,
\Magento\Cms\Model\Wysiwyg\Config $wysiwygConfig,
$data = []
) {
$this->factoryElement = $factoryElement;
$this->wysiwygConfig = $wysiwygConfig;
parent::__construct($context, $data);
}
public function prepareElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
$editor = $this->factoryElement->create('editor', ['data' => $element->getData()])
->setLabel('')
->setForm($element->getForm())
->setWysiwyg(true)
->setConfig(
$this->wysiwygConfig->getConfig([
'add_variables' => false,
'add_widgets' => false,
'add_images' => false
])
);
if ($element->getRequired()) {
$editor->addClass('required-entry');
}
$element->setData('after_element_html', $editor->getElementHtml());
$element->setValue(''); // Hides the additional label that gets added.
return $element;
}
}
Lastly flush cache
php bin/magento cache:flush
-
1Hello @kishor, I have successfully added TinyMCE editor, but when I add <a> and then try to save my widget, I am getting an error as: Failed to execute 'setStartBefore' on 'Range': parameter 1 is not of type 'Node'. Commented Feb 18, 2019 at 13:29
-
here the source of the solution. github.com/dmatthew/magento2-widget-parameters But the Error reported by @chirag still exists– ZFNerdCommented Mar 4, 2019 at 14:48
Finally found a solution: the widget had to be inserted via the "Widgets section" of the Admin and not by the "Pages" one. It works fine.
In magento 2.4 the above answers gave me a bug where I first had to click "show / hide editor". I fixed this by implementing it with a textarea and parse it afterwards with JS. I got inspired by core module: Magento\Catalog\Block\Adminhtml\Helper\Form\Wysiwyg;
class Editor extends \Magento\Backend\Block\Template
{
const TEXT_AREA_ID = 'stepsContentWidget';
protected $_elementFactory;
/**
* @var SecureHtmlRenderer
*/
protected $secureRenderer;
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Data\Form\Element\Factory $elementFactory
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Data\Form\Element\Factory $elementFactory,
?SecureHtmlRenderer $secureRenderer = null,
array $data = []
)
{
$this->secureRenderer = $secureRenderer ?? ObjectManager::getInstance()->get(SecureHtmlRenderer::class);
$this->_elementFactory = $elementFactory;
parent::__construct($context, $data);
}
/**
* Prepare chooser element HTML
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element Form Element
* @return \Magento\Framework\Data\Form\Element\AbstractElement
*/
public function prepareElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
$input = $this->_elementFactory->create("textarea", ['data' => $element->getData()]);
$input->setId(self::TEXT_AREA_ID);
$input->setForm($element->getForm());
$input->setClass("widget-option input-textarea admin__control-text");
if ($element->getRequired()) {
$input->addClass('required-entry');
}
$element->setData('after_element_html', $input->getElementHtml() . $this->addAfterHtmlJs() . $this->getAfterElementHtmlCss());
return $element;
}
public function addAfterHtmlJs()
{
$scriptString = <<<HTML
require([
'jquery',
'mage/adminhtml/wysiwyg/tiny_mce/setup'
], function(jQuery){
wysiwygcompany_description = new wysiwygSetup('{$this->getHtmlId()}', {
"width":"100%%", // defined width of editor
"height":"200px", // height of editor
"plugins":[], // for image
"tinymce4":{"toolbar":"formatselect | bold italic underline | alignleft aligncenter alignright | bullist numlist | link table charmap","plugins":"advlist autolink lists link charmap media noneditable table contextmenu paste code help table",
}
});
wysiwygcompany_description.setup("exact");
});
HTML;
return $this->secureRenderer->renderTag('script', [], $scriptString, false);
}
/**
* @return string
*/
protected function getAfterElementHtmlCss() {
$html = <<<HTML
<style>
.admin__field-control.control .control-value {
display: none !important;
}
</style>
HTML;
return $html;
}
public function getHtmlId()
{
return self::TEXT_AREA_ID;
}
}
This work in Magento 2.4.2
<?php
/**
* @author Vince Verhoeven
*/
namespace Vendor\Module\Block\Adminhtml\Widget;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\View\Helper\SecureHtmlRenderer;
class Editor extends \Magento\Backend\Block\Template
{
const TEXT_AREA_ID = 'contentWidget';
protected $_elementFactory;
/**
* @var SecureHtmlRenderer
*/
protected $secureRenderer;
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Data\Form\Element\Factory $elementFactory
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
array $data = [],
\Magento\Framework\Data\Form\Element\Factory $elementFactory,
?SecureHtmlRenderer $secureRenderer = null
)
{
$this->secureRenderer = $secureRenderer ?? ObjectManager::getInstance()->get(SecureHtmlRenderer::class);
$this->_elementFactory = $elementFactory;
parent::__construct($context, $data);
}
/**
* Prepare chooser element HTML
*
* @param \Magento\Framework\Data\Form\Element\AbstractElement $element Form Element
* @return \Magento\Framework\Data\Form\Element\AbstractElement
*/
public function prepareElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
$input = $this->_elementFactory->create("textarea", ['data' => $element->getData()]);
$input->setId(self::TEXT_AREA_ID);
$input->setForm($element->getForm());
$input->setClass("widget-option input-textarea admin__control-text");
if ($element->getRequired()) {
$input->addClass('required-entry');
}
$element->setData('after_element_html', $input->getElementHtml() . $this->addAfterHtmlJs() . $this->getAfterElementHtmlCss());
return $element;
}
public function addAfterHtmlJs()
{
$scriptString = <<<HTML
require([
'jquery',
'mage/adminhtml/wysiwyg/tiny_mce/setup'
], function(jQuery){
wysiwygcompany_description = new wysiwygSetup('{$this->getHtmlId()}', {
"width":"100%%", // defined width of editor
"height":"200px", // height of editor
"plugins":[], // for image
"tinymce4":{"toolbar":"formatselect | bold italic underline | alignleft aligncenter alignright | bullist numlist | link table charmap","plugins":"advlist autolink lists link charmap media noneditable table contextmenu paste code help table",
}
});
wysiwygcompany_description.setup("exact");
});
HTML;
return $this->secureRenderer->renderTag('script', [], $scriptString, false);
}
/**
* @return string
*/
protected function getAfterElementHtmlCss() {
$html = <<<HTML
<style>
.admin__field-control.control .control-value {
display: none !important;
}
</style>
HTML;
return $html;
}
public function getHtmlId()
{
return self::TEXT_AREA_ID;
}
}
For Multiple editors in one widget then change $this->getHtmlId() to $element->getId()
Happy Coding