Programmatically create upsell, cross sell and related products in Magento

Related Inchoo Services

This article will explain how to add upsell, cross sell and related products programmatically to Magento. One of practical examples would be data migration from some other ecommerce system to Magento. You can read a nice article on how to add upsell, cross sell and related products from administration here. It explains what all these product relations mean and where are they used on the site.

Load existing product data

At the beginning, there is a product that need to be updated with product relations. It needs to be loaded as usual.

$product = Mage::getModel('catalog/product')->load($productId);

This loaded product model will not contain information about already existing upsell, cross sell and related products. If loaded product doesn’t have previous upsell, cross sell or related products set, it can be saved immediately with new data. But, if there is already existing data about these products, it must be loaded first, merged with new data and then saved. There are specific functions for that. Otherwise, it would be overwritten with new data only.

$upSellProducts = $product->getUpSellProducts();
$crossSellProducts = $product->getCrossSellProducts();
$relatedProducts = $product->getRelatedProducts();

These functions load all upsell, cross sell and related product models as an array with numeric keys starting from zero.


Prepare existing product data

In order to update product’s upsell, cross sell and related information, they need to be rearranged in array with product ids as keys. This array should also contain information about product position as a subarray. Position parameter determines product’s order position on frontend, usually in sidebar or slider. This parameter can also be set through Magento administration by opening product’s upsell, cross sell or related tab.

foreach ($upSellProducts as $upSellProduct) {
    $upSellProductsArranged[$upSellProduct->getId()] = array('position' => $$upSellProduct->getPosition());
foreach ($crossSellProducts as $crossSellProduct) {
    $crossSellProductsArranged[$crossSellProduct->getId()] = array('position' => $crossSellProduct->getPosition());
foreach ($relatedProducts as $relatedProduct) {
    $relatedProductsArranged[$relatedProduct->getId()] = array('position' => $relatedProduct->getPosition());

Merge new product data

When migrating products to Magento, products will be created, not updated, so if there is multiple upsell, cross sell or related products, this parameter can be incremented in a loop starting from zero or they can all be set to zero.Merging new upsell, cross sell and related products:

$newUpSellProducts = array($newUpSellProduct1, $newUpSellProduct2);
foreach ($newUpSellProducts as $newUpSellProduct) {
    $upSellProductsArranged[$newUpSellProduct->getId()] = array('position' => '');
$newCrossSellProducts = array($newCrossSellProduct1, $newCrossSellProduct2);
foreach ($newCrossSellProducts as $newCrossSellProduct) {
    $crossSellProductsArranged[$newCrossSellProduct->getId()] = array('position' => '');
$newRelatedProducts = array($newRelatedProduct1, $newRelatedProduct2);
foreach ($newRelatedProducts as $newRelatedProduct) {
    $relatedProductsArranged[$newRelatedProduct->getId()] = array('position' => '');

When all relations are merged, they should be set as one of product’s _data parameter:


Finally the product can be saved:


Database structure

This may seem like a simple thing. All that is needed is to set upsell, cross sell and related product ids in array with their positions and save the product. Backend process is actually complicated. Magento function that handles product relations saving process is saveProductRelations($product). It is located in Mage_Catalog_Model_Product_Link class.

Database structure for product relations is eav structure. Main table, in which most of this information is saved, is “catalog_product_link”. It’s structure is very simple. It consists of 4 columns. “link_id” is increment ID, “product_id” is edited product, “linked_product_id” is ID of the product that is related to edited product, “link_type_id” is relation type ID. 4 is for upsell, 5 for cross sell and 1 for related product. Second table worth mentioning is “catalog_product_link_attribute_int” which saves product’s position parameter mentioned earlier.


select * from catalog_product_link;

| link_id | product_id | linked_product_id | link_type_id |
|     1   |     247    |               640 |            1 |
|     2   |     247    |               642 |            1 |
|     3   |     247    |               647 |            1 |
|     4   |     247    |               641 |            1 |
|     5   |     247    |               652 |            4 |
|     6   |     247    |               651 |            4 |
|     7   |     247    |               651 |            5 |
|     8   |     247    |               652 |            5 |
|     9   |     247    |               652 |            1 |
|    10   |     247    |               651 |            1 |

Damir Serfezi

- Backend Developer

Backend Developer who is passionate about development and bikes.

Read more posts by Damir / Visit Damir's profile


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.