Magento创建configurable产品的要点

接着上一篇用API创建可配置的产品Configurable Product说事。Magento的产品类型可分为Simple Product、Group Product、Configurable Product、Virtual Product、Bundle Product、Downloadable Product。其中Simple的产品最简单,属于基础产品。Configurable Product和Bundle Product的产品是建立在这些Simple产品之上的。

Configurable Product 和 Bundle Product的产品都可以独立的跟踪库存 。Custom Option是无法跟踪独立产品的库存。Configurable Product是需要独立建立不同属性的产品的组合,而 Bundle Product是可以组合产品的。举个例子来说,一件衣服有2种颜色和3个大小,建立Configurable Product 需要创建6个独立的Simple产品,而Bundle 是只需要创建2+3=5个Simple产品。在属性比较多的时候,区别还是很大的。

关于Configurable Product 的创建,不得不说,Magento管理后台的用户体验很差。前段时间教我的同事创建Configurable Product,过了一阵子,忘了,为此写下这篇文章。

首先创建Configurable Product有3个要点:

  1. 在属性集里必须有一个全局的属性,即属性的Scope为Global。

  2. 属性的Catalog Input Type for Store Owner要选择Dropdown。

  3. 属性的Use To Create Configurable Product要选择Yes。

下面以创建一个Configurable Product为例,该产品有一个cm_color的属性。有bule、red、yellow。价格分别为10、20、30。

创建Configurable Product的属性

从导航进入到CataLog->Attributes->Manage Attributes,在Properties这个tab中:

![magento-create-configurable-product0](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product0_thumb.png "magento-create-configurable-product0")

新建一个cm_color的属性,Scope选择Global,Catalog Input Type for Store Owner为Dropdown,Catalog Input Type for Store Owner为Yes,注意图中画红线的部分。

![magento-create-configurable-product1](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product1_thumb.png "magento-create-configurable-product1")

切换到Manage Label/Options,添加该属性在不同语言的store显示不同的Title,这里只需填写Admin的部分就可以了。

给该属性添加3个选项,Bule、Red、Yellow,然后Save Attribute。

![magento-create-configurable-product2](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product2_thumb.png "magento-create-configurable-product2")

将属性添加到属性集中

从导航进入到CataLog->Attributes->Manage Attributes Sets,选择Default属性集。

![magento-create-configurable-product3](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product3_thumb.png "magento-create-configurable-product3")![magento-create-configurable-product4](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product4_thumb.png "magento-create-configurable-product4")

将cm_color属性从右边的Unassigned Attribute拖到左边的Groups的General组,完成之后Save Attribute Set。

![magento-create-configurable-product5](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product5_thumb.png "magento-create-configurable-product5")

创建Configurable Product

从导航进入到CataLog->Manage products,点击Add Product。Attribute Set 选择Default,Product Type 选择Configurable Product,点击Continue。

![magento-create-configurable-product6](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product6_thumb.png "magento-create-configurable-product6")

选择具有全局属性的cm_color,点击Continue。

![magento-create-configurable-product7](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product7_thumb.png "magento-create-configurable-product7")

添加Configurable Product的基本属性,Name,Description,Short Description,SKU,Status,Visibility,Price等基本属性,点击Save and Continue Edit。

切换到Associated products选项卡,重点在红线的部分Quick Simple Product Creation。

![magento-create-configurable-product8](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product8_thumb.png "magento-create-configurable-product8")

创建一个Color为Bule的产品,Color选择Bule,price选择10,Fixed是直接定价,Percentage是百分比,该价格都是在原价价格加价。Visibility最好选择不显示Not Visible Individually。

![magento-create-configurable-product9](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product9_thumb.png "magento-create-configurable-product9")

点击Quick Create,可在下方的Super Product Attribute Configuration看到自动创建的Simple Product,并自动绑定到Color的Bule选项。

![magento-create-configurable-product10](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product10_thumb.png "magento-create-configurable-product10")

同样创建Color为Red,和Yellow的产品。

