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.
 	 */