8

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

5 Answers 5

14

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);
}
1
  • You answer helped me with a task I am working on. Thanks
    – diazwatson
    Commented Jul 31, 2018 at 13:26
16

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);
1
  • If you have some values in store_id 1then it won't be updated with this method. BUT you can do foreach on store_ids (0,1,etc) and call save() from \Magento\Catalog\Api\ProductRepositoryInterface Commented Sep 24, 2018 at 21:42
2

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.

1
  • 1
    This works pretty well, but keep in mind that this skips the Product Model call save() so it skips all the Observers and Plugins that hook into it. For example generating an URL key based on Product Name will not work.
    – Jacques
    Commented Oct 2, 2019 at 14:44
2

@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);
    }
}
1

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

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.