Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>There are a couple reason why it doesn't save/upload the image:</p> <ul> <li>The form <code>enctype</code> needs to be "<code>multipart/form-data</code>" for a file upload to work</li> <li>Even if you change the form <code>enctype</code> to "<code>multipart/form-data</code>" you will notice if you monitor the requests that it gets POST'ed as "<code>application/x-www-form-urlencoded</code>" this is because it is done through ajax and ajax by itself can't process a file upload, you need to process them separately.</li> </ul> <p>I have successfully implemented a "Insert Image" button which initialises the <code>Media Library</code> dialogue where you can browse your server for images and/or upload images.</p> <p>Once the user clicks "Insert File" it inserts the full image url into a textbox in the widget so it's passed along like a normal field to your template.</p> <p>This is how I achieved it:</p> <p>In your widget.xml specify a new node:</p> <pre><code>&lt;image translate="label"&gt; &lt;label&gt;Image&lt;/label&gt; &lt;visible&gt;1&lt;/visible&gt; &lt;required&gt;1&lt;/required&gt; &lt;type&gt;label&lt;/type&gt; &lt;helper_block&gt; &lt;type&gt;widgets/cms_wysiwyg_images_chooser&lt;/type&gt; &lt;data&gt; &lt;button translate="open"&gt; &lt;open&gt;Insert Image...&lt;/open&gt; &lt;/button&gt; &lt;/data&gt; &lt;/helper_block&gt; &lt;/image&gt; </code></pre> <p>The helper block type <code>&lt;type&gt;widgets/cms_wysiwyg_images_chooser&lt;/type&gt;</code> is a custom class, so you can change it to anything you want as long as you create the class/files correctly.</p> <pre><code>&lt;?php class Stackoverflow_Widgets_Block_Cms_Wysiwyg_Images_Chooser extends Mage_Adminhtml_Block_Template { public function prepareElementHtml(Varien_Data_Form_Element_Abstract $element) { $config = $this-&gt;getConfig(); $chooseButton = $this-&gt;getLayout()-&gt;createBlock('adminhtml/widget_button') -&gt;setType('button') -&gt;setClass('scalable btn-chooser') -&gt;setLabel($config['button']['open']) -&gt;setOnclick('MediabrowserUtility.openDialog(\''.$this-&gt;getUrl('*/cms_wysiwyg_images/index', array('target_element_id' =&gt; $element-&gt;getName())).'\')') -&gt;setDisabled($element-&gt;getReadonly()); $text = new Varien_Data_Form_Element_Text(); $text-&gt;setForm($element-&gt;getForm()) -&gt;setId($element-&gt;getName()) -&gt;setName($element-&gt;getName()) -&gt;setClass('widget-option input-text'); if ($element-&gt;getRequired()) { $text-&gt;addClass('required-entry'); } if ($element-&gt;getValue()) { $text-&gt;setValue($element-&gt;getValue()); } $element-&gt;setData('after_element_html', $text-&gt;getElementHtml().$chooseButton-&gt;toHtml()); return $element; } } ?&gt; </code></pre> <p>And that is it! You should now have a new field in your widget options called "Image" with a textbox and a button in which you can insert the url to an image on your server and display it from your template.</p> <p>A quick explanation of how it works:</p> <p>A button is created that has an <code>onclick</code> function that calls the <code>Media Library</code> dialogue by calling <code>MediabrowserUtility.openDialog()</code> which along is passed the parameter <code>target_element_id</code> which tells media library what element to set the value in once they user clicks "<code>Insert File</code>" so we simply pass along the <code>id</code> of our textbox in the widget for it to receive the url of the image that the user selected.</p> <p>Hope this helps someone as I couldn't find any resources out there that explained how to do it so I spent quite a while digging through Magento to work it all out :)</p> <p>What I would like to do in the future is have it so it displays the image after you select it in the widget, and it stores the url in a hidden field, but having an <code>onchange</code> bind is not fired when the value is set to the element from <code>js/mage/adminhtml/browser.js</code> in the <code>insert</code> function, so without changing the core files it is a lot harder to do. I thought about playing around with when the form gets focus again after the <code>Media Library</code> closes or a timer (pretty dodgey but would work), but I have other things to move on to and may come back to it later!</p> <p><strong>UPDATE:</strong></p> <p>The URL's that the <code>Media Library</code> generates are like so:</p> <p><code>http://www.yourwebsite.com/index.php/admin/cms_wysiwyg/directive/___directive/e3ttZWRpYSB1cmw9Ind5c2l3eWcvd2lkZ2V0cy9iYW5uZXIvaG9tZXBhZ2UvZm9yZWdyb3VuZC9maXNoLXRhbmsucG5nIn19/key/e8167e3884e40b97d8985e7b84e7cbc7875f134e5f7e5946c9c2a482d0279762/</code></p> <p>Which are a cached image, and only work if the user is an admin. Stupid? Yes. If you insert the same image in to a CMS page when the html is generated for output it converts it to the original url on the server accessible via <code>/media/wysiwyg/path/to/file/photo.jpg</code>. We need the original url to show to the user, so what we can do is hook into the function that generates the widget html (when you click "Insert Widget") and look for <code>/admin/cms_wysiwyg/directive/___directive/</code> and replace it with the original URL to the image as the CMS page does.</p> <p>In your <code>config.xml</code> for your custom widgets:</p> <pre><code>&lt;global&gt; &lt;models&gt; &lt;widget&gt; &lt;rewrite&gt; &lt;widget&gt;Stackoverflow_Widgets_Model_Widget&lt;/widget&gt; &lt;/rewrite&gt; &lt;/widget&gt; &lt;/models&gt; &lt;/global&gt; </code></pre> <p>Then create the model Widget <code>code\local\Stackoverflow\Widgets\Model\Widget.php</code>:</p> <pre><code>&lt;?php class Stackoverflow_Widgets_Model_Widget extends Mage_Widget_Model_Widget { public function getWidgetDeclaration($type, $params = array(), $asIs = true) { foreach($params as $k =&gt; $v){ if(strpos($v,'/admin/cms_wysiwyg/directive/___directive/') !== false){ $parts = explode('/',parse_url($v, PHP_URL_PATH)); $key = array_search('___directive', $parts); if($key !== false){ $directive = $parts[$key+1]; $src = Mage::getModel('core/email_template_filter')-&gt;filter(Mage::helper('core')-&gt;urlDecode($directive)); if(!empty($src)){ $params[$k] = parse_url($src, PHP_URL_PATH); } } } } return parent::getWidgetDeclaration($type, $params, $asIs); } } </code></pre> <p>Which overrides the <code>getWidgetDeclaration</code> function which is called every time a the widget output is produced for a textarea/wysiwyg and looks through all the parameters and if it finds an image that is linked to the admin cache it will find out the original image and overwrite the variable in the array and call the original function with the parameters.</p> <p>If the cached image is not found the function will work as normal.</p> <p><strong>UPDATE: 13/09/2012</strong></p> <p>As Jonathan Day pointed out you have to overwrite <code>Mage_Widget_Model_Widget_Instance</code> also if you want it to work in a Widget Instance.</p> <p>I haven't had the need to add an image to a widget through a Widget Instance until now and was confused why my function didn't work, until I investigated and realised the "popup" widget instances use <code>Mage_Widget_Model_Widget</code> and the widget instances that are used on a Widget options tab (no popup) are <code>Mage_Widget_Model_Widget_Instance</code> and do not extend <code>Mage_Widget_Model_Widget</code> so do not inherit the functionality.</p> <p>To add the functionality to <code>Mage_Widget_Model_Widget_Instance</code> simply add the line <code>&lt;widget_instance&gt;Petbarn_Widgets_Model_Widget_Instance&lt;/widget_instance&gt;</code> to your <code>config.xml</code> so it will look like:</p> <pre><code>&lt;global&gt; &lt;models&gt; &lt;widget&gt; &lt;rewrite&gt; &lt;widget&gt;Stackoverflow_Widgets_Model_Widget&lt;/widget&gt; &lt;widget_instance&gt;Stackoverflow_Widgets_Model_Widget_Instance&lt;/widget_instance&gt; &lt;/rewrite&gt; &lt;/widget&gt; &lt;/models&gt; &lt;/global&gt; </code></pre> <p>Then create the model Instance <code>code\local\Stackoverflow\Widgets\Model\Widget\Instance.php</code>:</p> <pre><code>&lt;?php class Petbarn_Widgets_Model_Widget_Instance extends Mage_Widget_Model_Widget_Instance { protected function _beforeSave() { if (is_array($this-&gt;getData('widget_parameters'))) { $params = $this-&gt;getData('widget_parameters'); foreach($params as $k =&gt; $v){ if(strpos($v,'/cms_wysiwyg/directive/___directive/') !== false){ $parts = explode('/',parse_url($v, PHP_URL_PATH)); $key = array_search('___directive', $parts); if($key !== false){ $directive = $parts[$key+1]; $src = Mage::getModel('core/email_template_filter')-&gt;filter(Mage::helper('core')-&gt;urlDecode($directive)); if(!empty($src)){ $params[$k] = parse_url($src, PHP_URL_PATH); } } } } $this-&gt;setData('widget_parameters', $params); } return parent::_beforeSave(); } } </code></pre> <p>This time we are modifying the <code>widget_parameters</code> data at the start of the <code>_beforeSave()</code> function so it fixes up the url before it saves it.</p> <p>You also have to ensure the <code>/js/mage/adminhtml/browser.js</code> javascript file is included (in my case it wasn't) to get the <code>MediabrowserUtility</code> functionality.</p> <p>To ensure it is included, the easiest way is to include it for all of admin (didn't spend much time targeting it better).</p> <p>Create a <code>local.xml</code> for adminhtml layouts (if you don't already have one): <code>app\design\adminhtml\default\default\layout\local.xml</code></p> <pre><code>&lt;?xml version="1.0"?&gt; &lt;layout version="0.1.0"&gt; &lt;default&gt; &lt;reference name="head"&gt; &lt;action method="addJs"&gt;&lt;script&gt;mage/adminhtml/browser.js&lt;/script&gt;&lt;/action&gt; &lt;/reference&gt; &lt;/default&gt; &lt;/layout&gt; </code></pre> <p>This will make Magento include <code>js/mage/adminhtml/browser.js</code> on every page of admin so <code>MediabrowserUtility</code> will always be available.</p> <p><em>NOTE: I'm using Magento Enterprise 1.11.2.0 so I'm not sure how it behaves on other versions.</em></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload