Create simple product programatically in magento2
-
12-12-2019 - |
Question
I have created simple product using following code.almost its working fine, but I'm not able assign product to websites.
Actually I have created two websites. I want to assign product to particular website or both websites. here
$this->product->setWebsiteIds(1); $this->product->setWebsiteIds(array(1));
both lines not working.
In Magento\Catalog\Api\ProductRepositoryInterface
there is no information websites (I mean there is no constants,setters,getters).
Anyone have idea?
namespace Kensium\Commands\Console;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;
use Magento\Framework\App\State;
use Magento\Framework\App\ObjectManager\ConfigLoader;
/**
* Command creates simple product by given data
*/
class CreateSimpleProduct extends Command
{
protected $_productRepository;
protected $product;
protected $registry;
protected $state;
protected $configLoader;
protected $objectManager;
const SIMPLE_PRODUCT_INFO = "simpleproductinfo";
public function __construct(
\Magento\Catalog\Api\ProductRepositoryInterface $_productRepository,
\Magento\Catalog\Api\Data\ProductInterface $product,
\Magento\Framework\Registry $registry,
State $state,
ConfigLoader $loader,
\Magento\Framework\ObjectManagerInterface $objectManager
)
{
$this->_productRepository =$_productRepository;
$this->product=$product;
$this->registry = $registry;
$this->state = $state;
$this->configLoader = $loader;
$this->objectManager = $objectManager;
parent::__construct();
}
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('kensium:create_product')
->setDescription('creates simple product')->setDefinition([
new InputArgument(self::SIMPLE_PRODUCT_INFO, InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Simple Product Info')
]);
parent::configure();
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
if (!$input->getArgument(self::SIMPLE_PRODUCT_INFO))
{
throw new \InvalidArgumentException('Missing Argument ' . self::SIMPLE_PRODUCT_INFO);
}
$this->registry->register('isSecureArea', true);
$this->state->setAreaCode('adminhtml');
$this->objectManager->configure($this->configLoader->load('adminhtml'));
$simples=$input->getArgument(self::SIMPLE_PRODUCT_INFO);
foreach($simples as $simple)
{
$arr=explode(":",$simple);
$data['name']=$arr[0];
$data['sku']=$arr[1];
$data['price']=$arr[2];
$this->product->setName($data['name']);
$this->product->setSku($data['sku']);
$this->product->setPrice($data['price']);
$this->product->setTypeId("simple");
$this->product->setAttributeSetId(4);
$this->product->setWebsiteIds(1); // $this->product->setWebsiteIds(array(1));
$this->_productRepository->save($this->product);
$output->writeln('<info>created simple product</info>');
}
}
}
Solution
Based on the comments...
it should work with setWebsiteIds(array(1))
. I have no idea why it doesn't work for you but you can try with $this->product->save()
instead of $this->_productRepository->save($this->product)
OTHER TIPS
I encountered the same issue and found that adding the website after the product has been saved to be the solution.
I used instances of the Magento\Catalog\Api\Data\ProductWebsiteLinkInterface
and Magento\Catalog\Api\ProductWebsiteLinkRepositoryInterface
repository with code similar to the below:
...
$mageProduct = $this->productRepository->save($mageProduct, true);
// Instance of ProductWebsiteLinkInterface
$siteLink = $this->productWebsiteLink;
$siteLink->setSku($mageProduct->getSku());
$siteLink->setWebsiteId(1);
// Instance of ProductWebsiteLinkRepositoryInterface
$websiteLinkRepo = $this->productWebsiteLinkRepository;
$websiteLinkRepo->save($siteLink);
I experienced some confusing application behavior when trying to add simple and configurable products to specific websites/stores in Magento 2.2.
My preferred solution:
/** * This version sets one of the stores the product is assigned to * as the "current store" * and assigns the product to other websites via setWebsiteIds[...]. * Disadvantage: There is no store with all products inside. * The product is assigned to websites 2, 4 and 5 in this example: */ $websiteIds = [2, 4, 5]; // this is obviously dynamically set by an external system $this->storeManager->setCurrentStoreId($websiteIds[0]); $newProduct = $this->productInterfaceFactory->create(); $newProduct->setWebsiteIds($websiteIds); // ... add other attributes $savedProduct = $this->productRepository->save($newProduct);
If changing default stores is not preferred, then it is also a possibility to use a hidden admin store:
/** * This version sets a hidden admin store as the "current store" * and assigns the product to other websites via setWebsiteIds[...]. * Disadvantage: Every product is assigned to the hidden admin store. * Advantage: Every product can be asssigned to and unassigned from * any (other) store programmatically. * The product is assigned to websites 2, 4 and 5 in this example: */ $this->storeManager->setCurrentStoreId(5); $newProduct = $this->productInterfaceFactory->create(); $newProduct->setWebsiteIds([2,4]); // ... add other attributes $savedProduct = $this->productRepository->save($newProduct);
If a product is always needed in all stores, this solution might be fine:
/** * If the current store is set to 0, each product is assigned to every * website. I would not know how to unassign a specific store: Stores * can NOT be unassigned via $newProduct->setWebsiteIds([]);. */ $this->storeManager->setCurrentStoreId(0); $newProduct = $this->productInterfaceFactory->create(); $newProduct->setStoreId(1); // This does not seem to have any impact. $newProduct->setWebsiteIds([2]); // This does not seem to have any impact. // ... add other attributes $savedProduct = $this->productRepository->save($newProduct);
Not setting the current store seems to result in a slightly random scenario:
/** * Here, the current store of the store manager is not set. * This version does work, but in addition to store id 2, each product * has a second store assigned in my case. * That second store seems to be quite random. */ $newProduct = $this->productInterfaceFactory->create(); $newProduct->setWebsiteIds([2]); // ... add other attributes $savedProduct = $this->productRepository->save($newProduct);
As a result, I keep these findings:
- It seems to be necessary to set the current store via the store manager before creating the product. Not setting it makes the results a bit random.
- Setting the current store to 0 assigns every product to all stores, but makes it hard to unassign them.
- If a product is created with the current store set, it can be assigned to a choice of websites.
- It seems to be not necessary to save the product twice; the websites can be chosen during the initial product creation.
I think, my research session was a bit funny; other people might know how to find that kind of information easier by looking through documentation or investigating code - but I did both, and even asked my colleagues, and nobody seemed to know. Hope, it helps anyone.