Magento API: Assigning preexisting simple products to configurable products

18,909

Solution 1

Well the notes here helped me get this running. So I thought I'd share with you the code to add a simple product to an existing Configurable Product.

This code assumes the simple product is a valid one to add, I'm not sure what would happen if it wasn't.

private function _attachProductToConfigurable( $_childProduct, $_configurableProduct ) {
   $loader = Mage::getResourceModel( 'catalog/product_type_configurable' )->load( $_configurableProduct );

   $ids = $_configurableProduct->getTypeInstance()->getUsedProductIds(); 
   $newids = array();
   foreach ( $ids as $id ) {
      $newids[$id] = 1;
   }

   $newids[$_childProduct->getId()] = 1;

   $loader->saveProducts( $_configurableProduct->getId(), array_keys( $newids ) );                
}

Solution 2

The code from the accepted answer by Scimon does not work anymore in recent versions of magento (at least in 1.7). But fortunately, you need just a small fix to get it working again:

private function _attachProductToConfigurable( $_childProduct, $_configurableProduct ) {
   $loader = Mage::getResourceModel( 'catalog/product_type_configurable' )->load( $_configurableProduct, $_configurableProduct->getId() );

   $ids = $_configurableProduct->getTypeInstance()->getUsedProductIds(); 
   $newids = array();
   foreach ( $ids as $id ) {
      $newids[$id] = 1;
   }

   $newids[$_childProduct->getId()] = 1;

   //$loader->saveProducts( $_configurableProduct->getid(), array_keys( $newids ) );                
   $loader->saveProducts( $_configurableProduct, array_keys( $newids ) );                
}

Solution 3

I'm working on doing this right now.

So far I've found these items helpful as references:

I'll post my code so far, and hopefully update it once it works..

// Set 'item_size' as the super attribute  # choose your own attribute!
// this is the 'choose-able' field that differenciates products
$super_attributes=array( Mage::getModel('eav/entity_attribute')
  ->loadByCode('catalog_product','item_size')
  ->getData('attribute_id')
  );  
$product_collection=Mage::getModel('catalog/product')->getCollection();

// Fetch configurable orders
$product_collection->addFieldToFilter('type_id',Array('eq'=>"configurable"));
#$product_collection->addFieldToFilter('sku',Array('eq'=>"ASMCL000002"));  

$product_collection->addAttributeToSelect('*');

$count=0;
foreach($product_collection as $product) {
  $sku = $product->getSku();
  echo "SKU: $sku\n";

  $simple_children_collection = Mage::getModel('catalog/product')->getCollection();
  $simple_children_collection->addAttributeToSelect('*');
  $simple_children_collection->addFieldToFilter('sku',Array('like'=>$sku . "-%"));
  echo "children: ";
  foreach($simple_children_collection as $child) {
      $child_sku = $child->getSku();
      echo "$child_sku ";
      #visiblity should be 'nowhere'
  }
  echo "\n";

if (!$product->getTypeInstance()->getUsedProductAttributeIds()) {
  # This is a new product without the Configurable Attribue Ids set
  $product->getTypeInstance()
    ->setUsedProductAttributeIds( $super_attributes );

  //$product->setConfigurableAttributesData(array($_attributeData));
  $product->setCanSaveConfigurableAttributes(true); # Not sure if this is needed.

  $product->setConfigurableProductsData(''); # Use this to add child products.

}


  $count++;

  try {
      $product->save();
      $productId = $product->getId();
      echo $product->getId() . ", $sku updated\n";
  }
  catch (Exception $e){
      echo "$sku not added\n";
      echo "exception:$e";
  }

}
echo "\nCount is $count\n";

Okay, this uses 'item_size' as the attribute that differentiates the "simple" products. Also, this assumes that the "configurable" parent SKU is the root of the child SKU. For example, ABC001 is the parent while ABC001-SMALL and ABC001-LARGE are the simple children.

Hope that helps someone.

Solution 4

Surprisingly, this works, if all your simple products share the same price:

        $childProducts = $configurable->getTypeInstance(true)->getUsedProductIds($configurable);

        // Don't add this product if it's already there
        if(!in_array($child->getId(), $childProducts)) {    
            $childProducts[] = $child->getId();
        }


        $existingIds = $configurable->getTypeInstance(true)->getUsedProductAttributeIds($configurable);
        $newAttributes = array();

        foreach($configurable->getTypeInstance(true)->getSetAttributes($configurable) as $attribute) {

        if(!in_array($attribute->getId(), $existingIds) && $configurable->getTypeInstance(true)->canUseAttribute($attribute)
            && $child->getAttributeText($attribute->getAttributeCode())) {

            // Init configurable attribute
            $configurableAtt = Mage::getModel('catalog/product_type_configurable_attribute')
                ->setProductAttribute($attribute);

            // Add new attribute to array
            $newAttributes[] = array(
               'id'             => $configurableAtt->getId(),
               'label'          => $configurableAtt->getLabel(),
               'position'       => $attribute->getPosition(),
               'values'         => $configurableAtt->getPrices() ? $configurable->getPrices() : array(),
               'attribute_id'   => $attribute->getId(),
               'attribute_code' => $attribute->getAttributeCode(),
               'frontend_label' => $attribute->getFrontend()->getLabel(),
            );
        }
    }

    if(!empty($newAttributes)) {

        $configurable->setCanSaveConfigurableAttributes(true);
        $configurable->setConfigurableAttributesData($newAttributes);
    }
        $configurable->setConfigurableProductsData(array_flip($childProducts));
        $configurable->save();

Solution 5

I this is an un-educated guess, but I think what your asking for can't be done with the existing API. You will have to write your own or just got directly to the DB.

Share:
18,909
keith
Author by

keith

Partner Developer Advocate working in sunny California for sunny Google. "Practice hard, not hardly"

Updated on June 14, 2022

Comments

  • keith
    keith almost 2 years

    I've got a client database with a large range of stock items, which are being uploaded to Magento as simple products.

    Now I need to group them up and assign them to configurable products with their size and colour being their configurable attributes.

    The Magento API has a Product_Link class, with a promising looking method: catalogue-product-link.assign (link), but I can't for the life of me figure out what arguments I need to make it work with configurable products, providing this is how assign was meant to be used.

  • Devplex
    Devplex almost 15 years
    With the EAV db schema they use there is no 'just' when directly accessing the DB. The Pain!!!
  • Mensch
    Mensch over 13 years
    I don't know if you're still working on this but I think I've cracked it.
  • Dimitrios Mistriotis
    Dimitrios Mistriotis over 13 years
    I am trying to do this from a command line script and I fail here: $loader = Mage::getResourceModel( 'catalog/product_type_configurable' )->load( $_configurableProduct ); (first line) Any ideas? I'm currently investigating it and will inform in case of a result.
  • aeno
    aeno over 11 years
    I updated the code by Scimon to work in recent versions of magento again: see below
  • Mensch
    Mensch about 11 years
    I had an excepted answer? It was a while ago, I've not done any Magento development for a year or so now so go with this.
  • Joseph Leedy
    Joseph Leedy about 11 years
    This probably should have been an edit to the accepted answer IMHO.
  • aeno
    aeno about 11 years
    @Joseph: I didn't had enough reputation to do so at the time of writing, so I did post a new answer.