2

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 4

7

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

2
  • 1
    Hello @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
    – ZFNerd
    Commented Mar 4, 2019 at 14:48
0

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.

0

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;
    }
}
0

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.