4

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 //Magento\Catalog\Api\Data\ProductLinkInterface
                    ->setSku("parent_sku")
                    ->setLinkedProductSku($skuLink)
                    ->setLinkType("related");
    $linkDataAll[] = $linkData;
  }

}
if($linkDataAll) {
  print(count($linkDataAll)); //gives 3
  $product->setProductLinks($linkDataAll);
}
$product->save();
10

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 //Magento\Catalog\Api\Data\ProductLinkInterface

It should like this:

 /** @var \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinks **/
$linkData = $productLinks->create();

See more here Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper::setProductLinks

Set related products programatically Magento 2

  • thanks for the gist, with object manager it works, but I don't want to use the object manager. productLinks->create() throws an non-existing method create. I've checked the available methods and there is no create in Magento\Catalog\Api\Data\ProductLinkInterface. then I realise I should use Factories, so using Magento\Catalog\Api\Data\ProductLinkInterfaceFactory and create() did the job – Claudiu Creanga Sep 15 '16 at 8:57
  • 1
    Yes, you can see more: Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper::setProductLinks. – Khoa TruongDinh Sep 15 '16 at 8:58
1

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")....

with

$linkData = clone $this->productLinks;
$linkData->setSku("parent_sku")....
  • thanks for the explanation. It is clearer now what happened. I guess it was harder to see it because var_dump crashes the site and xdebug is so slow so I cannot inspect how objects look. Anyway I should have used Factories: Magento\Catalog\Api\Data\ProductLinkInterfaceFactory and then create() method. – Claudiu Creanga Sep 15 '16 at 8:59
  • 1
    @ClaudiuCreanga. That's even better. You should use the factory. But I wanted to give you a quick solution with minimum code change. "Bafta". – Marius Sep 15 '16 at 9:00
0

You need to add the method setPosition to $productLinks

foreach($skuLinks as $n $skuLink) {
    // ...
    $this->productLinks
        ->setSku("parent_sku")
        ->setLinkedProductSku($skuLink)
        ->setLinkType("related")
        ->setPosition($n + 1);
    // ...
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.