Commit d569e1bbba8 for woocommerce
commit d569e1bbba868f3f7575c4e73eb478ca5674c854
Author: louwie17 <lourensschep@gmail.com>
Date: Tue Nov 10 17:53:04 2026 +0100
Hide dashboard status widget sales rows without Analytics, drop legacy report coupling (#70537)
* Hide status widget sales rows without Analytics and drop legacy report coupling
The WooCommerce Status dashboard widget no longer falls back to legacy
reports when Analytics is off: the net sales and top seller rows are hidden,
while order and stock rows stay. The woocommerce_dashboard_status_widget_reports
filter still fires, so an extension can still supply sales data.
The woocommerce_after_dashboard_status_widget_parameter filter now only builds
a WC_Admin_Report when a callback listens to woocommerce_after_dashboard_status_widget,
because extensions still call $reports->sales_sparkline() there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zLZuyA6EbDi4AZPQLKroq
* Fill in legacy status widget data when another callback hooks the reports filter
A callback on woocommerce_dashboard_status_widget_reports that adjusts
report_data->net_sales got null with Analytics off and crashed the widget.
Legacy reports now fill in the sales data first when another callback is
hooked, as on trunk; without one the sales rows stay hidden. Also document
the filter's array shape and use string assertions in the tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zLZuyA6EbDi4AZPQLKroq
* Pass the legacy report to other status widget parameter filter callbacks
Callbacks on woocommerce_after_dashboard_status_widget_parameter that run
after core received a WC_Admin_Report on trunk; build it for them too.
Share the "another callback is hooked" check, and only reject Analytics
links in the Analytics-off widget test, since the subscriptions row also
links to wc-admin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zLZuyA6EbDi4AZPQLKroq
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/wooplug-7854-dashboard-status-widget-legacy-reports b/plugins/woocommerce/changelog/wooplug-7854-dashboard-status-widget-legacy-reports
new file mode 100644
index 00000000000..720fe39409d
--- /dev/null
+++ b/plugins/woocommerce/changelog/wooplug-7854-dashboard-status-widget-legacy-reports
@@ -0,0 +1,4 @@
+Significance: patch
+Type: update
+
+Hide the sales rows in the WooCommerce Status dashboard widget when Analytics is turned off, instead of using legacy reports.
diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-dashboard.php b/plugins/woocommerce/includes/admin/class-wc-admin-dashboard.php
index 2497ef7ee6e..98cdb81dc22 100644
--- a/plugins/woocommerce/includes/admin/class-wc-admin-dashboard.php
+++ b/plugins/woocommerce/includes/admin/class-wc-admin-dashboard.php
@@ -170,27 +170,47 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
//phpcs:ignore
$is_wc_admin_disabled = apply_filters( 'woocommerce_admin_disabled', false ) || ! FeaturesUtil::feature_is_enabled( 'analytics' );
- $status_widget_reports = array(
- 'net_sales_link' => 'admin.php?page=wc-admin&path=%2Fanalytics%2Frevenue&chart=net_revenue&orderby=net_revenue&period=month&compare=previous_period',
- 'top_seller_link' => 'admin.php?page=wc-admin&filter=single_product&path=%2Fanalytics%2Fproducts&products=',
- 'lowstock_link' => 'admin.php?page=wc-admin&type=lowstock&path=%2Fanalytics%2Fstock',
- 'outofstock_link' => 'admin.php?page=wc-admin&type=outofstock&path=%2Fanalytics%2Fstock',
- 'report_data' => null,
- 'get_sales_sparkline' => array( $this, 'get_sales_sparkline' ),
- );
-
if ( $is_wc_admin_disabled ) {
+ $default_reports = array(
+ 'net_sales_link' => 'admin.php?page=wc-reports&tab=orders&range=month',
+ 'top_seller_link' => 'admin.php?page=wc-reports&tab=orders&report=sales_by_product&range=month&product_ids=',
+ 'lowstock_link' => 'admin.php?page=wc-reports&tab=stock&report=low_in_stock',
+ 'outofstock_link' => 'admin.php?page=wc-reports&tab=stock&report=out_of_stock',
+ 'report_data' => null,
+ 'get_sales_sparkline' => null,
+ );
+
/**
- * Filter to change the reports of the status widget on the Dashboard page.
+ * Filters the data of the status widget on the Dashboard page when Analytics is disabled.
*
- * Please note that this filter is mainly for backward compatibility with the legacy reports.
- * It's not recommended to use this filter to change the data of this widget.
+ * The net sales and top seller rows only show when `report_data` and `get_sales_sparkline` are both set.
+ * They are null by default; when another callback is hooked here, legacy reports fill them in first.
+ * This filter is kept for backward compatibility; it's not recommended for new code.
*
* @since 9.5.0
+ *
+ * @param array $status_widget_reports {
+ * Status widget data.
+ *
+ * @type string $net_sales_link Admin URL path for the net sales row.
+ * @type string $top_seller_link Admin URL path for the top seller row; the product ID is appended.
+ * @type string $lowstock_link Admin URL path for the low in stock row.
+ * @type string $outofstock_link Admin URL path for the out of stock row.
+ * @type object|null $report_data Sales data with a `net_sales` property.
+ * @type callable|null $get_sales_sparkline Called with ( $product_id, $days, $type ) and returns an array with `total` and `data`.
+ * }
*/
- $status_widget_reports = apply_filters( 'woocommerce_dashboard_status_widget_reports', $status_widget_reports );
+ $status_widget_reports = apply_filters( 'woocommerce_dashboard_status_widget_reports', $default_reports );
+ $status_widget_reports = is_array( $status_widget_reports ) ? array_merge( $default_reports, $status_widget_reports ) : $default_reports;
} else {
- $status_widget_reports['report_data'] = $this->get_wc_admin_performance_data();
+ $status_widget_reports = array(
+ 'net_sales_link' => 'admin.php?page=wc-admin&path=%2Fanalytics%2Frevenue&chart=net_revenue&orderby=net_revenue&period=month&compare=previous_period',
+ 'top_seller_link' => 'admin.php?page=wc-admin&filter=single_product&path=%2Fanalytics%2Fproducts&products=',
+ 'lowstock_link' => 'admin.php?page=wc-admin&type=lowstock&path=%2Fanalytics%2Fstock',
+ 'outofstock_link' => 'admin.php?page=wc-admin&type=outofstock&path=%2Fanalytics%2Fstock',
+ 'report_data' => $this->get_wc_admin_performance_data(),
+ 'get_sales_sparkline' => array( $this, 'get_sales_sparkline' ),
+ );
}
echo '<ul class="wc_status_list">';
@@ -213,7 +233,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
),
);
- if ( $report_data && is_callable( $get_sales_sparkline ) ) {
+ if ( $report_data && ! is_wp_error( $report_data ) && is_callable( $get_sales_sparkline ) ) {
$sparkline = call_user_func_array( $get_sales_sparkline, array( '', $days ) );
$sparkline = $this->sales_sparkline_markup( 'sales', $days, $sparkline['total'], $sparkline['data'] );
?>
@@ -232,8 +252,8 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
<?php
}
- $top_seller = $this->get_top_seller();
- if ( $top_seller && $top_seller->qty && is_callable( $get_sales_sparkline ) ) {
+ $top_seller = is_callable( $get_sales_sparkline ) ? $this->get_top_seller() : null;
+ if ( $top_seller && $top_seller->qty ) {
$sparkline = call_user_func_array( $get_sales_sparkline, array( $top_seller->product_id, $days, 'count' ) );
$sparkline = $this->sales_sparkline_markup( 'count', $days, $sparkline['total'], $sparkline['data'] );
?>
diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-reports.php b/plugins/woocommerce/includes/admin/class-wc-admin-reports.php
index b41721799c5..68b57757c02 100644
--- a/plugins/woocommerce/includes/admin/class-wc-admin-reports.php
+++ b/plugins/woocommerce/includes/admin/class-wc-admin-reports.php
@@ -29,8 +29,68 @@ class WC_Admin_Reports {
* Register the hook handlers for integrating with admin.
*/
public static function register_hook_handlers() {
- add_filter( 'woocommerce_after_dashboard_status_widget_parameter', array( __CLASS__, 'get_report_instance' ) );
- add_filter( 'woocommerce_dashboard_status_widget_reports', array( __CLASS__, 'replace_dashboard_status_widget_reports' ) );
+ add_filter( 'woocommerce_after_dashboard_status_widget_parameter', array( __CLASS__, 'get_status_widget_report_instance' ) );
+ add_filter( 'woocommerce_dashboard_status_widget_reports', array( __CLASS__, 'maybe_replace_dashboard_status_widget_reports' ) );
+ }
+
+ /**
+ * Fill in legacy sales data for the dashboard status widget, but only when another callback is hooked to the filter.
+ *
+ * Those callbacks were written against the legacy data, for example to adjust `report_data->net_sales`.
+ *
+ * @internal
+ * @since 11.4.0
+ *
+ * @param mixed $status_widget_reports The data to display in the status widget.
+ * @return mixed
+ */
+ public static function maybe_replace_dashboard_status_widget_reports( $status_widget_reports ) {
+ if ( ! self::has_other_callbacks( 'woocommerce_dashboard_status_widget_reports' ) || ! is_array( $status_widget_reports ) ) {
+ return $status_widget_reports;
+ }
+
+ return self::replace_dashboard_status_widget_reports( $status_widget_reports );
+ }
+
+ /**
+ * Provide a legacy report to the status widget hooks, but only when another callback can receive it.
+ *
+ * That is a listener on `woocommerce_after_dashboard_status_widget`, or another callback on this filter.
+ *
+ * @internal
+ * @since 11.4.0
+ *
+ * @param mixed $reports The value passed to `woocommerce_after_dashboard_status_widget`.
+ * @return mixed
+ */
+ public static function get_status_widget_report_instance( $reports ) {
+ if ( ! has_action( 'woocommerce_after_dashboard_status_widget' ) && ! self::has_other_callbacks( 'woocommerce_after_dashboard_status_widget_parameter' ) ) {
+ return $reports;
+ }
+
+ return self::get_report_instance();
+ }
+
+ /**
+ * Check whether a hook has callbacks besides the one of this class that is running it.
+ *
+ * @param string $hook_name Hook name.
+ * @return bool
+ */
+ private static function has_other_callbacks( string $hook_name ): bool {
+ global $wp_filter;
+
+ $hook = $wp_filter[ $hook_name ] ?? null;
+ if ( ! $hook instanceof WP_Hook ) {
+ return false;
+ }
+
+ $callback_count = 0;
+ foreach ( $hook->callbacks as $callbacks ) {
+ $callback_count += count( $callbacks );
+ }
+
+ return $callback_count > 1;
}
/**
@@ -90,6 +150,8 @@ class WC_Admin_Reports {
/**
* Filter handler for replacing the data of the status widget on the Dashboard page.
*
+ * Core only calls this when another callback is hooked to `woocommerce_dashboard_status_widget_reports`.
+ *
* @param array $status_widget_reports The data to display in the status widget.
*/
public static function replace_dashboard_status_widget_reports( $status_widget_reports ) {
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php b/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php
index 62a8ac83015..b04065939f6 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php
@@ -25,7 +25,6 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case {
// Mock http request to performance endpoint.
add_filter( 'rest_pre_dispatch', array( $this, 'mock_rest_responses' ), 10, 3 );
- add_filter( 'woocommerce_dashboard_status_widget_reports', array( $this, 'mock_replace_dashboard_status_widget_reports' ) );
}
/**
@@ -34,7 +33,6 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case {
public function tearDown(): void {
parent::tearDown();
remove_filter( 'rest_pre_dispatch', array( $this, 'mock_rest_responses' ), 10 );
- remove_filter( 'woocommerce_dashboard_status_widget_reports', array( $this, 'mock_replace_dashboard_status_widget_reports' ) );
}
/**
@@ -162,7 +160,7 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case {
}
/**
- * Ways Analytics can be turned off, each of which must bring back the legacy report links.
+ * Ways Analytics can be turned off.
*
* @return array<string, array{callable}>
*/
@@ -183,30 +181,77 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case {
}
/**
- * @testdox Should use the legacy status widget reports filter when Analytics is disabled.
+ * @testdox Should hide the sales rows, but keep the order and stock rows, when Analytics is disabled.
* @dataProvider provide_analytics_disabled_setups
*
* @param callable $disable_analytics Turns Analytics off.
*/
- public function test_status_widget_with_analytics_disabled( callable $disable_analytics ) {
- $this->skip_if_hpos_enabled( 'We don\'t support legacy reports on HPOS' );
+ public function test_status_widget_hides_sales_rows_with_analytics_disabled( callable $disable_analytics ) {
wp_set_current_user( $this->user );
+ update_option( 'woocommerce_manage_stock', 'yes' );
$order = WC_Helper_Order::create_order();
$order->set_status( OrderStatus::COMPLETED );
$order->save();
$disable_analytics();
- $this->expectOutputRegex( '/50\.00 worth in the/' );
+ ob_start();
+ ( new WC_Admin_Dashboard() )->status_widget_content();
+ $widget_output = ob_get_clean();
+
+ $this->assertStringNotContainsString( 'sales-this-month', $widget_output, 'Net sales row should be hidden without Analytics.' );
+ $this->assertStringNotContainsString( 'best-seller-this-month', $widget_output, 'Top seller row should be hidden without Analytics.' );
+ $this->assertStringContainsString( 'processing-orders', $widget_output );
+ $this->assertStringContainsString( 'on-hold-orders', $widget_output );
+ $this->assertStringContainsString( 'page=wc-reports&tab=stock&report=low_in_stock', $widget_output );
+ $this->assertStringContainsString( 'page=wc-reports&tab=stock&report=out_of_stock', $widget_output );
+ $this->assertStringNotContainsString( 'path=%2Fanalytics', $widget_output, 'No status widget link should point to Analytics while it is disabled.' );
+ }
+
+ /**
+ * @testdox Should show sales rows, linked to legacy Reports, when a filter supplies only sales data while Analytics is disabled.
+ */
+ public function test_status_widget_reports_filter_still_supplies_sales_rows_with_analytics_disabled() {
+ wp_set_current_user( $this->user );
+ $order = WC_Helper_Order::create_order();
+ $order->set_status( OrderStatus::COMPLETED );
+ $order->save();
+
+ add_filter( 'woocommerce_admin_disabled', '__return_true' );
+ add_filter( 'woocommerce_dashboard_status_widget_reports', array( $this, 'mock_replace_dashboard_status_widget_reports' ) );
+ ob_start();
( new WC_Admin_Dashboard() )->status_widget_content();
+ $widget_output = ob_get_clean();
- $widget_output = $this->getActualOutput();
- $this->assertMatchesRegularExpression( '/page\=wc-reports\&\#038\;tab\=orders\&\#038\;range\=month/', $widget_output );
- $this->assertMatchesRegularExpression( '/page\=wc-reports\&\#038\;tab\=orders\&\#038\;report\=sales_by_product/', $widget_output );
- $this->assertMatchesRegularExpression( '/page\=wc-reports\&\#038\;tab\=stock\&\#038\;report\=low_in_stock/', $widget_output );
- $this->assertMatchesRegularExpression( '/page\=wc-reports\&\#038\;tab\=stock\&\#038\;report\=out_of_stock/', $widget_output );
- $this->assertDoesNotMatchRegularExpression( '/page\=wc-admin/', $widget_output, 'No status widget link should point to Analytics while it is disabled.' );
+ $this->assertStringContainsString( '50.00 worth in the', $widget_output );
+ $this->assertStringContainsString( 'page=wc-reports&tab=orders&range=month', $widget_output );
+ $this->assertStringContainsString( 'page=wc-reports&tab=orders&report=sales_by_product', $widget_output );
+ }
+
+ /**
+ * @testdox Should show legacy sales data adjusted by a reports filter callback when Analytics is disabled.
+ */
+ public function test_status_widget_reports_filter_can_adjust_legacy_net_sales_with_analytics_disabled() {
+ wp_set_current_user( $this->user );
+ add_filter( 'woocommerce_admin_disabled', '__return_true' );
+ include_once WC_ABSPATH . 'includes/admin/class-wc-admin-reports.php';
+ WC_Admin_Reports::register_hook_handlers();
+ add_filter(
+ 'woocommerce_dashboard_status_widget_reports',
+ function ( $reports ) {
+ $reports['report_data']->net_sales = 4321;
+ return $reports;
+ },
+ 20
+ );
+
+ ob_start();
+ ( new WC_Admin_Dashboard() )->status_widget_content();
+ $widget_output = ob_get_clean();
+
+ $this->assertStringContainsString( 'sales-this-month', $widget_output );
+ $this->assertStringContainsString( '4,321.00', $widget_output );
}
/**
@@ -258,10 +303,6 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case {
$report_data = new stdClass();
$report_data->net_sales = 123;
- $status_widget_reports['net_sales_link'] = 'admin.php?page=wc-reports&tab=orders&range=month';
- $status_widget_reports['top_seller_link'] = 'admin.php?page=wc-reports&tab=orders&report=sales_by_product&range=month&product_ids=';
- $status_widget_reports['lowstock_link'] = 'admin.php?page=wc-reports&tab=stock&report=low_in_stock';
- $status_widget_reports['outofstock_link'] = 'admin.php?page=wc-reports&tab=stock&report=out_of_stock';
$status_widget_reports['report_data'] = $report_data;
$status_widget_reports['get_sales_sparkline'] = function () {
return array(
diff --git a/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-reports-test.php b/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-reports-test.php
index ed4483ebb8c..1dc7b03f67b 100644
--- a/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-reports-test.php
+++ b/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-reports-test.php
@@ -27,7 +27,7 @@ final class WC_Admin_Reports_Test extends WC_Unit_Test_Case {
}
/**
- * @testdox Should point the dashboard status widget at legacy Reports, which it only uses when Analytics is disabled.
+ * @testdox Should keep pointing the legacy status widget reports at legacy Reports for code that still calls them.
*/
public function test_replace_dashboard_status_widget_reports_uses_legacy_report_links(): void {
$reports = \WC_Admin_Reports::replace_dashboard_status_widget_reports( array() );
@@ -37,4 +37,105 @@ final class WC_Admin_Reports_Test extends WC_Unit_Test_Case {
$this->assertSame( 'admin.php?page=wc-reports&tab=stock&report=low_in_stock', $reports['lowstock_link'] );
$this->assertSame( 'admin.php?page=wc-reports&tab=stock&report=out_of_stock', $reports['outofstock_link'] );
}
+
+ /**
+ * @testdox Should hook only the conditional legacy handlers into the dashboard status widget.
+ */
+ public function test_register_hook_handlers_hooks_conditional_status_widget_handlers(): void {
+ \WC_Admin_Reports::register_hook_handlers();
+
+ $this->assertFalse( has_filter( 'woocommerce_dashboard_status_widget_reports', array( \WC_Admin_Reports::class, 'replace_dashboard_status_widget_reports' ) ) );
+ $this->assertSame( 10, has_filter( 'woocommerce_dashboard_status_widget_reports', array( \WC_Admin_Reports::class, 'maybe_replace_dashboard_status_widget_reports' ) ) );
+ $this->assertSame( 10, has_filter( 'woocommerce_after_dashboard_status_widget_parameter', array( \WC_Admin_Reports::class, 'get_status_widget_report_instance' ) ) );
+ }
+
+ /**
+ * @testdox Should leave the status widget sales data empty when no other callback is hooked to the reports filter.
+ */
+ public function test_status_widget_reports_stay_empty_without_other_callbacks(): void {
+ remove_all_filters( 'woocommerce_dashboard_status_widget_reports' );
+ \WC_Admin_Reports::register_hook_handlers();
+
+ $reports = apply_filters( 'woocommerce_dashboard_status_widget_reports', $this->get_default_status_widget_reports() );
+
+ $this->assertNull( $reports['report_data'] );
+ $this->assertNull( $reports['get_sales_sparkline'] );
+ }
+
+ /**
+ * @testdox Should fill in legacy sales data when another callback adjusts it through the reports filter.
+ */
+ public function test_status_widget_reports_are_filled_for_other_callbacks(): void {
+ remove_all_filters( 'woocommerce_dashboard_status_widget_reports' );
+ \WC_Admin_Reports::register_hook_handlers();
+ add_filter(
+ 'woocommerce_dashboard_status_widget_reports',
+ function ( $reports ) {
+ $reports['report_data']->net_sales = 42;
+ return $reports;
+ },
+ 20
+ );
+
+ $reports = apply_filters( 'woocommerce_dashboard_status_widget_reports', $this->get_default_status_widget_reports() );
+
+ $this->assertSame( 42, $reports['report_data']->net_sales );
+ $this->assertIsCallable( $reports['get_sales_sparkline'] );
+ }
+
+ /**
+ * @testdox Should pass a legacy report to the after status widget action only when something listens to it.
+ */
+ public function test_status_widget_report_instance_is_only_created_for_listeners(): void {
+ remove_all_actions( 'woocommerce_after_dashboard_status_widget' );
+ remove_all_filters( 'woocommerce_after_dashboard_status_widget_parameter' );
+ \WC_Admin_Reports::register_hook_handlers();
+
+ $this->assertNull( apply_filters( 'woocommerce_after_dashboard_status_widget_parameter', null ), 'No report should be created without listeners.' );
+
+ add_action( 'woocommerce_after_dashboard_status_widget', '__return_null' );
+ $reports = apply_filters( 'woocommerce_after_dashboard_status_widget_parameter', null );
+
+ $this->assertIsObject( $reports, 'Listeners should still receive a legacy report.' );
+ $this->assertSame( 'WC_Admin_Report', get_class( $reports ) );
+ }
+
+ /**
+ * @testdox Should pass a legacy report to another callback on the after status widget parameter filter.
+ */
+ public function test_status_widget_report_instance_is_created_for_other_parameter_callbacks(): void {
+ remove_all_actions( 'woocommerce_after_dashboard_status_widget' );
+ remove_all_filters( 'woocommerce_after_dashboard_status_widget_parameter' );
+ \WC_Admin_Reports::register_hook_handlers();
+ $received = null;
+ add_filter(
+ 'woocommerce_after_dashboard_status_widget_parameter',
+ function ( $reports ) use ( &$received ) {
+ $received = $reports;
+ return $reports;
+ },
+ 20
+ );
+
+ apply_filters( 'woocommerce_after_dashboard_status_widget_parameter', null );
+
+ $this->assertIsObject( $received, 'Another callback on the filter should receive a legacy report.' );
+ $this->assertSame( 'WC_Admin_Report', get_class( $received ) );
+ }
+
+ /**
+ * The status widget data the dashboard passes to the reports filter when Analytics is disabled.
+ *
+ * @return array
+ */
+ private function get_default_status_widget_reports(): array {
+ return array(
+ 'net_sales_link' => 'admin.php?page=wc-reports&tab=orders&range=month',
+ 'top_seller_link' => 'admin.php?page=wc-reports&tab=orders&report=sales_by_product&range=month&product_ids=',
+ 'lowstock_link' => 'admin.php?page=wc-reports&tab=stock&report=low_in_stock',
+ 'outofstock_link' => 'admin.php?page=wc-reports&tab=stock&report=out_of_stock',
+ 'report_data' => null,
+ 'get_sales_sparkline' => null,
+ );
+ }
}