4

I have created this custom import module that will create products and set different values for each store view. The problem is, when I save a single attribute for the product on a store view, all the other attributes are saved to it as well for that store view. I want the store view version to inherit (use default) all values except the one I'm changing (description).

This is stripped/simplified version of the script:

// Create a product model using \Magento\Catalog\Model\ProductFactory
$productModel = $this->productFactory->create();

// Set the default values
$productModel
  ->setStoreId(0)
  ->setName($name)
  ->setAttributeSetId($productModel->getDefaultAttributeSetId())
  ->setWebsiteIds([1,2])
  ->setVisibility(4)
  ->setUrlKey($urlKey)
  ->setStatus(2)
  ->setTypeId('simple')
  ->setPrice(10)
  ->save();

// Reload product
$productStoreView = $this->productFactory->create()
  ->load($productModel->getId())
  ->setStoreId(1)
  ->setDescription('Desc for store view 1')
  ->save();

$productStoreView = $this->productFactory->create()
  ->load($productModel->getId())
  ->setStoreId(2)
  ->setDescription('Desc for store view 2')
  ->save();

The result now when I, using Magento 2 admin, looking at the product, each store view has it's own values for status, name etc set for each store view when it should only be "description" that isn't using default value.

Any tips on what I'm doing wrong?

Updated 2017-01-30:

I've started up a brand new environment with a fresh Magento 2.1.3 install. Then I created a new website, store and store view with the same root catalog.

After that, I saved this script in pub/test.php and executed it via CLI (I know it's not best practice, it's just to test/prove my case).

I visit admin and click on the newly created product. The default view looks as it's supposed to. I then switch stores and status is not using default value among other attributes.

<?php

use Magento\Framework\App\Bootstrap;

require __DIR__ . '/../app/bootstrap.php';

$bootstrap = Bootstrap::create(BP, $_SERVER);

$obj = $bootstrap->getObjectManager();

$state = $obj->get('Magento\Framework\App\State');
$state->setAreaCode('frontend');

$product = $obj->get('Magento\Catalog\Model\Product');

$product
    ->setName('Random name ' . time())
    ->setSku(time())
    ->setPrice(0)
    ->setStatus(2)// Disabled
    ->setWebsiteIds([1, 2])
    ->setVisibility(4)
    ->setAttributeSetId($product->getDefaultAttributeSetId())
    ->setTypeId('simple')
    ->save();

echo "Saved product ID " . $product->getId() . "\n";

$obj->create('Magento\Catalog\Model\Product')
    ->load($product->getId())
    ->setStoreId(1)
    ->setDescription('Description store view 1')
    ->save();

$obj->create('Magento\Catalog\Model\Product')
    ->load($product->getId())
    ->setStoreId(2)
    ->setDescription('Description store view 2')
    ->save();

All store views: https://i.sstatic.net/YkGjV.jpg

Store view 1: https://i.sstatic.net/C8Tuh.jpg

Store view 2: https://i.sstatic.net/uAS2h.jpg

2
  • After load product u can set store id
    – Bhavik
    Commented Jan 27, 2017 at 8:52
  • could you please post your full script ?
    – Keyur Shah
    Commented Jan 27, 2017 at 9:22

5 Answers 5

7

I think the best answer to this question currently looks like this (using price as example attribute):

/** @var  \Magento\Catalog\Model\ProductFactory */
protected $productFactory;

/** @var  \Magento\Catalog\Model\ResourceModel\Product */
protected $productResourceModel;

public function __construct(
    \Magento\Catalog\Model\ProductFactory $productFactory,
    \Magento\Catalog\Model\ResourceModel\Product $productResourceModel
)
{
    $this->productFactory = $productFactory;
    $this->productResourceModel = $productResourceModel;
}


private function setStoreViewPrice($productId, $storeId, $price)
{
    $product = $this->productFactory->create();
    $this->productResourceModel->load($product, $productId);
    $product->setStoreId($storeId);
    $product->setPrice($price);
    $this->productResourceModel->saveAttribute($product, 'price');
}

See also https://magento.stackexchange.com/a/114958/35180

2
  • 1
    It is good for update but what about creating a product?
    – Sarvagya
    Commented Mar 23, 2018 at 9:47
  • Working great for product visibility attribute !!!! thanks @Patrick Commented Jan 24, 2020 at 14:12
2

As of today no fix has been released by Magento and there are several others having similar issues. There are also many issues on Github describing the same (or similar) problems.

My only work-around right now is to "reset" the fields that M2 feels the need to update.

$this->objectManager->create('Magento\Catalog\Model\Product')
    ->load($product->getId())
    ->setStoreId($storeviewId)
    ->setStatus($storeStatus)
    ->setDescription('Store description')
    ->setName(null) // Use default
    ->setPrice($price) // Store price
    ->setTaxClassId(null) // Use default
    ->setVisibility(null) // Use default
    ->setCountryOfManufacture(null) // Use default
    ->save();
1

// Reload product

$productStoreView = $this->productFactory->create()
  ->load($productModel->getId());

 $productStoreView->setDescription('Desc for store view 1');
 $productStoreView->setStoreId(1);
 $productStoreView->save();
1
  • I've updated the main issue with new information, this answer isn't fixing the issue :(
    – Robban
    Commented Jan 30, 2017 at 10:02
0

I think you have to set storeId after loading product object. I have tried in my system and it is working fine.

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $objectManager->create('Magento\Catalog\Model\Product')->load(2)->setStoreId(1)->setDescription('english content')->save();
        $objectManager->create('Magento\Catalog\Model\Product')->load(2)->setStoreId(2)->setDescription('french content')->save();

I know direct loading of object manager is not good but I have created simple script to check is it working or not.

1
  • I've updated the main issue with new information, this answer isn't fixing the issue :(
    – Robban
    Commented Jan 30, 2017 at 10:01
0

In oder to set different store specific attribute values for a product in different stores of a Magento2 installation, the class \Magento\Catalog\Model\ResourceModel\Product\Action::class can be used:

/**
 * Sets different values for an attribute, depending on the store.
 * 
 * This example sets the hs code attribute of product 123 to 111111 for the UK and 222222 for AU.
 */
public function testSetProductAttributes()
{
    $storeIdUK = 1;
    $storeIdAU = 2;

    $product_id = 123;

    $hs_code_uk = '111111';
    $hs_code_au = '222222';

    $attrDataUK = [
      'hs_code' => $hs_code_uk
    ];
    $attrDataAU = [
      'hs_code' => $hs_code_au
    ];

    $productAction = $this->_objectManager->get(\Magento\Catalog\Model\ResourceModel\Product\Action::class);

    $productAction->updateAttributes([$product_id], $attrDataUK, $storeIdUK);
    $productAction->updateAttributes([$product_id], $attrDataAU, $storeIdAU);
}

This works for me in Magento 2.2.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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