get_route(); // Gate both the free (/thinkrank/v1/) and Pro (/thinkrank-pro/v1/) // namespaces so the Role Manager governs Pro sections too — otherwise the // whole Pro namespace bypasses the capability gate. if (strpos($route, '/thinkrank/v1/') !== 0 && strpos($route, '/thinkrank-pro/v1/') !== 0) { return $result; } // MCP + OAuth routes authenticate INSIDE their handlers (Bearer token / // OAuth access token — server-to-server calls with no logged-in user), // so the namespace-wide capability gate must not touch them. The MCP // management routes (/mcp/connection, /mcp/connect, …) stay gated. See // ThinkRank\Mcp\Mcp_Manager. if ('/thinkrank/v1/mcp' === $route || strpos($route, '/thinkrank/v1/mcp/oauth/') === 0) { return $result; } if (!Capability_Manager::current_user_can(Capability_Manager::ACCESS)) { return new WP_Error( 'thinkrank_forbidden', __('You do not have permission to access ThinkRank.', 'thinkrank'), ['status' => rest_authorization_required_code()] ); } $capability = Capability_Manager::capability_for_route($route); if ($capability !== Capability_Manager::ACCESS && !Capability_Manager::current_user_can($capability)) { return new WP_Error( 'thinkrank_forbidden_section', __('You do not have permission to access this ThinkRank section.', 'thinkrank'), ['status' => rest_authorization_required_code()] ); } return $result; } }