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
->setSku("parent_sku")
->setLinkedProductSku($skuLink)
->setLinkType("related");
$linkDataAll[] = $linkData;
}
}
if($linkDataAll) {
print(count($linkDataAll)); //gives 3
$product->setProductLinks($linkDataAll);
}
$product->save();
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")....
with
$linkData = clone $this->productLinks;
$linkData->setSku("parent_sku")....
Method 3
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);
// ...
}
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.
<?php
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)
->setLinkedProductSku($skuLink)
->setPosition($index)
->setLinkType('related')
;
}
$product = $this->productrepInter->get($productSku);
$product->setProductLinks($linkData)->save();
}
return parent::afterSave();
}
}
Method 5
Use MagentoCatalogApiProductLinkManagementInterface $productLinkManagement
before:
if($linkDataAll) {
print(count($linkDataAll)); //gives 3
$product->setProductLinks($linkDataAll);
}
$product->save();
after:
$this->productLinkManagement->setProductLinks("parent_sku", $linkDataAll);
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0