Commit 6f6db1a2be5 for woocommerce
commit 6f6db1a2be59f657ca9a75b6d42d7b95e72b948d
Author: louwie17 <lourensschep@gmail.com>
Date: Thu Jun 4 14:09:26 2026 +0200
Fix: Allow view_woocommerce_reports cap to access Analytics Leaderboards endpoint (#65492)
* Allow view_woocommerce_reports cap to access Analytics Leaderboards endpoint
The Leaderboards REST controller extends WC_REST_Data_Controller, whose
inherited get_items_permissions_check requires manage_woocommerce. Other
Analytics report controllers gate on view_woocommerce_reports instead.
Override the permission callback locally to match sibling endpoints so
users with view_woocommerce_reports (but not manage_woocommerce) can see
leaderboard tiles on the Analytics > Overview screen.
Closes #39366
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Preserve manage_woocommerce access for back-compat
Accept either view_woocommerce_reports or manage_woocommerce so any
custom role that previously relied on the inherited manage_woocommerce
check continues to reach the Leaderboards endpoint. Mirrors the OR'd
cap pattern used by the analytics dashboard widget.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/fix-39366 b/plugins/woocommerce/changelog/fix-39366
new file mode 100644
index 00000000000..5e9db33fc4a
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-39366
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Allow users with the `view_woocommerce_reports` capability to access the Analytics Leaderboards REST endpoint and view leaderboard data.
diff --git a/plugins/woocommerce/src/Admin/API/Leaderboards.php b/plugins/woocommerce/src/Admin/API/Leaderboards.php
index 2638462792d..9ac10ec8837 100644
--- a/plugins/woocommerce/src/Admin/API/Leaderboards.php
+++ b/plugins/woocommerce/src/Admin/API/Leaderboards.php
@@ -87,6 +87,30 @@ class Leaderboards extends \WC_REST_Data_Controller {
);
}
+ /**
+ * Check whether a given request has permission to read leaderboards.
+ *
+ * Leaderboards expose analytics report data, so allow users with the
+ * `view_woocommerce_reports` capability to access the endpoint (matching
+ * other Analytics report endpoints). The `manage_woocommerce` check is
+ * preserved for backwards compatibility with the previous behavior
+ * inherited from `\WC_REST_Data_Controller`, so users granted only the
+ * broader manage capability are not regressed.
+ *
+ * @param \WP_REST_Request<array<string, mixed>> $request Full details about the request.
+ * @return \WP_Error|boolean
+ */
+ public function get_items_permissions_check( $request ) {
+ if (
+ ! wc_rest_check_manager_permissions( 'reports', 'read' )
+ && ! wc_rest_check_manager_permissions( 'settings', 'read' )
+ ) {
+ return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
+ }
+
+ return true;
+ }
+
/**
* Get the data for the coupons leaderboard.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/leaderboards.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/leaderboards.php
index 30eada7f88d..3a20f440e18 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/leaderboards.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/leaderboards.php
@@ -161,6 +161,60 @@ class WC_Admin_Tests_API_Leaderboards extends WC_REST_Unit_Test_Case {
$this->assertArrayHasKey( 'label', $header_properties );
}
+ /**
+ * Test that a user with only the `view_woocommerce_reports` capability can
+ * read the leaderboards endpoint.
+ *
+ * Regression test for woocommerce/woocommerce#39366.
+ */
+ public function test_get_leaderboards_with_view_woocommerce_reports_cap() {
+ $user_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+ $user = new WP_User( $user_id );
+ $user->add_cap( 'view_woocommerce_reports' );
+ wp_set_current_user( $user_id );
+
+ $request = new WP_REST_Request( 'GET', $this->endpoint );
+ $response = $this->server->dispatch( $request );
+ $this->assertEquals( 200, $response->get_status() );
+
+ $request = new WP_REST_Request( 'GET', $this->endpoint . '/allowed' );
+ $response = $this->server->dispatch( $request );
+ $this->assertEquals( 200, $response->get_status() );
+
+ $request = new WP_REST_Request( 'GET', $this->endpoint . '/products' );
+ $response = $this->server->dispatch( $request );
+ $this->assertEquals( 200, $response->get_status() );
+ }
+
+ /**
+ * Test that a user with only the `manage_woocommerce` capability can read
+ * the leaderboards endpoint (backwards compatibility with the previous
+ * behavior inherited from `\WC_REST_Data_Controller`).
+ */
+ public function test_get_leaderboards_with_manage_woocommerce_cap() {
+ $user_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+ $user = new WP_User( $user_id );
+ $user->add_cap( 'manage_woocommerce' );
+ wp_set_current_user( $user_id );
+
+ $request = new WP_REST_Request( 'GET', $this->endpoint );
+ $response = $this->server->dispatch( $request );
+ $this->assertEquals( 200, $response->get_status() );
+ }
+
+ /**
+ * Test that a user without report-viewing capabilities is denied access to
+ * the leaderboards endpoint.
+ */
+ public function test_get_leaderboards_without_capabilities_is_denied() {
+ $user_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+ wp_set_current_user( $user_id );
+
+ $request = new WP_REST_Request( 'GET', $this->endpoint );
+ $response = $this->server->dispatch( $request );
+ $this->assertEquals( 403, $response->get_status() );
+ }
+
/**
* Test that leaderboards response changes based on applied filters.
*/