Существует несколько причин, по которым изображение не сохраняется / не загружается:
- Форма
enctype
должна быть "multipart/form-data
" для загрузки файла на работу
- Даже если вы измените форму
enctype
на "multipart/form-data
", вы заметите, что если вы отслеживаете запросы на получение POST'а как "application/x-www-form-urlencoded
", то это потому, что это выполняется через ajax и ajax отдельно. невозможно обработать загрузку файла, вам нужно обрабатывать их отдельно.
Я успешно реализовал кнопку «Вставить изображение», которая инициализирует диалоговое окно Media Library
, где вы можете просматривать изображения и / или загружать изображения на сервер.
Как только пользователь нажимает «Вставить файл», он вставляет полный URL-адрес изображения в текстовое поле в виджете, чтобы он передавался в шаблон как обычное поле.
Вот как я этого добился:
В вашем widget.xml укажите новый узел:
<image translate="label">
<label>Image</label>
<visible>1</visible>
<required>1</required>
<type>label</type>
<helper_block>
<type>widgets/cms_wysiwyg_images_chooser</type>
<data>
<button translate="open">
<open>Insert Image...</open>
</button>
</data>
</helper_block>
</image>
Вспомогательный тип блока <type>widgets/cms_wysiwyg_images_chooser</type>
является пользовательским классом, поэтому вы можете изменить его на любой, если хотите правильно создать класс / файлы.
<?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->getConfig();
$chooseButton = $this->getLayout()->createBlock('adminhtml/widget_button')
->setType('button')
->setClass('scalable btn-chooser')
->setLabel($config['button']['open'])
->setOnclick('MediabrowserUtility.openDialog(\''.$this->getUrl('*/cms_wysiwyg_images/index', array('target_element_id' => $element->getName())).'\')')
->setDisabled($element->getReadonly());
$text = new Varien_Data_Form_Element_Text();
$text->setForm($element->getForm())
->setId($element->getName())
->setName($element->getName())
->setClass('widget-option input-text');
if ($element->getRequired()) {
$text->addClass('required-entry');
}
if ($element->getValue()) {
$text->setValue($element->getValue());
}
$element->setData('after_element_html', $text->getElementHtml().$chooseButton->toHtml());
return $element;
}
}
?>
И это все! Теперь у вас должно появиться новое поле в настройках вашего виджета под названием «Изображение» с текстовым полем и кнопкой, в которую вы можете вставить URL-адрес изображения на вашем сервере и отобразить его из вашего шаблона.
Краткое объяснение того, как это работает:
Создается кнопка, которая имеет функцию onclick
, которая вызывает диалог Media Library
, вызывая MediabrowserUtility.openDialog()
, которому передается параметр target_element_id
, который сообщает библиотеке мультимедиа, в какой элемент установить значение, когда пользователь щелкает «Insert File
», поэтому мы просто передаем id
нашего текстового поля в виджете, чтобы оно получило URL изображения, выбранного пользователем.
Надеюсь, это кому-нибудь поможет, так как я не смог найти там никаких ресурсов, объясняющих, как это сделать, поэтому я потратил довольно много времени, копаясь в Magento, чтобы решить все это:)
В будущем я хотел бы сделать так, чтобы оно отображало изображение после его выбора в виджете и сохраняло URL в скрытом поле, но привязка onchange
не срабатывает, когда значение устанавливается на элемент из js/mage/adminhtml/browser.js
в функции insert
, поэтому без изменения основных файлов сделать это намного сложнее. Я думал о том, чтобы поиграться, когда форма снова сфокусируется после закрытия Media Library
или таймера (довольно хитро, но сработает), но у меня есть другие вещи, к которым можно перейти, и я могу вернуться к нему позже!
UPDATE:
URL, которые генерирует Media Library
, выглядят так:
http://www.yourwebsite.com/index.php/admin/cms_wysiwyg/directive/___directive/e3ttZWRpYSB1cmw9Ind5c2l3eWcvd2lkZ2V0cy9iYW5uZXIvaG9tZXBhZ2UvZm9yZWdyb3VuZC9maXNoLXRhbmsucG5nIn19/key/e8167e3884e40b97d8985e7b84e7cbc7875f134e5f7e5946c9c2a482d0279762/
Кэшированное изображение, которое работает только в том случае, если пользователь является администратором. Глупый? Да. Если вы вставляете то же изображение на страницу CMS, когда HTML-файл генерируется для вывода, он преобразует его в исходный URL-адрес на сервере, доступном через /media/wysiwyg/path/to/file/photo.jpg
. Нам нужно показать исходный URL-адрес пользователю, поэтому мы можем подключиться к функции, которая генерирует HTML-виджет (когда вы нажимаете «Вставить виджет»), и найдите /admin/cms_wysiwyg/directive/___directive/
и замените его исходным URL-адресом на изображение, как на странице CMS.
В вашем config.xml
для ваших пользовательских виджетов:
<global>
<models>
<widget>
<rewrite>
<widget>Stackoverflow_Widgets_Model_Widget</widget>
</rewrite>
</widget>
</models>
</global>
Затем создайте модель виджета code\local\Stackoverflow\Widgets\Model\Widget.php
:
<?php
class Stackoverflow_Widgets_Model_Widget extends Mage_Widget_Model_Widget
{
public function getWidgetDeclaration($type, $params = array(), $asIs = true)
{
foreach($params as $k => $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')->filter(Mage::helper('core')->urlDecode($directive));
if(!empty($src)){
$params[$k] = parse_url($src, PHP_URL_PATH);
}
}
}
}
return parent::getWidgetDeclaration($type, $params, $asIs);
}
}
, которая переопределяет функцию getWidgetDeclaration
, которая вызывается каждый раз, когда вывод виджета создается для textarea / wysiwyg и просматривает все параметры, и если он находит изображение, связанное с кешем администратора, он обнаруживает Исходное изображение и перезаписать переменную в массиве и вызвать исходную функцию с параметрами.
Если кэшированное изображение не найдено, функция будет работать в обычном режиме.
ОБНОВЛЕНИЕ: 13.09.2012
Как отметил Джонатан Дэй, вы должны перезаписать Mage_Widget_Model_Widget_Instance
также, если вы хотите, чтобы он работал в экземпляре виджета.
До сих пор у меня не было необходимости добавлять изображение в виджет через инстанс виджета, и я не мог понять, почему моя функция не работает, пока я не исследовал и не понял, что экземпляры "всплывающих" виджетов используют Mage_Widget_Model_Widget
и экземпляры виджета, используемые на вкладке параметров виджета (без всплывающего окна), Mage_Widget_Model_Widget_Instance
и не расширяют Mage_Widget_Model_Widget
, поэтому не наследуют функциональность.
Чтобы добавить функциональность к Mage_Widget_Model_Widget_Instance
, просто добавьте строку <widget_instance>Petbarn_Widgets_Model_Widget_Instance</widget_instance>
к вашему config.xml
, чтобы она выглядела так:
<global>
<models>
<widget>
<rewrite>
<widget>Stackoverflow_Widgets_Model_Widget</widget>
<widget_instance>Stackoverflow_Widgets_Model_Widget_Instance</widget_instance>
</rewrite>
</widget>
</models>
</global>
Затем создайте экземпляр модели code\local\Stackoverflow\Widgets\Model\Widget\Instance.php
:
<?php
class Petbarn_Widgets_Model_Widget_Instance extends Mage_Widget_Model_Widget_Instance
{
protected function _beforeSave()
{
if (is_array($this->getData('widget_parameters'))) {
$params = $this->getData('widget_parameters');
foreach($params as $k => $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')->filter(Mage::helper('core')->urlDecode($directive));
if(!empty($src)){
$params[$k] = parse_url($src, PHP_URL_PATH);
}
}
}
}
$this->setData('widget_parameters', $params);
}
return parent::_beforeSave();
}
}
На этот раз мы модифицируем данные widget_parameters
в начале функции _beforeSave()
, чтобы она исправляла URL-адрес до его сохранения.
Вы также должны убедиться, что javascript-файл /js/mage/adminhtml/browser.js
включен (в моем случае его не было), чтобы получить функциональность MediabrowserUtility
.
Чтобы убедиться, что он включен, самый простой способ - включить его для всех администраторов (не тратя много времени на его настройку).
Создайте local.xml
для макетов adminhtml (если у вас его еще нет): app\design\adminhtml\default\default\layout\local.xml
<?xml version="1.0"?>
<layout version="0.1.0">
<default>
<reference name="head">
<action method="addJs"><script>mage/adminhtml/browser.js</script></action>
</reference>
</default>
</layout>
Это заставит Magento включать js/mage/adminhtml/browser.js
на каждой странице администратора, поэтому MediabrowserUtility
всегда будет доступен.
ПРИМЕЧАНИЕ: я использую Magento Enterprise 1.11.2.0, поэтому я не уверен, как он ведет себя в других версиях.