如何在Magento小部件配置中允许多个产品选择?

时间:2012-11-21 12:48:46

标签: php magento-1.6 magento

我正在尝试实现嵌入式小部件。管理员将能够配置此窗口小部件并将其嵌入到WYSIWYG编辑器中。许多配置选项中有两个是应该显示在前端和类别列表中的产品列表。

我想通过“ adminhtml / catalog_product_widget_chooser ”和“ adminhtml / catalog_category_widget_chooser ”来允许此选择。我尝试使用Web上提供的稀疏文档来实现这些小部件,但我设法完成的只是选择一个产品或选择一个类别的实现。我需要多选行为。

据我所知,目前的实施不允许多选的可能性。我检查了类和grid.phtml模板的代码,它接缝很糟糕,并且不能超出当前的使用意图。例如,您可以假设为widget参数初始化辅助块以允许多个select:

<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模板只显示“搜索”和“重置过滤器”按钮。并没有添加另一个按钮的处理。例如,这里是负责打印按钮html的默认代码:

public function getMainButtonsHtml()
{
    $html = '';
    if($this->getFilterVisibility()){
        $html.= $this->getResetFilterButtonHtml();
        $html.= $this->getSearchButtonHtml();
    }
    return $html;
}

默认情况下,只打印这两个按钮。

所以我基于上面提到的两个实现开始了我自己的实现,它变得丑陋,最终可能会成为一个难以维护的复制意大利面。我原则上认为,如果事情看起来很难看,那么我做错了。

是否有一种直接的方法可以使用网格小部件在小部件配置屏幕上实现多个产品和多个类别选择?

5 个答案:

答案 0 :(得分:5)

我找到了一种快速方法,可以使用基于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

答案 1 :(得分:4)

我已经添加了这个问题的答案。 Implement multiple product chooser widget 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()函数,该函数将帮助&#34;选择&#34;选中/选中的产品。

/**
 * 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 for checkbox checked / unchecked

/**
 * Checkbox Check JS Callback
 *
 * @return string
 */
public function getCheckboxCheckCallback()
{
    if ($this->getUseMassaction())
    {
        return "function (grid, element) {
            $(grid.containerId).fire('product:changed', {element: element});                 
        }";
    }
}

JS for Row / Product Clicked / Checked / Selected

/**
 * 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;
}

用于使用产品ID准备POST元素的附加JS。

/**
 * 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

步骤:

  
      
  1. 导航到ADMIN面板中的CMS页面
  2.   
  3. 点击&#34;插入小工具&#34;在WYSIWYG编辑器
  4.   
  5. 选择窗口小部件类型 - 目录多个产品窗口小部件
  6.   
  7. 输入标题,产品数量
  8.   
  9. 选择一个模板(可以根据需要添加任意数量的模板)
  10.   
  11. 点击&#34;选择产品&#34;按钮
  12.   
  13. 从GRID中选择产品
  14.   
  15. 点击&#34;选择所选产品&#34;按钮
  16.   

希望这有助于某人!

快乐编码......

答案 2 :(得分:2)

看起来你并不是第一个为此开发自己的实现的人。

David Manners似乎用他的Manners_Widgets解决了同样的问题。

  

Manners_Widgets扩展的功能:

     
      
  • 多个产品和类别选择
  •   

我没有与David联系过,也没有使用过此解决方案,因此无法对此代码的质量(或完整性)发表评论......但如果您还没有看到此解决方案,则可能会节省你有一段时间(或者最糟糕的是,在这个问题上给你一个合作联系点)。

希望这对你有所帮助,祝你好运!

答案 3 :(得分:0)

这里有一个快速修复:不使用产品小部件选择器,但使用文本字段而不是允许逗号分隔的SKU。

然后在你的代码中爆炸skus并通过sku获取产品。将其返回到您的模板。更容易:)

答案 4 :(得分:0)