Question

I want to update product information for "All Store Views" but it seems that when I try to update a product, Magento ignores setStoreId(0). Instead the product information will be saved to store view 1.

For reference I have 4 store views: 1, 2, 3, 4 + store view 0 (admin).

enter image description here

My code:

$collection = $this->filter->getCollection($this->collectionFactory->create());

foreach ($collection->getAllIds() AS $productId)
{
    $product = $this->productRepository->getById($productId);

    $product->setStoreId(0);
    $product->setSpecialPrice(111);

    $this->productRepository->save($product);
}
Was it helpful?

Solution

If you only need to change a single product attribute, the product model has an addAttributeUpdate() method that takes store_id as a parameter:

$store_id = 0; // or 1,2,3,... ?
$attribute_code = 'name';
$value = 'Storeview Specific Name';

$product->addAttributeUpdate($attribute_code, $value, $store_id);

Looking at the method in ./vendor/magento/module-catalog/Model/Product.php - it automatically does the "save the current store code and switch back after the update" thing that mcyrulik's answer does,

## ./vendor/magento/module-catalog/Model/Product.php

/**
 * Save current attribute with code $code and assign new value
 *
 * @param string $code  Attribute code
 * @param mixed  $value New attribute value
 * @param int    $store Store ID
 * @return void
 */
public function addAttributeUpdate($code, $value, $store)
{
    $oldValue = $this->getData($code);
    $oldStore = $this->getStoreId();

    $this->setData($code, $value);
    $this->setStoreId($store);
    $this->getResource()->saveAttribute($this, $code);

    $this->setData($code, $oldValue);
    $this->setStoreId($oldStore);
}

OTHER TIPS

I've noticed the same thing - Magento 2 ignores this:

$product->setStoreId(0);

So what we've done thats seems to allow us to achieve what you are trying to do is to use the \Magento\Store\Model\StoreManagerInterface instead.

In your constructor

public function __construct(
    \Magento\Store\Model\StoreManagerInterface $storeManager
) {
    $this->_storeManager = $storeManager;
} 

Then in your code before you try to update the products you can do:

$this->_storeManager->setCurrentStore(0);

Tip: I've started doing this though, to make sue that the appropriate store gets put back when I'm done:

$originalStoreId = $this->_storeManager->getStore()->getId();
$this->_storeManager->setCurrentStore(0);
// Do other things...
$this->_storeManager->setCurrentStore($originalStoreId);

You can use \Magento\Catalog\Model\ResourceModel\Product\Action like this:

public function __construct(
    \Magento\Catalog\Model\ResourceModel\Product\Action $productAction
) {
    $this->productAction = $productAction;
} 

And then quickly update atributes:

$this->productAction->updateAttributes(
    [$row->getProductId()], //array with product id's
    [
        $row->getAttributeCode() => $row->getAttributeValue(),
        $row->getOtherAttributeCode() => $row->getOtherAttributeValue()
    ],
    $storeId
);

This is especially good (fast) for changing attributes to many products at once.

@Silas Palmer solution seems a better approach to me to solve your issue, but if you still have issues setting the default store id, you set the store id using an observer on catalog_product_save_before.

1.Creates the events.xml (I am placing mine in frontend)

<!-- /magento/app/code/VendorName/ModuleName/etc/frontend/events.xml -->
<?xml version="1.0" encoding="UTF-8"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
        <event name="catalog_product_save_before">
            <observer name="your_observer_name" instance="Vendor\YouModule\Observer\YourObserverName"/>
        </event>
    </config>

2.Set the store id using the observer

<?php
// magento/app/code/VendorName/ModuleName/Observer/YourObserverName.php
namespace VendorName\ModuleName\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Store\Model\Store;

class YourObserverName implements ObserverInterface
{

    /**
     * @param Observer $observer
     * @return void
     */
    public function execute(Observer $observer)
    {
        $product = $observer->getData('product');
        $product->setData('store_id', Store::DEFAULT_STORE_ID);
    }
}

I'm also investigating this issue, for some reason it seams that we can't update the Admin Store View data using product repository.

You have to get the product using the repository like this,

$product = $this->productRepository->getById($productId, true, 0); // added edit mode and storeview id

Set the data you want

$product->setName('Test');

and then just save using the save function

$product->save();

Repeate the process for each storeview, or just update the attribute using the methods given above

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