![magento-create-configurable-product11](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product11_thumb.png "magento-create-configurable-product11")

![magento-create-configurable-product12](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product12_thumb.png "magento-create-configurable-product12")

![magento-create-configurable-product13](http://www.xbc.me/wp-content/uploads/magento-create-configurable-product13_thumb.png "magento-create-configurable-product13")

此时创建好了3个Simple Product了,并都已经绑定相应的属性上。选择Save and Continue Edit。

创建Shipping Module

Magento系统自带了大概7种运费方式:平价、运费表、免运费、ups、usps、fedex、dhl等。不过这些依然无法满足我们的需求,这时候就需要创建一个shipping module 来实现了。创建一个shipping module 很简单,需要继承Mage_Shipping_Model_Carrier_Abstract抽象类, 实现Mage_Shipping_Model_Carrier_Interface接口类,这样就能利用函数collectRates来自定义计算运费的方式。这样就可以创建一个插件来自定义shipping method。

添加模块配置信息

首先,添加模块信息,创建文件app/etc/modules/Xbc_Ship.xml

 <config><modules><xbc_ship><active>true</active>
      <codepool>local</codepool>            
            <depends><mage_shipping></mage_shipping></depends> 
      <version>1.1.0</version></xbc_ship></modules></config> 

添加模块配置信息,创建文件app/code/local/Xbc/Ship/etc/config.xml

 <config><modules><xbc_ship><version>1.1.0</version></xbc_ship></modules> 
  <global>
    <helpers><ship><class>Xbc_Ship_Helper</class></ship></helpers> 
     <resources><ship_setup><setup><module>Xbc_Ship</module></setup> 
         <connection><use>core_setup</use></connection></ship_setup> 
      <ship_write><connection><use>core_write</use></connection></ship_write> 
      <ship_read><connection><use>core_read</use></connection></ship_read></resources> 
     <models><ship><class>Xbc_Ship_Model</class>
        <resourcemodel>ship_mysql4</resourcemodel></ship></models> 
  </global>    
     <default><carriers><cm_dhl><active>1</active>
                <debug>0</debug>
                <model>ship/carrier_cm_dhl</model>
                <name>DHL</name>
                <title>DHL</title>
                <description>DHL</description>
                <sort_order>0</sort_order></cm_dhl></carriers></default></config> 

实现自定义运费

创建文件app/code/local/Hofan/Ship/Model/Carrier/Cm/Dhl.php。

getConfigFlag('active')) {
                return false;
            }

            $result = Mage::getModel('shipping/rate_result');  
            $method = Mage::getModel('shipping/rate_result_method');  
            $method->setCarrier($this->_code);  
            $method->setCarrierTitle($this->getConfigData('title'));
            $method->setMethod($this->_code);  
            $method->setMethodTitle($this->getConfigData('name'));

            $debug = $this->getConfigData('debug');
            $rate = $this->getConfigData('rate');

            //get find the country id
            $country_id = $request->getDestCountryId();

            //Get all items
            $items = $request->getAllItems();
            $weight = $request->getPackageWeight();
            foreach ($items as $item){
                $_product = $item->getProduct();
                if ($_product instanceof Mage_Catalog_Model_Product) {
                    $product = Mage::getModel('catalog/product')->load($_product->getId());
                    if($_weight = $product->getWeight()){

                    }
                }
            }

            //get price
            $shippingPrice = 100;

            $method->setPrice($shippingPrice);
            $method->setCost($shippingPrice);
            $result->append($method);  
            return $result;  
        }  

        /**
         * Get allowed shipping methods
         *
         * @return array
         */
        public function getAllowedMethods()
        {
            return array($this->_code=>$this->getConfigData('name'));
        }
    }  

添加后台配置

