Commit 64cbb8d3cc9 for woocommerce

commit 64cbb8d3cc9d3c698b8fba47c9335d8cd8466f02
Author: Barry Hughes <3594411+barryhughes@users.noreply.github.com>
Date:   Wed Oct 28 15:59:35 2026 -0700

    Include the System Status Report in the Beta Tester bug report link and handle object-typed fields (#69959)

    * Include the SSR in the Beta Tester bug report and print object-typed fields as JSON

    construct_ssr() checked class_exists( 'WC' ), which is always false because
    WC() is a function, so the "Submit bug report" link never carried the System
    Status Report. Fixing the check exposed a second problem: the builder casts
    each environment field to its schema type and prints it with sprintf(), which
    fatals on object-typed fields such as the environment.action_scheduler field
    added by #69882. Object and array values are now printed as JSON, fields
    without a schema description fall back to their key, and WC_Plugin_Updates is
    included explicitly instead of relying on get_plugin_data() having loaded it.

    Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

    * Build only the environment section when constructing the SSR

    get_item_mappings() is deprecated since WooCommerce 3.9 and computes all
    eleven report sections, while the bug report only reads the environment one.

    Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

    * Build the SSR only for users with manage_woocommerce

    * Leave private paths out of the beta tester SSR

    ---------

    Co-authored-by: The Original Barry Hughes <robotic.code@gmail.com>
    Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>

diff --git a/plugins/woocommerce-beta-tester/changelog/fix-wooplug-8034-beta-tester-ssr b/plugins/woocommerce-beta-tester/changelog/fix-wooplug-8034-beta-tester-ssr
new file mode 100644
index 00000000000..d21ebebdb6c
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/changelog/fix-wooplug-8034-beta-tester-ssr
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Include the System Status Report in the "Submit bug report" link again, for users who may view it, and print object-typed report fields as JSON.
diff --git a/plugins/woocommerce-beta-tester/changelog/fix-wooplug-8034-beta-tester-ssr-private-paths b/plugins/woocommerce-beta-tester/changelog/fix-wooplug-8034-beta-tester-ssr-private-paths
new file mode 100644
index 00000000000..e61ae8c26d2
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/changelog/fix-wooplug-8034-beta-tester-ssr-private-paths
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Leave server paths out of the System Status Report in the "Submit bug report" link, as the Status page copy does.
diff --git a/plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php b/plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php
index 52064399528..a8d14f3667e 100644
--- a/plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php
+++ b/plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php
@@ -12,6 +12,16 @@ defined( 'ABSPATH' ) || exit;
  */
 class WC_Beta_Tester_Admin_Menus {

+	/**
+	 * Environment values the WooCommerce Status page marks private and leaves out of its copyable report.
+	 *
+	 * Nested keys use dot notation.
+	 */
+	private const PRIVATE_KEYS = array(
+		'log_directory',
+		'action_scheduler.source_path', // Added to the environment section by WooCommerce PR #69882.
+	);
+
 	/**
 	 * Constructor
 	 */
@@ -147,16 +157,97 @@ Copy and paste the system status report from **WooCommerce > System Status** in
 		return $plugins_info;
 	}

+	/**
+	 * Get the environment section of the SSR, one "label: value" line per field.
+	 *
+	 * Object and array values are printed as JSON. Private values (see PRIVATE_KEYS) are left out.
+	 *
+	 * @param array|object $environment Environment values, already cast to their schema types.
+	 * @param array        $properties  The environment properties of the system status schema.
+	 * @return string
+	 */
+	private function get_environment_ssr_info( $environment, $properties ) {
+		$ssr = '';
+
+		foreach ( $environment as $key => $value ) {
+			if ( in_array( $key, self::PRIVATE_KEYS, true ) ) {
+				continue;
+			}
+
+			if ( 'external_object_cache' === $key ) {
+				$ssr .= sprintf( "%s: %s\n", 'External object cache', wc_bool_to_string( $value ) );
+				continue;
+			}
+
+			if ( is_bool( $value ) ) {
+				$value = wc_bool_to_string( $value );
+			} elseif ( is_array( $value ) || is_object( $value ) ) {
+				$value = wp_json_encode( $this->remove_private_keys( $value, $key ) );
+			}
+
+			$label = $properties[ $key ]['description'] ?? $key;
+			$ssr  .= sprintf( "%s: %s\n", $label, $value );
+		}
+
+		return $ssr;
+	}
+
+	/**
+	 * Remove the private keys nested under an environment field before it is printed as JSON.
+	 *
+	 * @param array|object $value Field value.
+	 * @param string       $key   Field key, the first segment of each dotted private key.
+	 * @return array|object
+	 */
+	private function remove_private_keys( $value, $key ) {
+		foreach ( self::PRIVATE_KEYS as $private_key ) {
+			$segments = explode( '.', $private_key );
+
+			if ( array_shift( $segments ) === $key && ! empty( $segments ) ) {
+				$value = $this->remove_key_path( $value, $segments );
+			}
+		}
+
+		return $value;
+	}
+
+	/**
+	 * Remove one key path from a nested array or object. The value comes back as an array.
+	 *
+	 * @param array|object $value    Value to remove the key from.
+	 * @param string[]     $segments Key path, outermost segment first.
+	 * @return array
+	 */
+	private function remove_key_path( $value, array $segments ) {
+		$value   = (array) $value;
+		$segment = array_shift( $segments );
+
+		if ( empty( $segments ) ) {
+			unset( $value[ $segment ] );
+		} elseif ( isset( $value[ $segment ] ) && ( is_array( $value[ $segment ] ) || is_object( $value[ $segment ] ) ) ) {
+			$value[ $segment ] = $this->remove_key_path( $value[ $segment ], $segments );
+		}
+
+		return $value;
+	}
+
 	/**
 	 * Constructs a WC System Status Report.
 	 *
+	 * The report is embedded in the admin bar markup of every wp-admin page, so it is only built for
+	 * users who may view the System Status page. Everyone else gets an empty string.
+	 *
 	 * @return string
 	 */
 	protected function construct_ssr() {
+		if ( ! current_user_can( 'manage_woocommerce' ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown -- WooCommerce capability, the same gate core uses for the status page.
+			return '';
+		}
+
 		// This function depends on the WC core global being available. Sometimes, such as when we deactivate
 		// WC to install a live branches version, WC will not be available and cause a crash if we don't exit early
 		// here.
-		if ( ! class_exists( 'WC' ) ) {
+		if ( ! function_exists( 'WC' ) ) {
 			return '';
 		}

@@ -175,7 +266,7 @@ Copy and paste the system status report from **WooCommerce > System Status** in
 			// Get SSR.
 			$api      = new WC_REST_System_Status_Controller();
 			$schema   = $api->get_item_schema();
-			$mappings = $api->get_item_mappings();
+			$mappings = $api->get_item_mappings_per_fields( array( 'environment' ) );
 			$response = array();

 			foreach ( $mappings as $section => $values ) {
@@ -188,19 +279,10 @@ Copy and paste the system status report from **WooCommerce > System Status** in
 				$response[ $section ] = $values;
 			}

-			$ssr = '';
-			foreach ( $response['environment'] as $key => $value ) {
-				$index = $key;
-				if ( 'external_object_cache' === $index ) {
-					$ssr .= sprintf( "%s: %s\n", 'External object cache', wc_bool_to_string( $value ) );
-					continue;
-				}
-
-				if ( is_bool( $value ) ) {
-					$value = wc_bool_to_string( $value );
-				}
+			$ssr = $this->get_environment_ssr_info( $response['environment'], $schema['properties']['environment']['properties'] );

-				$ssr .= sprintf( "%s: %s\n", $schema['properties']['environment']['properties'][ $index ]['description'], $value );
+			if ( ! class_exists( 'WC_Plugin_Updates' ) ) {
+				include_once WC_ABSPATH . 'includes/admin/plugin-updates/class-wc-plugin-updates.php';
 			}

 			$active_plugins   = $api->get_active_plugins();