0

I've added 'p' tags to a textarea in a custom widget, but it seems like it breaks the edit functionality. In other words, after adding html tags the widget no longer shows up as a clickable element in the WYSIWIG, it renders out as text.

It looks like I can edit the attributes directly, but I'm setting this up for a client so need this to be as simple as possible. Is there any way I can add html tags and still retaing the clickable functionality to edit the widget values?

3

Note: It's not so simple to solve!

I can't mark as a duplicate, but I encountered the same problem and solved it on Stack Overflow: https://stackoverflow.com/questions/23925826/magento-widgets-truncate-fields-containing-quotes

In summary, the process involves extending the widget controller to encode and decode widget parameters on-the-fly.

Note to moderators: If someone knows how to migrate the SO post I reference to MSE, please do!


Update

Here's some code taken from the module I ultimately built out of the SO answer above.

Module Configuration

Setup an overload on the core widget controller:

# app/code/local/Namespace/Module/etc/config.xml
<config>
    <modules>
        <Namespace_Module>
            <version>0.0.1</version>
        </Namespace_Module>
    </modules>
    ...
    <admin>
        <routers>
            <yourmodule>
                <use>admin</use>
                <args>
                    <module>Namespace_Module</module>
                    <frontName>yourmodule</frontName>
                </args>
            </yourmodule>
            <adminhtml>
                <args>
                    <modules>
                        <yourmodule before="Mage_Widget_Adminhtml">Namespace_Module_Adminhtml</yourmodule>
                    </modules>
                </args>
            </adminhtml>
        </routers>
    </admin>
    ...
</config>

Widget Extensions

Here you have to extend the getData method to encode/decode widget params on-the-fly:

# app/code/local/Namespace/Module/Block/Widget.php

protected $_reservedData = array(
    'type', 'name_in_layout', 'area', 'module_name', 
    'name', '_is_changed', '_renderer_name'
);

...
public function getData($key = '', $index = null)
{
    // Check for decoded flag on widget, as needed with
    // custom preset configurations, widget instances, and
    // other cases where widget configuration is not
    // passed through the widget builder controller.
    if (parent::getData('is_data_decoded')) {
        // If already decoded, then return as-is
        return parent::getData($key, $index);
    }

    if ('' === $key) {
        $data = Mage::helper('yourmodule')->decodeWidgetValues($this->_data, $this->_reservedData);
    } else {
        $data = parent::getData($key, $index);

        if (is_scalar($data)) {
            $data = Mage::helper('yourmodule')->decodeWidgetValues($data, $this->_reservedData);
        }
    }

    return $data;
}
...

I re-factored this from the SO post by putting the encoding work into a helper. Notice the _reservedData property. These are data set on the widget that should have nothing to do with what we're concerned about encoding. These are standard block properties that we should never mess with.

Encoding Helper

Here's the work to handle encoding/decoding from a re-usable helper:

# app/code/local/Namespace/Module/Helper/Data.php
...
public function decodeWidgetValues($values, $ignore = array())
{
    if (!is_array($values)) {
        return base64_decode($values);
    }

    foreach ($values as $key => $value) {
        if ( is_scalar($value) && !in_array($key, $ignore) ) {
            $values[$key] = base64_decode($value);
        }
    }

    return $values;
}

public function encodeWidgetValues($values, $ignore = array())
{
    if ( !is_array($values) && !in_array($key, $ignore) ) {
        return base64_encode($values);
    }

    foreach ($values as $key => $value) {
        if (is_scalar($value)) {
            $values[$key] = base64_encode($value);
        }
    }

    return $values;
}
...

The benefit of a helper is revealed in our controller extension, where we are able to leverage encoding/decoding processes both in the frontend rendering of the widget and also in the translation into a widgetDirective in admin CMS editing.

Controller Extensions

# app/code/local/Namespace/Module/controllers/Adminhtml/WidgetController.php
require_once 'Mage/Widget/controllers/Adminhtml/WidgetController.php';

