Как разрешить выбор нескольких продуктов в конфигурации виджета Magento?
Я пытаюсь реализовать встроенный виджет. Администраторы смогут настроить этот виджет и встроить его в редактор WYSIWYG. Два из многих параметров конфигурации - это список продуктов, которые должны отображаться в интерфейсе и списке категорий.
Я хочу разрешить этот выбор с помощью adminhtml/catalog_product_widget_chooser "и" adminhtml/catalog_category_widget_chooser ". Я попытался реализовать эти виджеты с разреженной документацией, доступной в Интернете, но все, что мне удалось выполнить, - это реализация для выбора одного продукта или выбора одной категории. Мне нужно многосегментное поведение.
Насколько я могу судить, для текущей реализации не разрешена возможность многократного выбора. Я проверил код для обоих классов и шаблон grid.phtml, и он швы он плохо написан и не расширяется за пределами текущего намерения использования. Например, так вы предположили бы инициализировать вспомогательный блок для параметра виджета, чтобы разрешить множественный выбор:
<helper_block>
<type>adminhtml/catalog_product_widget_chooser</type>
<data>
<button translate="open">
<open>Select Products...</open>
</button>
<use_massaction>1</use_massaction>
</data>
</helper_block>
Но выбор продукта жестко закодирован для использования без массовых действий с этой частью кода:
public function prepareElementHtml(Varien_Data_Form_Element_Abstract $element)
{
$uniqId = Mage::helper('core')->uniqHash($element->getId());
$sourceUrl = $this->getUrl('*/catalog_product_widget/chooser', array(
'uniq_id' => $uniqId,
'use_massaction' => false,
));
...
И шаблон grid.phtml, который должен иметь какую-то кнопку для подтверждения множественного выбора, просто показывает кнопки "Поиск" и "Reset фильтр". И нет необходимости добавлять другую кнопку. Например, здесь используется код по умолчанию для печати кнопки html:
public function getMainButtonsHtml()
{
$html = '';
if($this->getFilterVisibility()){
$html.= $this->getResetFilterButtonHtml();
$html.= $this->getSearchButtonHtml();
}
return $html;
}
По умолчанию будут напечатаны только эти две кнопки.
Итак, я начал свою собственную реализацию на основе двух реализаций, упомянутых выше, и она становится уродливой и может закончиться как незаменимый беспорядок копий-макарон. И я работаю по принципу: если что-то начинает выглядеть уродливо, я делаю что-то неправильно.
Итак, существует ли простой способ реализовать множественный выбор продуктов и нескольких категорий на экране конфигурации виджета с помощью виджета сетки?
Ответы
Ответ 1
Я нашел быстрый способ получить мультиселекцию категории по параметрам виджета с использованием исходной модели на основе adminhtml/system_config_source_category
. Я удалил фильтр корневого уровня и добавил отступ для подкатегорий.
widget.xml:
<widgets>
<my_widget type="mymodule/block" translate="name" module="mymodule">
<name>Widget with Multiselect Categories</name>
<parameters>
<category_ids translate="label description">
<visible>1</visible>
<required>1</required>
<label>Categories</label>
<type>multiselect</type>
<source_model>mymodule/system_config_source_category</source_model>
</category_ids>
</parameters>
</my_widget>
</widgets>
Исходная модель:
class Mynamespace_Mymodule_Model_System_Config_Source_Category
{
public function toOptionArray()
{
$collection = Mage::getResourceModel('catalog/category_collection');
$collection->addAttributeToSelect('name')
->addFieldToFilter('path', array('neq' => '1'))
->load();
$options = array();
foreach ($collection as $category) {
$depth = count(explode('/', $category->getPath())) - 2;
$indent = str_repeat('-', max($depth * 2, 0));
$options[] = array(
'label' => $indent . $category->getName(),
'value' => $category->getId()
);
}
return $options;
}
}
Результат:
![Multiselect widget parameter]()
Источник: http://www.magentocommerce.com/knowledge-base/entry/tutorial-creating-a-magento-widget-part-2
Ответ 2
Я добавил ответ на этот вопрос.
Внедрить виджет выбора продукта Magento
Я проверил модуль, который находится под https://github.com/dio5/magento-multiproducts-widget.
Используйте опцию FORK вместо ZIP.
Он работает и дает нам точные результаты, например, выбор нескольких продуктов в WIDGET. Если есть какие-либо ошибки, дайте мне знать.
Сообщите мне, если это сработает для вас.
Спасибо!
[Редактирование моего предыдущего комментария по запросу здесь прямо)
/Namespace/Modulename/etc/widget.xml
<widgets>
<catalog_product_multiproducts type="namespace_modulename/widget_catalog_product_multiproducts" translate="name description" module="namespace_modulename">
<name>Catalog Multiple Products Widget</name>
<description>Select multiple products for display</description>
<parameters>
<title translate="label">
<visible>1</visible>
<label>Title</label>
<type>text</type>
</title>
<products_count translate="label">
<visible>1</visible>
<required>1</required>
<label>No of Products</label>
<type>text</type>
</products_count>
<ids translate="label">
<visible>1</visible>
<required>1</required>
<label>Products</label>
<type>label</type>
<helper_block>
<type>namespace_modulename/adminhtml_catalog_product_widget_multiproducts_chooser</type>
<data>
<button translate="open">
<open>Select Products...</open>
</button>
</data>
</helper_block>
<sort_order>10</sort_order>
</ids>
<template translate="label description">
<required>1</required>
<visible>1</visible>
<label>Product Carousel Template</label>
<type>text</type>
<value>catalog/product/widget/products_carousel.phtml</value>
<values>
<default translate="label"> <value>catalog/product/widget/products_carousel.phtml</value>
<label>New Products Grid Template</label>
</default>
<list translate="label">
<value>catalog/product/widget/new/content/new_list.phtml</value>
<label>New Products List Template</label>
</list>
</values>
<description>Template path cannot be changed/updated</description>
</template>
</parameters>
</catalog_product_multiproducts>
</widgets>
/NameSpace/ModuleName/Block/Adminhtml/Catalog/Product/MultiProducts/Chooser.php
Эта функция вызовет функцию DOCHOOSE(), которая поможет "Выбрать" проверенные/выбранные продукты.
/**
* prepare layout for products grid
*
* @return type Mage_Adminhtml_Block_Catalog_Product_Widget_Chooser
*/
protected function _prepareLayout()
{
$this->setChild('choose_button', $this->getLayout()->createBlock('adminhtml/widget_button')
->setData(array(
'label' => Mage::helper('adminhtml')->__('Choose Selected Products'),
'onclick' => $this->getJsObjectName() . '.doChoose()'
))
);
return parent::_prepareLayout();
}
Следующая функция должна использоваться для подготовки элемента продукта HTML в формате {1} {2}
/**
* Prepare chooser element HTML
*
* @param Varien_Data_Form_Element_Abstract $element Form Element
* @return Varien_Data_Form_Element_Abstract
*/
public function prepareElementHtml(Varien_Data_Form_Element_Abstract $element)
{
$uniqueId = Mage::helper('core')->uniqHash($element->getId());
$sourceUrl = $this->getUrl('*/multiproducts/chooser', array(
'uniq_id' => $uniqueId,
'use_massaction' => true,
));
$chooser = $this->getLayout()->createBlock('widget/adminhtml_widget_chooser')
->setElement($element)
->setTranslationHelper($this->getTranslationHelper())
->setConfig($this->getConfig())
->setFieldsetId($this->getFieldsetId())
->setSourceUrl($sourceUrl)
->setUniqId($uniqueId);
if ($element->getValue())
{
$label = "";
$ids = explode('}{', $element->getValue());
$cleanIds = array();
foreach ($ids as $id)
{
$id = str_replace('{', '', $id);
$id = str_replace('}', '', $id);
$cleanIds[] = $id;
}
$products = $this->_getProductsByIDs($cleanIds);
if ($products)
{
$label .= '<ul>';
foreach ($products as $product)
{
$label .= '<li>' . $product->getName() . '</li>';
}
$label .= '</ul>';
$chooser->setLabel($label);
}
}
$element->setData('after_element_html', $chooser->toHtml());
return $element;
}
JS для флажка отмечен/снят флажок
/**
* Checkbox Check JS Callback
*
* @return string
*/
public function getCheckboxCheckCallback()
{
if ($this->getUseMassaction())
{
return "function (grid, element) {
$(grid.containerId).fire('product:changed', {element: element});
}";
}
}
JS для строки/продукта, нажата/проверена/выбрана
/**
* Grid Row JS Callback
*
* @return string
*/
public function getRowClickCallback()
{
if (!$this->getUseMassaction())
{
$chooserJsObject = $this->getId();
return '
function (grid, event) {
var trElement = Event.findElement(event, "tr");
var productId = trElement.down("td").innerHTML;
var productName = trElement.down("td").next().next().innerHTML;
var optionLabel = productName;
var optionValue = "product/" + productId.replace(/^\s+|\s+$/g,"");
if (grid.categoryId) {
optionValue += "/" + grid.categoryId;
}
if (grid.categoryName) {
optionLabel = grid.categoryName + " / " + optionLabel;
}
' . $chooserJsObject . '.setElementValue(optionValue);
' . $chooserJsObject . '.setElementLabel(optionLabel);
' . $chooserJsObject . '.close();
}
';
}
}
JS-код, если пользователь заинтересован в выборе продуктов из определенной категории.
/**
* Category Tree node onClick listener js function
*
* @return string
*/
public function getCategoryClickListenerJs()
{
$js = '
function (node, e) {
{jsObject}.addVarToUrl("category_id", node.attributes.id);
{jsObject}.reload({jsObject}.url);
{jsObject}.categoryId = node.attributes.id != "none" ? node.attributes.id : false;
{jsObject}.categoryName = node.attributes.id != "none" ? node.text : false;
}
';
$js = str_replace('{jsObject}', $this->getJsObjectName(), $js);
return $js;
}
Дополнительный JS для подготовки элемента POST с идентификаторами продукта.
/**
* return additional JS for controls
*
* @return JS
*/
public function getAdditionalJavascript()
{
$chooserJsObject = $this->getId();
$js = '
{jsObject}.initChecked = function() {
$$("#' . $chooserJsObject . '_table tbody input:checkbox").each(function(element, i) {
var values = ' . $chooserJsObject . '.getElementValue();
var capture = values.replace("{"+element.value+"}", "match");
var searchValue = "match";
if(capture.search(searchValue) != -1)
{
element.checked = true;
}
});
}
{jsObject}.initChecked();
var values = ' . $chooserJsObject . '.getElementValue();
$("' . $chooserJsObject . '").insert({bottom: "<div class=\"filter\"><input type=\"hidden\" value=\"+values+\" name=\"selected_products\" /></div>"});
$$("#' . $chooserJsObject . '_table tbody input:checkbox").invoke("observe", "change", function(event) {
var element = Event.element(event);
var label = element.up("td").next().next().next().innerHTML;
label = label.replace(/^\s\s*/, "").replace(/\s\s*$/, "");
if(element.checked)
{
{jsObject}.addValue(element.value);
{jsObject}.addLabel(label);
} else {
{jsObject}.removeValue(element.value);
{jsObject}.removeLabel(label);
}
});
{jsObject}.removeValue = function(value) {
var currentValue = ' . $chooserJsObject . '.getElementValue();
currentValue = currentValue.replace("{"+value+"}", "");
' . $chooserJsObject . '.setElementValue(currentValue);
}
{jsObject}.addValue = function(value) {
var currentValue = ' . $chooserJsObject . '.getElementValue();
currentValue = currentValue.replace("{"+value+"}", "");
currentValue = currentValue + "{"+value+"}";
' . $chooserJsObject . '.setElementValue(currentValue);
}
{jsObject}.removeLabel = function(label) {
var currentLabel = ' . $chooserJsObject . '.getElementLabelText();
currentLabel = currentLabel.replace("<li>"+label+"</li>", "");
' . $chooserJsObject . '.setElementLabel(currentLabel);
}
{jsObject}.addLabel = function(label) {
var currentLabel = ' . $chooserJsObject . '.getElementLabelText();
if(currentLabel.search("ul") != -1)
{
currentLabel = currentLabel.replace("</ul>", "");
currentLabel = currentLabel.replace("<li>"+label+"</li>", "");
} else {
currentLabel = "<ul>";
}
currentLabel = currentLabel +"<li>"+label+"</li></ul>";
' . $chooserJsObject . '.setElementLabel(currentLabel);
}
{jsObject}.doChoose = function(node,e) {
' . $chooserJsObject . '.close();
}
';
$js = str_replace('{jsObject}', $this->getJsObjectName(), $js);
return $js;
}
Вышеупомянутые основные функции помогут вам выбрать несколько продуктов из GRID во всплывающем окне.
В коде есть код, который можно проверить здесь: https://github.com/dio5/magento-multiproducts-widget
Шаги:
- Перейдите на страницу CMS на панели ADMIN.
- Нажмите "Вставить виджет" в редакторе WYSIWYG
- Выберите тип виджета - Каталог нескольких виджетах продуктов
- Введите название, количество продуктов
- Выберите шаблон (в качестве опции можно добавить как можно больше шаблонов)
- Нажмите кнопку "Выбрать продукты"
- Выберите продукты из GRID
- Нажмите кнопку "Выбрать выбранные продукты"
Надеюсь, это поможет кому-то!
Счастливое кодирование...
Ответ 3
Похоже, вы не первый, кто пошел по пути разработки собственной реализации для этого.
Дэвид Мэннерс, похоже, решил ту же проблему, с его Manners_Widgets.
Особенности расширения Manners_Widgets:
- Множественный выбор для продуктов и категорий
У меня не было контакта с Дэвидом, и я не использовал это решение, поэтому не могу комментировать качество (или полноту) этого кода... но если вы еще не видели это решение, оно может сэкономить вы некоторое время (или, в худшем случае, дадите вам контакт для совместной работы по этой проблеме).
Надеюсь, это поможет вам, удачи в этом!
Ответ 4
Вот быстрое решение: не используйте выборщик виджетов продукта, но вместо этого используйте текстовое поле, которое позволяет разделять запятыми.
Затем в вашем коде взорвите skus и получите продукты по sku. Верните это в свой шаблон. Гораздо проще:)
Ответ 5
Попробуйте https://github.com/dio5/magento-multiproducts-widget.
Кажется очень полезным.