Подтвердить что ты не робот

Как разрешить выбор нескольких продуктов в конфигурации виджета 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;
}

По умолчанию будут напечатаны только эти две кнопки.

Итак, я начал свою собственную реализацию на основе двух реализаций, упомянутых выше, и она становится уродливой и может закончиться как незаменимый беспорядок копий-макарон. И я работаю по принципу: если что-то начинает выглядеть уродливо, я делаю что-то неправильно.

Итак, существует ли простой способ реализовать множественный выбор продуктов и нескольких категорий на экране конфигурации виджета с помощью виджета сетки?

4b9b3361

Ответ 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. Верните это в свой шаблон. Гораздо проще:)