class Namespace_Module_Adminhtml_WidgetController 
    extends Mage_Widget_Adminhtml_WidgetController
{

    protected function _setOptions($request)
    {
        $optionsBlock = $this->getLayout()->getBlock('wysiwyg_widget.options');

        if (isset($request['widget_type'])) {
            $optionsBlock->setWidgetType($request['widget_type']);
        }

        if (isset($request['values']))  {
            // Decode only if type is your widget
            if ($optionsBlock->getWidgetType() == 'yourmodule/widget') {
                $request['values'] = Mage::helper('yourmodule')->decodeWidgetValues($request['values']);
            }

            $optionsBlock->setWidgetValues($request['values']);
        }

        return $this;
    }

    public function buildWidgetAction()
    {
        $type   = $this->getRequest()->getPost('widget_type');
        $params = $this->getRequest()->getPost('parameters', array());
        $asIs   = $this->getRequest()->getPost('as_is');

        // Encode all params for your widget
        if ($type == 'yourmodule/widget') {
            $params = Mage::helper('yourmodule')->encodeWidgetValues($params);
        }

        $html = Mage::getSingleton('widget/widget')->getWidgetDeclaration($type, $params, $asIs);

        $this->getResponse()
            ->setBody($html);
    }

    public function loadOptionsAction()
    {
        try {
            $this->loadLayout('empty');

            if ( ($paramsJson = $this->getRequest()->getParam('widget')) ) {
                $request = Mage::helper('core')->jsonDecode($paramsJson);

                if (is_array($request)) {
                    $this->_setOptions($request);
                }

                $this->renderLayout();
            }
        } catch (Mage_Core_Exception $e) {
            $result = array('error' => true, 'message' => $e->getMessage());

            $this->getResponse()
                ->setBody(Mage::helper('core')->jsonEncode($result));
        }
    }

}

Now in this class the keys are in loadOptions, where we extend from the parent method to decode the widget params before loading them into the widget editor dialog; and also in buildWidgetAction, where we convert the parameters into a useful widgetDirective for CMS editing.


So what you end up with is a widget directive with a bunch of garbled parameters, but at least they won't kill the widget:

{{widget type="yourmodule/widget" preset="c2hhcmVfcm91bmRfc2ltcGxlX3NtYWxs" name="c29jaWFsc2hhcmVfaW5zdGFuY2VfNTNjZTY0ZDU3Yzg5MA==" align="Y2VudGVy" before_widget_html="PGgzIHN0eWxlPSJtYXJnaW4tYm90dG9tOjhweDsiPiZuYnNwOzwvaDM+"}}

I might have missed some implementation details, but this should set you up well.

| improve this answer | |
  • So the first two functions I replace in WidgetController.php? Where does the third one, function getData() reside? – user2925994 Mar 6 '15 at 21:55
  • getData is an override on your widget block. Because widgets inherit ultimately from Varien_Object, you'll be overriding every data getter call, whether explicitly on getData or through a magic operation (getSomeValue -> getData('some_value')). And in this way you can encode or decode everything. – Rick Buczynski Mar 6 '15 at 22:03
  • @user2925994 I updated my answer for more details – Rick Buczynski Mar 6 '15 at 22:23
  • Hi Rick, Thank you for your patience. I'm pretty new to Magento and definitley stuggling a bit here. That widget declaration, does that go in Widget.php, or my specific widget (its and Event widget, so would that belong in Event.php?) – user2925994 Mar 6 '15 at 22:39
  • 1
    Thanks for the reference Rick, I'll go ahead and do my homework, think that's what its ging to take. I'm close, no WYSIWIG editor but the widget is encoding my tags and still maintaining clickable functionality which is really all I'm looking for. Didn't result in any errors, but now the widget content itself just isn't rendering. But I should be able to figure out from what you've posted. Thanks again! – user2925994 Mar 6 '15 at 23:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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