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.