【问题标题】:Programmatically add Magento products to categories以编程方式将 Magento 产品添加到类别中
【发布时间】:2011-09-23 09:48:23
【问题描述】:

我正在使用 Magento 1.4.0.1。 我有超过 21000 个简单的产品,每个都进入一个类别。 我的网站上有数百个类别。 有些产品属于多个类别。 有什么方法可以让我以编程方式将产品添加到多个类别中?

【问题讨论】:

    标签: magento categories


    【解决方案1】:

    您可以编写一个模块(这需要时间,但在导入数据时可能会更快),或者您可以将一些东西与 API 放在一起(较少涉及 Magento 编程,但在导入数据时可能会更慢)。

    你已经知道什么的起点、你的时间有多么宝贵以及你需要多久运行一次更新应该决定你的选择。

    这是用于将产品添加到类别的 Magento API 文档(参见页面底部的示例):

    http://www.magentocommerce.com/wiki/doc/webservices-api/api/catalog_category

    【讨论】:

    • 感谢指点!您能否为我澄清一下 UpdateCategory 方法 - 该方法是否允许我将产品分配到其他(多个)类别?还是会覆盖已分配的现有类别?
    • 我希望你能从编程向导那里得到一些答案 - 如果我是你怂恿他们的话,我会取消勾选...这取决于你如何看待任务 - 首先是类别或产品.如果您遍历产品,那么您绝对可以将它们分配给多个类别 - 这将是“将类别分配给产品”而不是“将产品分配给类别”。从产品更新 API 代码开始,而不是目录更新。有更好的方法,但至少使用 API,您可以让您的算法正常工作。
    • 感谢您的更新 - 为产品分配类别听起来好多了...也许有人已经编写了这样一段代码并且很乐意分享它:-)
    【解决方案2】:

    在 PHP 代码中,您可以在导入它们时将它们放入类别中。

    假设您有一个名为 $product 的产品和一个名为 $category_id 的类别 ID

    您可以通过以下操作设置产品所属的类别

    $categories = array($category_id);
    $product->setCategoryIds($categories);
    $product->save();
    

    如果产品已经有类别并且您想再添加一个类别,那么您可以像这样使用getCategoryIds()

    $categories = $product->getCategoryIds();
    $categories[] = $categoryId;
    $product->setCategoryIds($categories);
    $product->save();
    

    或者,正如 Joshua Peck 在 cmets 中提到的,您可以使用 category_api 模型在类别中添加或删除产品,而不会影响其当前的类别分配:

    Mage::getSingleton('catalog/category_api')
      ->assignProduct($category->getId(),$p‌​roduct->getId());
    
    Mage::getSingleton('catalog/category_api')
      ->removeProduct($category->getId(),$p‌​roduct->getId());
    

    【讨论】:

    • 嗨 Josh,谢谢你,但是这些产品已经在 Magento 中,我只需要将它们添加到多个类别中(或者在大多数情况下为每个产品分配多个类别)。
    • 然后您所要做的就是加载产品并执行 setCategoryIds() 函数并保存它。如果您想做多个类别,可以将多个 category_id 放入该数组。
    • 从这里不清楚,这是覆盖类别还是添加到它们?
    • 这将覆盖为该产品分配的类别。要添加到类别,您可以将 $product->getCategoryIds() 分配给变量,将您的 ID 添加到数组,然后 setCategoryIds(),然后保存。
    • 我只想补充一点,您可以使用 getSingleton 类别 API 删除和添加:Mage::getSingleton('catalog/category_api')->removeProduct($category->getId(),$product->getId());Mage::getSingleton('catalog/category_api')->assignProduct($category->getId(),$product->getId()); 这不会覆盖产品已经在的任何类别。
    【解决方案3】:

    由于某种懒惰的原因,我最终使用 API 进行了此操作。这会将所有可见产品添加到 ID 为 146 的类别中:

    <?php
      $client= new SoapClient('http://www.example.com/api/soap/?wsdl', array('trace' => 1, "connection_timeout" => 120));
    
      // Can be added in Magento-Admin -> Web Services with role set to admin
    
      $sess_id= $client->login('apiuser', 'apikey');
    
      // Get the product list through SOAP
      $filters = array('visibility' => '4', 'status' => '1');
      $all_products=$client->call($sess_id, 'product.list', array($filters));
    
      // Now chuck them into category 146
    
      foreach($all_products as $product)
      {  //var_dump($product);
          echo $product['sku']."\n";
          $doit=$client->call($sess_id, 'category.assignProduct', array('146', $product['sku']));
      }
    ?>
    

    【讨论】:

    • 嗨马修,你能解释一下你在这里发布的代码吗?例如$filters = array('visibility' => '4', 'status' => '1');参考?
    • 可见性 4 是目录/搜索,状态 1 已启用。因此,它不会在“一切”目录(对我来说是 ID 146)中放入数以百万计的简单元素。
    • 我可以在 localhost 中使用 API。
    【解决方案4】:

    查看 Magento API 后:Magento 通过以下方式将产品添加到类别中:

    public function assignProduct($categoryId, $productId, $position = null, $identifierType = null)
    {
        $category = $this->_initCategory($categoryId);
        $positions = $category->getProductsPosition();
        $productId = $this->_getProductId($productId);
        $positions[$productId] = $position;
        $category->setPostedProducts($positions);
    
        try {
            $category->save();
        } catch (Mage_Core_Exception $e) {
            $this->_fault('data_invalid', $e->getMessage());
        }
    
        return true;
    }
    

    并获得所有指定的产品:

    public function assignedProducts($categoryId, $store = null)
    {
        $category = $this->_initCategory($categoryId);
    
        $storeId = $this->_getStoreId($store);
        $collection = $category->setStoreId($storeId)->getProductCollection();
        ($storeId == 0)? $collection->addOrder('position', 'asc') : $collection->setOrder('position', 'asc');;
    
        $result = array();
    
        foreach ($collection as $product) {
            $result[] = array(
                'product_id' => $product->getId(),
                'type'       => $product->getTypeId(),
                'set'        => $product->getAttributeSetId(),
                'sku'        => $product->getSku(),
                'position'   => $product->getPosition()
            );
        }
    
        return $result;
    }
    

    【讨论】:

      【解决方案5】:

      我只想补充一点,您可以使用 getSingleton 类别 API 删除和添加:

      从类别中删除产品:

      Mage::getSingleton('catalog/category_api')->removeProduct($category->getId(),$p‌​roduct->getId());
      

      将产品添加到类别:

      Mage::getSingleton('catalog/category_api')->assignProduct($category->getId(),$p‌​roduct->getId());
      

      这不会覆盖产品已有的任何类别

      【讨论】:

      • 这是最好的答案
      • 为什么它打破循环 foreach($products as $prod)?我无法在整个产品系列中运行它。
      • @versedi 我没有看到它打破循环。我让它运行了 100,000 个产品 SKU。我会尝试捕获并查看是否发生错误以及原因。
      • 请注意,Magento 将在 assignProduct/removeProduct 调用之后运行类别/产品重新索引,因此对于分配大量产品/类别而言,这不是一个可持续的解决方案。
      • 这慢得要命,但比保存产品要快...我的回答可以更快地满足您的需求
      【解决方案6】:

      我们可以使用 magento 脚本以编程方式将多个产品分配给该类别。请创建一个类别数组并根据自定义属性或字段选择产品。

      $newproducts = $product->getCollection()->addAttributeToFilter(array(array('attribute'=>'attribute_label', 'eq'=> 'attribute_id')));
      

      遍历产品并分配到如下所示的类别。

      $newCategory = array( $list[0] , $list[$key]); 
      foreach ($newproducts as $prod)
      {
          $prod->setCategoryIds(array_merge($prod->getCategoryIds(), $newCategory));
          $prod->save();
      }
      

      请参考my tutorial,它给出了一步一步的解释。

      【讨论】:

        【解决方案7】:

        以上最佳答案点使用Mage::getSingleton('catalog/category_api') ->assignProduct($category->getId(),$p‌​roduct->getId());

        无论如何,如果您有很多产品/类别要更新,该功能会很慢。

        这是因为api函数assignProduct()

        • 一次只接受 1 个产品/类别
        • 每次调用都会加载产品和类别,然后保存类别
          (如果您需要多次更新同一类别,速度会很慢)

        例如,假设您要将 10 个产品分配给 1 个类别...它将加载并保存同一类别 10 次...
        (如果您确定产品 ID 正确,则加载所有实际不需要的产品)

        更快的方法
        我想出了以下与 api 相同的功能,但它只加载和保存类别一次

        此函数接受一个数组作为参数$data,该数组需要包含$category_id =&gt; array(all the products you want to assign)形式的所有收集更改

        根据您的需要自定义它是微不足道的,例如,为产品添加store_id的参数(该函数默认使用0)和位置信息......

        添加类别

        function assignCategories($data)
        {
            foreach ($data as $cat_id => $products_ids) {
                /** @var  $category Mage_Catalog_Model_Category */
                $category = Mage::getModel('catalog/category')
                    ->setStoreId(0)
                    ->load($cat_id );
        
                $positions = $category->getProductsPosition();
                foreach ($products_ids as $pid) {
                    $positions[$pid] = null;
                }
                $category->setPostedProducts($positions);
                $category->save();
            }
        }
        

        删除类别

        function removeProduct($data)
        {
            foreach ($data as $cat_id => $products_ids) {
                /** @var  $category Mage_Catalog_Model_Category */
                $category = Mage::getModel('catalog/category')
                    ->setStoreId(0)
                    ->load($cat_id);
        
                $positions = $category->getProductsPosition();
                foreach ($products_ids as $pid) {
                    unset($positions[$pid]);
                }
                $category->setPostedProducts($positions);
                $category->save();
            }
        }
        

        注意

        保存类别会触发Category Flat DataCatalog URL Rewrites 重新索引(如果它们设置为update on save)。
        这不是很快(API 调用也是如此)...
        ...因此您可能希望在运行更改之前将这些重新索引设置为手动更新,然后在之后对它们进行完整的重新索引
        (取决于您要更新的类别/产品的数量,这可能是最佳选择)

        【讨论】:

          【解决方案8】:

          将类别分配给产品的最佳方式。 来自核心代码的引用 - app\code\core\Mage\Catalog\Model\Resource\Category.php

          $write = Mage::getSingleton('core/resource')->getConnection('core_write');
          $categoryProductTable = Mage::getSingleton('core/resource')->getTableName('catalog/category_product');
          $productData = array();$position=0;
          foreach ($_productCollection as $product) {
              $productData[] = array(
                  'category_id' => (int)$catId1,
                  'product_id'  => (int)$product->getId(),
                  'position'    => (int)$position
              );
          $productData[] = array(
                  'category_id' => (int)$catId2,
                  'product_id'  => (int)$product->getId(),
                  'position'    => (int)$position
              );
          }
          
          $write->insertMultiple($categoryProductTable, $productData);
          

          【讨论】:

            猜你喜欢
            • 2012-10-28
            • 1970-01-01
            • 2016-03-14
            • 1970-01-01
            • 1970-01-01
            • 2015-04-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多