22

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

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

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

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

所以我基于上面提到的两个实现开始了我自己的实现,它变得越来越难看,最终可能会变成一团无法维护的复制面。而且我的工作原则是,如果事情开始变得丑陋,那么我做错了什么。

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

4

5 回答 5

5

我找到了一种使用基于adminhtml/system_config_source_category. 我删除了根级过滤器并为子类别添加了缩进。

小部件.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;
    }
}

结果:

多选小部件参数

资料来源: http: //www.magentocommerce.com/knowledge-base/entry/tutorial-creating-a-magento-widget-part-2

于 2013-10-10T17:32:53.343 回答
4

我已经添加了这个问题的答案。 实现多个产品选择器小部件 Magento

我检查了https://github.com/dio5/magento-multiproducts-widget下的模块。

使用 FORK 选项而不是下载 ZIP。

它有效并为我们提供了准确的结果,即 WIDGET 中的多个产品选择。如果有任何错误,请告诉我。

让我知道这是否适合你。

谢谢!

[编辑我之前的评论,根据代码的要求直接在这里]

/命名空间/模块名/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;
}

用于准备带有产品 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. 在管理面板中导航到 CMS 页面
  2. 在所见即所得编辑器中单击“插入小部件”
  3. 选择小部件类型 - 目录多个产品小部件
  4. 输入标题、产品数量
  5. 选择一个模板(可以根据需要添加任意数量的模板作为选项)
  6. 点击“选择产品”按钮
  7. 从 GRID 中选择产品
  8. 点击“选择所选产品”按钮

希望这对某人有帮助!

快乐的编码...

于 2016-01-12T11:49:18.200 回答
2

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

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

Manners_Widgets 扩展的特点:

  • 产品和类别的多项选择

我没有与大卫联系过,也没有使用过这个解决方案,所以不能评论这个代码的质量(或完整性)......但如果你还没有看到这个解决方案,它可能会为你节省一些时间(或者在最坏的情况下,给你一个联系点,以便在这个问题上进行合作)。

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

于 2013-03-24T06:00:06.770 回答
0

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

然后在您的代码中分解 sku 并按 sku 获取产品。将其返回到您的模板。容易得多:)

于 2013-06-20T18:10:10.830 回答
0

尝试https://github.com/dio5/magento-multiproducts-widget

它似乎非常有用。

于 2015-12-15T13:40:40.783 回答