Store-Specific Product Prices Not Working in Magento 2
We encountered the issue that if we change the price of a product in a specific store view, the price would not change and the “Use default” checkbox was still checked. However, we did not want to use the default price from the global level, but wanted to have a store-specific price.
After some debugging, we found out that the product
price attributes were defined to be global. You can check this with the following query:
SELECT `is_global` FROM `catalog_eav_attribute` WHERE `attribute_id` IN ( SELECT `attribute_id` FROM `eav_attribute` WHERE `frontend_input` = 'price' );
The meaning of the returned values can be looked up at
0means that the attribute scope is store.
1means that the attribute scope is global.
2means that the attribute scope is website.
We expected this to be
2 / website, but it was still
1 / global in our case - even though we configured Stores > Configuration > Catalog > Catalog > Price > Catalog Price Scope (
catalog/price/scope) to be “Website”. We saw that we locked this configuration value in
app/etc/config.php. After some further debugging, we bumped into the observer
Magento\Catalog\Observer\SwitchPriceAttributeScopeOnConfigChange. It is called on each configuration change in the
catalog area and sets the scope of the price attributes according to the setting
catalog/price/scope. Since we locked this value via
bin/magento and did not set it via the administration panel, this observer was never called, so the scope of the price attributes remained global.
We came up with multiple ideas to fix this issue:
Simply change an unimportant setting in the catalog section (and revert the change afterwards), so that the observer is called.
Call the observer manually in a REPL console via
Remove the lock from
app/etc/config.phpand set the desired value via the administration panel.
Change the attribute scope in the database directly via:
UPDATE `catalog_eav_attribute` SET `is_global` = 2 WHERE `attribute_id` IN ( SELECT `attribute_id` FROM `eav_attribute` WHERE `frontend_input` = 'price' );
In the end, it does not matter which solution you implement - all these suggestions should fix the issue. Even though this can be considered an edge case, it is a rather poor implementation choice by Adobe / Magento to rely on an observer being called, which is simply not happening if you lock the configuration value with
bin/magento config:set --lock-env or