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>');
    }


    }


}
Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top