Using an Image Selector Parameter for Magento Widgets

Don’t feel like reading? See the code: https://github.com/dmatthew/magento-widget-types

Widgets are great in Magento but can be a little limited in what types of values you can use for the different parameters. Out of the box, Magento provides text boxes, select dropdowns, and blocks. Examples of “block” parameters in Magento are a CMS Block chooser, product chooser, category chooser, and a banner chooser. One very helpful chooser that does not come with Magento is an image chooser. I recently was tasked with rebuilding our home page, and was asked to make sure it was easily editable by non-coders. To do this I created several new types of widgets that admin users could use to build their own homepage designs. One very useful feature of the homepage widgets I created was the ability to add background images to certain blocks. Since Magento does not have any core classes which provide an image selector for widgets, I decided to create my own. There are a few other image selectors online that I found but none of them fully worked so this is my working solution.

Building an Image Selector for Widgets

We are going to build an image selector that you can use in widgets. First, you specify that your parameter will use your new widget by adding the following to your widget.xml:

            <parameter xsi:type="block" name="background_image" visible="true" sort_order="10">
                <label translate="true">Background Image</label>
                <block class="Dmatthew\WidgetParameters\Block\Adminhtml\Widget\Type\ImageChooser">
                    <data>
                        <item name="button" xsi:type="array">
                            <item name="open" xsi:type="string">Choose Image...</item>
                        </item>
                    </data>
                </block>
            </parameter>

What we are doing here is creating a parameter for our widget for background image. The important piece here is the “ part, which tells Magento this parameter uses a custom block class to display our Background Image parameter. The other important piece is this:

<block class="Dmatthew\WidgetParameter\Block\Adminhtml\Widget\Type\ImageChooser">
...
</block>

This is where we define what block class to use.

The ImageChooser Block Class

<?php
namespace Dmatthew\WidgetParameters\Block\Adminhtml\Widget\Type;

use Magento\Backend\Block\Template;
use Magento\Framework\Data\Form\Element\AbstractElement;
use Magento\Backend\Block\Template\Context;
use Magento\Framework\Data\Form\Element\Factory;

/**
 * Class ImageChooser
 */
class ImageChooser extends Template
{
    /**
     * @var Factory
     */
    protected $elementFactory;

    /**
     * @param Context $context
     * @param Factory $elementFactory
     * @param array $data
     */
    public function __construct(Context $context, Factory $elementFactory, $data = [])
    {
        $this->elementFactory = $elementFactory;
        parent::__construct($context, $data);
    }

    /**
     * Prepare chooser element HTML
     *
     * @param AbstractElement $element
     * @return AbstractElement
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function prepareElementHtml(AbstractElement $element)
    {
        $config = $this->_getData('config');
        $onInsertUrl = $this->getUrl('dmatthew_widgettypes/wysiwyg_images/onInsert');
        $sourceUrl = $this->getUrl('cms/wysiwyg_images/index',
            ['target_element_id' => $element->getId(), 'on_insert_url' => $onInsertUrl]);
        /** @var \Magento\Backend\Block\Widget\Button $chooser */
        $chooser = $this->getLayout()->createBlock('Magento\Backend\Block\Widget\Button')
            ->setType('button')
            ->setClass('btn-chooser')
            ->setLabel($config['button']['open'])
            ->setOnClick('MediabrowserUtility.openDialog(\'' . $sourceUrl . '\', 0, 0, "Insert File...", {})')
            ->setDisabled($element->getReadonly());
        /** @var \Magento\Framework\Data\Form\Element\Text $input */
        $input = $this->elementFactory->create("text", ['data' => $element->getData()]);
        $input->setId($element->getId());
        $input->setForm($element->getForm());
        $input->setClass("widget-option input-text admin__control-text");
        if ($element->getRequired()) {
            $input->addClass('required-entry');
        }
        $element->setData('after_element_html', $input->getElementHtml()
            . $chooser->toHtml() . "require(['mage/adminhtml/browser']);");
        $element->setValue('');  // Hides the additional label that gets added.
        return $element;
    }
}

This class creates a button which when clicked will open a dialog using the MediabrowserUtility JavaScript function. The dialog displays the standard WYSIWYG image selector that is used in CMS Blocks and Pages. Much of this came from a GitHub Gist. The biggest problem I ran into was that Magento inserts the image using its {{media url=”…”}} syntax, which does not play well with widgets because you end up with something like this:

{{widget type="…" background_image="{{media url="wysiwyg/photo.jpg"}}

There are multiple sets of double quotes so it breaks, and I really wanted the full URL of the image. So I ended up creating a new controller path, dmatthew_widgettypes/wysiwyg_images/onInsert, which just output the actual URL of the image instead of the {{media …}} directive or a backend url which looks something ugly like

example.com/index.php/admin/cms_wysiwyg/directive/___directive/jsn3487gb4ugf84fn2fu4b373cn29duybdvjrng9834f23bydcbsvkjrtnr9etg438vrfu3fn2m3k3gy/key/kecnjmbejnf3928hufvbmgnjytmj9j43736drvcbvnetihj5g7gybrjbv/

This url does return the image, but its not as helpful as the actual image url.

You end up with something that looks like this:
ImageChooserWidgetParameter

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s