Getting the product stock status programatically in Magento 2 with and without MSI
In this article, I will show how to get the stock status of the product programmatically in Magento 2. I will also show how the new MSI feature in Magento 2.3 makes it a bit more complex to get the stock data and how to overcome this problem.
Magento 2.1 and 2.2
The code
Here is the code that gets the product stock status for Magento 2.1 and 2.2:
class Myclass{
protected $stockRegistryProvider;
public function __construct(\Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface $stockRegistryProvider){
$this->stockRegistryProvider = $stockRegistryProvider;
}
public function getStockStatus($store, $product){
$websiteId = $store->getWebsiteId();
$stockItem = $this->stockRegistryProvider->getStockItem($product->getId(), $websiteId);
$status = $stockItem->getIsInStock();
if($status === null){
$stockItem = $this->stockRegistryProvider->getStockItem($product->getId(), $this->stockConfiguration->getDefaultScopeId());
$status = $stockItem->getIsInStock();
}
return $status;
}
}
Magento 2.3
The MSI and the new Magento approach
In the 2.3 version, Magento introduced the new MSI (Multi-Source Inventory) functionality. We can observe in the Magento core code that whenever Magento needs to fetch stock data, it first tries to fetch it from the MSI, and if it doesn’t succeed - it falls back to the old inventory module.
You can see it for example in vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/Helper/Stock/AdaptAssignStatusToProductPlugin.php function aroundAssignStatusToProduct:
public function aroundAssignStatusToProduct(
Stock $subject,
callable $proceed,
Product $product,
$status = null
) {
if (null === $product->getSku()) {
return;
}
try {
$this->getProductIdsBySkus->execute([$product->getSku()]);
if (null === $status) {
$stockId = $this->getStockIdForCurrentWebsite->execute();
$status = (int)$this->isProductSalable->execute($product->getSku(), $stockId);
}
$proceed($product, $status);
} catch (NoSuchEntityException $e) {
return;
}
}
This is a plugin that wraps the old \Magento\CatalogInventory\Helper::assignStatusToProduct function. The plugin first tries to fetch the stock status from the MSI, and then it passes the result to the old assignStatusToProduct function. Then if the result is null, the old function tries to fetch the status from the old inventory module.
The code
Therefore, to get the product stock status in Magento 2.3, use the following code:
class Myclass{
protected $stockRegistryProvider;
public function __construct(\Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface $stockRegistryProvider){
$this->stockRegistryProvider = $stockRegistryProvider;
}
public function getStockStatus($store, $product){
$stock = $this->stockResolver->execute(\Magento\InventorySalesApi\Api\Data\SalesChannelInterface::TYPE_WEBSITE, $store->getWebsite()->getCode());
$stockId = (int)$stock->getStockId();
$status = (int)$this->isProductSalable->execute($product->getSku(), $stockId);
if ($status === null) {
$websiteId = $store->getWebsiteId();
$stockItem = $this->stockRegistryProvider->getStockItem($product->getId(), $websiteId);
$status = $stockItem->getIsInStock();
if($status === null){
$stockItem = $this->stockRegistryProvider->getStockItem($product->getId(), $this->stockConfiguration->getDefaultScopeId());
$status = $stockItem->getIsInStock();
}
}
return $status;
}
}
Summing up
Getting the product stock status in Magento 2 was never easy, but with the introduction of the new MSI feature in Magento 2.3, it became even more complicated. In this article, I showed you how to do that in Magento 2.1, 2.2 and 2.3. I hope that it was helpful.