Magento 2 – Create Widget with Image Chooser

magento2widgets

So am working on a widget which allows the client to choose an image from their library of images and then insert it into the widget's params. Here is the block class code I am using for the image chooser and below is the widget parameter declaration in widget.xml

<parameter name="widget_image_chooser" xsi:type="block" visible="true" sort_order="20" required="true">
    <label translate="true">Category</label>
    <block class="Company\Module\Block\Widget\Image\Chooser">
        <data>
            <item name="button" xsi:type="array">
                <item name="open" xsi:type="string">Select Image</item>
            </item>
        </data>
    </block>
</parameter>

Now the problem is when the widget is inserted to a CMS Page or Block, it is inserted as a media widget instance, breaking the code because there can't be double quotes within double quotes, see below.

{{widget type="Company\Module\Block\Widget\LityVideo" identifier="https://vimeo.com/169559548" widget_image_chooser="{{media url="wysiwyg/13876414_1349854728361522_4781756811153391947_n.jpg"}}"}}

Is there a way of solving this without having to use javascript? I haven't been able to find the Model which renders the widgets in the CMS in the backend.

Best Answer

There seems to be a lot of people looking for a solution for this so here is my solution to my own answer.

The first thing you need to do is create a new plugin (interceptor) under [COMPANY]/[MODULE]/etc/di.xml

<?xml version="1.0" encoding="UTF-8" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Widget\Model\Widget">
        <plugin name="test1" type="[COMPANY]\[MODULE]\Model\Widget" sortOrder="1" disabled="false"/>
    </type>
</config>

Then create the interceptor logic, you need to use the before method, this way you can change the parameters being passed to \Magento\Widget\Model\Widget, getWidgetDeclaration so something like this.

namespace [COMPANY]\[MODULE]\Model;

use \Magento\Widget\Model\Widget as BaseWidget;

class Widget
{
    public function beforeGetWidgetDeclaration(BaseWidget $subject, $type, $params = [], $asIs = true)
    {
        // I rather do a check for a specific parameters
        if(key_exists("widget_image_chooser", $params)) {

            $url = $params["widget_image_chooser"];
            if(strpos($url,'/directive/___directive/') !== false) {

                $parts = explode('/', $url);
                $key   = array_search("___directive", $parts);
                if($key !== false) {

                    $url = $parts[$key+1];
                    $url = base64_decode(strtr($url, '-_,', '+/='));

                    $parts = explode('"', $url);
                    $key   = array_search("{{media url=", $parts);
                    $url   = $parts[$key+1];

                    $params["widget_image_chooser"] = $url;
                }
            }
        }

        return array($type, $params, $asIs);
    }
}