如果完成了上面的步骤,你可以添加后台配置文件。创建文件app/code/local/Xbc/Ship/etc/system.xml

 <config><sections><carriers translate="label" module="ship"><groups><cm_dhl translate="label"><label>Hofan DHL</label>
                      <frontend_type>text</frontend_type>
                      <sort_order>0</sort_order>
                      <show_in_default>1</show_in_default>
                      <show_in_website>1</show_in_website>
                      <show_in_store>1</show_in_store>
                      <model>ship/carrier_cm_dhl</model>
                       <fields><active translate="label"><label>Enabled</label>
                                        <frontend_type>select</frontend_type>
                                        <source_model>adminhtml/system_config_source_yesno</source_model>
                                        <sort_order>10</sort_order>
                                        <show_in_default>1</show_in_default>
                                        <show_in_website>1</show_in_website>
                                        <show_in_store>1</show_in_store></active> 
                                 <debug translate="label"><label>Debug Mode</label>
                                        <frontend_type>select</frontend_type>
                                        <source_model>adminhtml/system_config_source_yesno</source_model>
                                        <sort_order>20</sort_order>
                                        <show_in_default>1</show_in_default>
                                        <show_in_website>1</show_in_website>
                                        <show_in_store>1</show_in_store></debug> 
                                 <title translate="label"><label>Title</label>
                                        <frontend_type>text</frontend_type>
                                        <sort_order>30</sort_order>
                                        <show_in_default>1</show_in_default>
                                        <show_in_website>1</show_in_website>
                                        <show_in_store>1</show_in_store></title> 
                                 <name translate="label"><label>Method Name</label>
                                        <frontend_type>text</frontend_type>
                                        <sort_order>40</sort_order>
                                        <show_in_default>1</show_in_default>
                                        <show_in_website>1</show_in_website>
                                        <show_in_store>1</show_in_store></name> 
                                 <description translate="label"><label>Description</label>
                                        <frontend_type>textarea</frontend_type>
                                        <sort_order>50</sort_order>
                                        <show_in_default>1</show_in_default>
                                        <show_in_website>1</show_in_website>
                                        <show_in_store>1</show_in_store></description> 
                                 <sort_order translate="label"><label>Sort Order</label>
                                        <frontend_type>text</frontend_type>
                                        <sort_order>100</sort_order>
                                        <show_in_default>1</show_in_default>
                                        <show_in_website>1</show_in_website>
                                        <show_in_store>1</show_in_store></sort_order></fields></cm_dhl></groups></carriers></sections></config> 

该插件在Magento CE 1.6.2上测试通过。

参考资料

Adding New Shipping Module In Magento

自定义Magento导航目录

Magento的默认主题中导航目录是垂直下拉式菜单:鼠标滑过时会显示下级菜单。实际上你如果要把菜单改成水平下拉式的话,最好的方式重写目录导航的block,自定义生成你所需要的导航样式。定义目录导航的文件位于/app/code/core/Mage/Catalog/Block/Navigation.php。主要由这renderCategoriesMenuHtml和_renderCategoryMenuItemHtml两个函数来实现。

函数renderCategoriesMenuHtml取出所有一级目录,然后丢给renderCategoryMenuItemHtml去循环判断是否有子目录,如果子目录是可显示的话,才能在前台显示。其实可以由一个递归函数来实现嘛。为此,我写一个小插件来实现这个功能。

首先添加插件的模块信息app/etc/modules/Cm_Menu.xml

 <config><modules><cm_menu><active>true</active>
      <codepool>local</codepool>
      <version>1.0.0</version></cm_menu></modules></config> 

添加模块配置信息,重写了catalog/navigation这个block

 <config><modules><cm_menu><version>1.0.0</version></cm_menu></modules> 
  <global><helpers><menu>
        <class>Cm_Menu_Helper</class>
      </menu></helpers> 
    <blocks><menu>
            <class>Cm_Menu_Block</class>
        </menu>

         <catalog><rewrite><navigation>Cm_Menu_Block_Navigation</navigation></rewrite></catalog></blocks></global></config>  

自定义renderMenu函数来生成导航。Cm_Menu_Block_Navigation 继承Mage_Catalog_Block_Navigation,这样就可以使用在phtml使用自定义的函数。

