Store-Specific Product Prices Not Working in Magento 2
The Error
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.
Debugging
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 Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface
:
0
means that the attribute scope is store.1
means that the attribute scope is global.2
means 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.
Possible Solutions
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
n98-magerun2.phar dev:console
.Remove the lock from
app/etc/config.php
and 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 --lock-config
respectively.