set related/upsell products programatically only works for 1 product

The question:

I am trying to update products programatically and I’m having issues with the related/upsell section.

It updates only with the last product sku. So if I am trying to link 3 products with a parent one as in the example below, only the last one will appear in the related section for product parent_sku.

$linkDataAll = [];
$skuLinks = "9780500420584,9780500544679,9780500650936";
$skuLinks = explode(",",$skuLinks);

foreach($skuLinks as $skuLink) {
  //check first that the product exist
  $linkedProduct = $this->productFactory->create()->loadByAttribute("sku",$skuLink);
  if($linkedProduct) {
    $linkData = $this->productLinks //MagentoCatalogApiDataProductLinkInterface
    $linkDataAll[] = $linkData;

if($linkDataAll) {
  print(count($linkDataAll)); //gives 3

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

This part caused your issue, if you created this object outsize the foreach loop, that means it is a “global” object. So, we need to create a new object inside the loop.

$linkData = $productLinks //MagentoCatalogApiDataProductLinkInterface

It should like this:

 /** @var MagentoCatalogApiDataProductLinkInterfaceFactory $productLinks **/
$linkData = $productLinks->create();

See more here MagentoCatalogControllerAdminhtmlProductInitializationHelper::setProductLinks

Set related products programatically Magento 2

Method 2

You are always editing the same object.
$this->productLinks is an object so it gets passed around by reference.
$linkData (which is the same as $this->productLinks) is always are reference to the same object.
So $linkDataAll will be an array of 3 elements in your case, but they will all point to the same object.
When first entering the loop, you add some properties to $this->productLinks and add it to the $linkDataAll array.
On the second loop, you add some properties to the same $this->productLinks object and add it again in the array, but this way your first element in the array gets changed.

A simple solution would be to replace

$linkData = $this->productLinks->setSku("parent_sku")....


$linkData = clone $this->productLinks;

Method 3

You need to add the method setPosition to $productLinks

foreach($skuLinks as $n $skuLink) {
    // ...
        ->setPosition($n + 1);
    // ...

Method 4

I have same issue, But after above comment i have update the ProductLinkInterfaceFactory Object, And create new

$productLink = $this->productLinkFactory->create()

every time in loop, Now its work for me.

namespace {{namespace}};
use MagentoCatalogApiDataProductLinkInterfaceFactory as ProductLinkFactory;
class {{classname}} extends MagentoFrameworkAppConfigValue
{   protected $productLinkFactory;
    protected $productrepInter;  
    public function __construct(
          ProductLinkFactory $productLinkFactory,
          MagentoCatalogApiProductRepositoryInterface $productrepInter,
    ) {
        $this->productLinkFactory = $productLinkFactory;
        $this->productrepInter = $productrepInter;
    public function afterSave()

              $productSku = 'main_sku';
              $relatedSku = 'rel_sku1;rel_sku2';
              $skuLinks = explode(";",$relatedSku);                            
              $linkData = array();
              foreach($skuLinks as $index=>$skuLink)              {
                  $productLink  = $this->productLinkFactory->create();  
                  $linkData[] =  $productLink ->setSku($productSku)
                $product = $this->productrepInter->get($productSku);
        return parent::afterSave();

Method 5

Use MagentoCatalogApiProductLinkManagementInterface $productLinkManagement


if($linkDataAll) {
  print(count($linkDataAll)); //gives 3


$this->productLinkManagement->setProductLinks("parent_sku", $linkDataAll);

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment