From 15dd9a0c508e519fe25e002c0fbdff9a49e1243a Mon Sep 17 00:00:00 2001 From: Luke Holder Date: Tue, 18 Aug 2026 23:04:57 +0800 Subject: [PATCH 1/2] Fix fatal error in dashboard widgets when user has no editable sites Cp::requestedSite() returns null when the current user has no editable sites, causing a fatal error on ->getStore() in every Commerce widget's init(). Fall back to the primary store in that case, matching the pattern used elsewhere in the codebase. Fixes #4347 --- CHANGELOG.md | 4 ++++ src/widgets/AverageOrderTotal.php | 5 +++-- src/widgets/NewCustomers.php | 5 +++-- src/widgets/Orders.php | 4 ++-- src/widgets/RepeatCustomers.php | 5 +++-- src/widgets/TopCustomers.php | 5 +++-- src/widgets/TopProductTypes.php | 5 +++-- src/widgets/TopProducts.php | 5 +++-- src/widgets/TopPurchasables.php | 5 +++-- src/widgets/TotalOrders.php | 5 +++-- src/widgets/TotalOrdersByCountry.php | 5 +++-- src/widgets/TotalRevenue.php | 5 +++-- 12 files changed, 36 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fad0250f5..f751c33a08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Release Notes for Craft Commerce +## Unreleased + +- Fixed a bug where the Commerce dashboard widgets could cause a PHP error for users without edit permissions on any site. ([#4347](https://github.com/craftcms/commerce/issues/4347)) + ## 5.7.2 - 2026-08-12 - Fixed a bug where inactive carts’ search index rows weren’t being purged. ([#4344](https://github.com/craftcms/commerce/issues/4344)) diff --git a/src/widgets/AverageOrderTotal.php b/src/widgets/AverageOrderTotal.php index 271438042b..054ff820a3 100644 --- a/src/widgets/AverageOrderTotal.php +++ b/src/widgets/AverageOrderTotal.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\AverageOrderTotal as AverageOrderTotalStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -45,9 +46,9 @@ public function init(): void parent::init(); if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->_stat = new AverageOrderTotalStat( diff --git a/src/widgets/NewCustomers.php b/src/widgets/NewCustomers.php index 76225e08a9..c9583d0047 100644 --- a/src/widgets/NewCustomers.php +++ b/src/widgets/NewCustomers.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\NewCustomers as NewCustomersStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -47,9 +48,9 @@ public function init(): void parent::init(); if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->_stat = new NewCustomersStat( diff --git a/src/widgets/Orders.php b/src/widgets/Orders.php index baf0ee6ad4..dfcacc2790 100644 --- a/src/widgets/Orders.php +++ b/src/widgets/Orders.php @@ -43,9 +43,9 @@ public function init(): void parent::init(); if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } } diff --git a/src/widgets/RepeatCustomers.php b/src/widgets/RepeatCustomers.php index 153b310edb..03ce914a5e 100644 --- a/src/widgets/RepeatCustomers.php +++ b/src/widgets/RepeatCustomers.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\RepeatCustomers as RepeatingCustomersStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -45,9 +46,9 @@ public function init(): void parent::init(); if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->dateRange = !isset($this->dateRange) || !$this->dateRange ? RepeatingCustomersStat::DATE_RANGE_TODAY : $this->dateRange; diff --git a/src/widgets/TopCustomers.php b/src/widgets/TopCustomers.php index 3202a06d3f..2eacdb3681 100644 --- a/src/widgets/TopCustomers.php +++ b/src/widgets/TopCustomers.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\TopCustomers as TopCustomersStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -60,9 +61,9 @@ class TopCustomers extends Widget public function init(): void { if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->_typeOptions = [ diff --git a/src/widgets/TopProductTypes.php b/src/widgets/TopProductTypes.php index a497e7ef79..f7093e0680 100644 --- a/src/widgets/TopProductTypes.php +++ b/src/widgets/TopProductTypes.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\TopProductTypes as TopProductTypesStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -60,9 +61,9 @@ class TopProductTypes extends Widget public function init(): void { if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->_typeOptions = [ diff --git a/src/widgets/TopProducts.php b/src/widgets/TopProducts.php index bc4705e52b..68a82fc641 100644 --- a/src/widgets/TopProducts.php +++ b/src/widgets/TopProducts.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\TopProducts as TopProductsStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -77,9 +78,9 @@ public function init(): void parent::init(); if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->_typeOptions = [ diff --git a/src/widgets/TopPurchasables.php b/src/widgets/TopPurchasables.php index 953ab96a24..06eaba3c62 100644 --- a/src/widgets/TopPurchasables.php +++ b/src/widgets/TopPurchasables.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\TopPurchasables as TopPurchasablesStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -70,9 +71,9 @@ class TopPurchasables extends Widget public function init(): void { if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->nameField = isset($this->nameField) ?: 'description'; diff --git a/src/widgets/TotalOrders.php b/src/widgets/TotalOrders.php index b60d591b3d..b316ea26cb 100644 --- a/src/widgets/TotalOrders.php +++ b/src/widgets/TotalOrders.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\TotalOrders as TotalOrdersStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -49,9 +50,9 @@ public function init(): void parent::init(); if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->dateRange = !isset($this->dateRange) || !$this->dateRange ? TotalOrdersStat::DATE_RANGE_TODAY : $this->dateRange; diff --git a/src/widgets/TotalOrdersByCountry.php b/src/widgets/TotalOrdersByCountry.php index 5b864e7b22..2931cded64 100644 --- a/src/widgets/TotalOrdersByCountry.php +++ b/src/widgets/TotalOrdersByCountry.php @@ -11,6 +11,7 @@ use craft\base\Widget; use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; +use craft\commerce\Plugin; use craft\commerce\stats\TotalOrdersByCountry as TotalOrdersByCountryStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -63,9 +64,9 @@ public function init(): void parent::init(); if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->_typeOptions = [ diff --git a/src/widgets/TotalRevenue.php b/src/widgets/TotalRevenue.php index 34f0190dd6..a3af34f05e 100644 --- a/src/widgets/TotalRevenue.php +++ b/src/widgets/TotalRevenue.php @@ -12,6 +12,7 @@ use craft\commerce\base\StatWidgetTrait; use craft\commerce\behaviors\StoreBehavior; use craft\commerce\helpers\Currency; +use craft\commerce\Plugin; use craft\commerce\stats\TotalRevenue as TotalRevenueStat; use craft\commerce\web\assets\commercewidgets\CommerceWidgetsAsset; use craft\commerce\web\assets\statwidgets\StatWidgetsAsset; @@ -71,9 +72,9 @@ public function init(): void parent::init(); if (!(isset($this->storeId)) || !$this->storeId) { - /** @var Site|StoreBehavior $site */ + /** @var Site|StoreBehavior|null $site */ $site = Cp::requestedSite(); - $this->storeId = $site->getStore()->id; + $this->storeId = $site?->getStore()->id ?? Plugin::getInstance()->getStores()->getPrimaryStore()->id; } $this->dateRange = !isset($this->dateRange) || !$this->dateRange ? TotalRevenueStat::DATE_RANGE_TODAY : $this->dateRange; From 7566714eba6b2d3dbe01c5201c35b15f14c9defd Mon Sep 17 00:00:00 2001 From: Nathaniel Hammond Date: Tue, 8 Sep 2026 08:11:14 +0100 Subject: [PATCH 2/2] Fix changelog merge --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28b2314941..a38f746c79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,15 @@ # Release Notes for Craft Commerce -## 5.7.3 - 2026-09-02 +## Unreleased - Fixed a PHP error on the dashboard that could occur for users without edit permissions on any site. ([#4347](https://github.com/craftcms/commerce/issues/4347)) + +## 5.7.3 - 2026-09-02 + - Fixed a bug where `craft\commerce\elements\Order::setShippingAddress()` and `setBillingAddress()` weren’t setting custom field values. ([#4353](https://github.com/craftcms/commerce/issues/4353)) -- Fixed a bug where the deprecated `craft\commerce\services\ProductTypes::getEditableProductTypes()` method could still be called. ([#4349](https://github.com/craftcms/commerce/issues/4349)) - Fixed a bug where variants’ auto-generated SKUs would be incorrect if the SKU Format contained `{id}`. - Fixed a bug where adding a new site via project config apply could cause additional project config changes. ([#4348](https://github.com/craftcms/commerce/issues/4348)) +- Fixed a deprecation warning that was getting logged when accessing `/admin/commerce`. ([#4349](https://github.com/craftcms/commerce/issues/4349)) ## 5.7.2 - 2026-08-12