getStoreCategories() as $child) {
                if ($child->getIsActive()) {
                    $activeCategories[] = $child;
                }
            }
        }else{
            if (!$category->getIsActive()) {
                return '';
            }   
            // get all children
            if (Mage::helper('catalog/category_flat')->isEnabled()) {
                $children = (array)$category->getChildrenNodes();
            } else {
                $children = $category->getChildren();
            }
            foreach ($children as $child) {
                if ($child->getIsActive()) {
                    $activeCategories[] = $child;
                }
            }
        }
        $activeCategoriesCount = count($activeCategories);
        $hasActiveCategoriesCount = ($activeCategoriesCount > 0);
        //only check parent category 
        if($level == 0 && $category == ''){
            if (!$hasActiveCategoriesCount) {
                return '';
            }
        }
        $_html = '';
        $j = 0;
        if($level == 0 && $category == ''){
            foreach ($activeCategories as $category) {
                $_html .= $this->renderMenu( $level, $category , ($j == 0));
                $j++;
            }
            return $_html;
        }else{
            $_url = $this->getCategoryUrl($category);
            $_name = $this->escapeHtml($category->getName());
            //$_child = Mage::getModel( 'catalog/category' )->load($category->getId());
            //$_description = $_child->getDescription();
            if(!$_description){
                $_description = $_name;
            }
            $html = array();
            foreach ($activeCategories as $category) {
                $_html .= $this->renderMenu( $level + 1, $category , ($j == 0));
                $j++;
            }
            $classes = array();
            if ($isFirst) {
                $classes[] = 'fore';
            } 
            if($level == 0){
                $classes[] = 'item';
                $attributes = array();
                if (count($classes) > 0) {
                    $attributes['class'] = implode(' ', $classes);
                }
                $htmlLi = ' <div'; foreach="" ($attributes="" as="" $attrname="">$attrValue) {
                    $htmlLi .= ' ' . $attrName . '="' . str_replace('"', '\"', $attrValue) . '"';
                }
                $htmlLi .= '>';
                $html[] = $htmlLi;

                $html[] = '<span>';
                $html[] = '

### ';
                $html[] = '['.$_name.']('.$_url.' "'.$_description.'")';
                $html[] = '

';
                $html[] = '</span>';
                $html[] = '

<div class="i-mc">';
                $html[] = '

<div class="subitem">';
                $html[] = $_html;   
                $html[] = '</div>

';
                $html[] = '</div>

';
                $html[] = '';
            }
            if($level == 1){
                $attributes = array();
                if (count($classes) > 0) {
                    $attributes['class'] = implode(' ', $classes);
                }
                $htmlLi = ' <dl'; foreach="" ($attributes="" as="" $attrname="">$attrValue) {
                    $htmlLi .= ' ' . $attrName . '="' . str_replace('"', '\"', $attrValue) . '"';
                }
                $htmlLi .= '>';
                $html[] = $htmlLi;

                $html[] = '

<dt>';
                $html[] = '['.$_name.']('.$_url.' "'.$_description.'")';
                $html[] = '</dt>

';
                $html[] = '

<dd>';
                $html[] = $_html;
                $html[] = '</dd>

';
                $html[] = '';
            }
            if($level == 2){
                $html[] = '_';
                $html[] = '['.$_name.']('.$_url.' "'.$_description.'")';
                $html[] = '_';
            }
            $_html = implode("\n", $html);
            return $_html;
        }
    }
}
?></dl';></div';> 

在renderMenu函数中,函数有3个参数,$level,$category,$j。$level参数是目录的层级,参数$category是子目录的实例。目录的层级限制在3层以内,在第一次循环的的时候,$level=0,会从系统取出全部的一级目录分类,存入$activeCategories数组中,通过计算$activeCategories数组的个数来判断时候是否存在二级目录。如果存在二级目录,再丢给renderMenu函数自己,此时$level=0,$category参数是子目录的实例,根据不同的$level进行循环,得到最后的目录列表。

将block的type换成

在模板中只需要调用renderMenu函数

renderMenu();?>

本插件在Magento CE 1.6.2 上测试通过