PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 5.1.3
WooCommerce v5.1.3
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / admin / class-wc-admin-dashboard.php
woocommerce / includes / admin Last commit date
helper 5 years ago importers 5 years ago list-tables 5 years ago marketplace-suggestions 5 years ago meta-boxes 5 years ago notes 5 years ago plugin-updates 5 years ago reports 5 years ago settings 5 years ago views 5 years ago class-wc-admin-addons.php 5 years ago class-wc-admin-api-keys-table-list.php 6 years ago class-wc-admin-api-keys.php 6 years ago class-wc-admin-assets.php 5 years ago class-wc-admin-attributes.php 5 years ago class-wc-admin-customize.php 5 years ago class-wc-admin-dashboard.php 5 years ago class-wc-admin-duplicate-product.php 5 years ago class-wc-admin-exporters.php 5 years ago class-wc-admin-help.php 5 years ago class-wc-admin-importers.php 5 years ago class-wc-admin-log-table-list.php 5 years ago class-wc-admin-menus.php 5 years ago class-wc-admin-meta-boxes.php 5 years ago class-wc-admin-notices.php 5 years ago class-wc-admin-permalink-settings.php 5 years ago class-wc-admin-pointers.php 5 years ago class-wc-admin-post-types.php 5 years ago class-wc-admin-profile.php 5 years ago class-wc-admin-reports.php 5 years ago class-wc-admin-settings.php 5 years ago class-wc-admin-setup-wizard.php 5 years ago class-wc-admin-status.php 5 years ago class-wc-admin-taxonomies.php 5 years ago class-wc-admin-webhooks-table-list.php 7 years ago class-wc-admin-webhooks.php 5 years ago class-wc-admin.php 5 years ago wc-admin-functions.php 5 years ago wc-meta-box-functions.php 5 years ago
class-wc-admin-dashboard.php
424 lines
1 <?php
2 /**
3 * Admin Dashboard
4 *
5 * @package WooCommerce\Admin
6 * @version 2.1.0
7 */
8
9 use Automattic\Jetpack\Constants;
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly.
13 }
14
15 if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
16
17 /**
18 * WC_Admin_Dashboard Class.
19 */
20 class WC_Admin_Dashboard {
21
22 /**
23 * Hook in tabs.
24 */
25 public function __construct() {
26 // Only hook in admin parts if the user has admin access.
27 if ( current_user_can( 'view_woocommerce_reports' ) || current_user_can( 'manage_woocommerce' ) || current_user_can( 'publish_shop_orders' ) ) {
28 // If on network admin, only load the widget that works in that context and skip the rest.
29 if ( is_multisite() && is_network_admin() ) {
30 add_action( 'wp_network_dashboard_setup', array( $this, 'register_network_order_widget' ) );
31 } else {
32 add_action( 'wp_dashboard_setup', array( $this, 'init' ) );
33 }
34 }
35 }
36
37 /**
38 * Init dashboard widgets.
39 */
40 public function init() {
41 // Reviews Widget.
42 if ( current_user_can( 'publish_shop_orders' ) && post_type_supports( 'product', 'comments' ) ) {
43 wp_add_dashboard_widget( 'woocommerce_dashboard_recent_reviews', __( 'WooCommerce Recent Reviews', 'woocommerce' ), array( $this, 'recent_reviews' ) );
44 }
45 wp_add_dashboard_widget( 'woocommerce_dashboard_status', __( 'WooCommerce Status', 'woocommerce' ), array( $this, 'status_widget' ) );
46
47 // Network Order Widget.
48 if ( is_multisite() && is_main_site() ) {
49 $this->register_network_order_widget();
50 }
51 }
52
53 /**
54 * Register the network order dashboard widget.
55 */
56 public function register_network_order_widget() {
57 wp_add_dashboard_widget( 'woocommerce_network_orders', __( 'WooCommerce Network Orders', 'woocommerce' ), array( $this, 'network_orders' ) );
58 }
59
60 /**
61 * Get top seller from DB.
62 *
63 * @return object
64 */
65 private function get_top_seller() {
66 global $wpdb;
67
68 $query = array();
69 $query['fields'] = "SELECT SUM( order_item_meta.meta_value ) as qty, order_item_meta_2.meta_value as product_id
70 FROM {$wpdb->posts} as posts";
71 $query['join'] = "INNER JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON posts.ID = order_id ";
72 $query['join'] .= "INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta ON order_items.order_item_id = order_item_meta.order_item_id ";
73 $query['join'] .= "INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta_2 ON order_items.order_item_id = order_item_meta_2.order_item_id ";
74 $query['where'] = "WHERE posts.post_type IN ( '" . implode( "','", wc_get_order_types( 'order-count' ) ) . "' ) ";
75 $query['where'] .= "AND posts.post_status IN ( 'wc-" . implode( "','wc-", apply_filters( 'woocommerce_reports_order_statuses', array( 'completed', 'processing', 'on-hold' ) ) ) . "' ) ";
76 $query['where'] .= "AND order_item_meta.meta_key = '_qty' ";
77 $query['where'] .= "AND order_item_meta_2.meta_key = '_product_id' ";
78 $query['where'] .= "AND posts.post_date >= '" . gmdate( 'Y-m-01', current_time( 'timestamp' ) ) . "' ";
79 $query['where'] .= "AND posts.post_date <= '" . gmdate( 'Y-m-d H:i:s', current_time( 'timestamp' ) ) . "' ";
80 $query['groupby'] = 'GROUP BY product_id';
81 $query['orderby'] = 'ORDER BY qty DESC';
82 $query['limits'] = 'LIMIT 1';
83
84 return $wpdb->get_row( implode( ' ', apply_filters( 'woocommerce_dashboard_status_widget_top_seller_query', $query ) ) ); //phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
85 }
86
87 /**
88 * Get sales report data.
89 *
90 * @return object
91 */
92 private function get_sales_report_data() {
93 include_once dirname( __FILE__ ) . '/reports/class-wc-report-sales-by-date.php';
94
95 $sales_by_date = new WC_Report_Sales_By_Date();
96 $sales_by_date->start_date = strtotime( gmdate( 'Y-m-01', current_time( 'timestamp' ) ) );
97 $sales_by_date->end_date = strtotime( gmdate( 'Y-m-d', current_time( 'timestamp' ) ) );
98 $sales_by_date->chart_groupby = 'day';
99 $sales_by_date->group_by_query = 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)';
100
101 return $sales_by_date->get_report_data();
102 }
103
104 /**
105 * Show status widget.
106 */
107 public function status_widget() {
108 include_once dirname( __FILE__ ) . '/reports/class-wc-admin-report.php';
109
110 $reports = new WC_Admin_Report();
111
112 echo '<ul class="wc_status_list">';
113
114 if ( current_user_can( 'view_woocommerce_reports' ) ) {
115 $report_data = $this->get_sales_report_data();
116 if ( $report_data ) {
117 ?>
118 <li class="sales-this-month">
119 <a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-reports&tab=orders&range=month' ) ); ?>">
120 <?php echo $reports->sales_sparkline( '', max( 7, gmdate( 'd', current_time( 'timestamp' ) ) ) ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
121 <?php
122 printf(
123 /* translators: %s: net sales */
124 esc_html__( '%s net sales this month', 'woocommerce' ),
125 '<strong>' . wc_price( $report_data->net_sales ) . '</strong>'
126 ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
127 ?>
128 </a>
129 </li>
130 <?php
131 }
132
133 $top_seller = $this->get_top_seller();
134 if ( $top_seller && $top_seller->qty ) {
135 ?>
136 <li class="best-seller-this-month">
137 <a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-reports&tab=orders&report=sales_by_product&range=month&product_ids=' . $top_seller->product_id ) ); ?>">
138 <?php echo $reports->sales_sparkline( $top_seller->product_id, max( 7, gmdate( 'd', current_time( 'timestamp' ) ) ), 'count' ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
139 <?php
140 printf(
141 /* translators: 1: top seller product title 2: top seller quantity */
142 esc_html__( '%1$s top seller this month (sold %2$d)', 'woocommerce' ),
143 '<strong>' . get_the_title( $top_seller->product_id ) . '</strong>',
144 $top_seller->qty
145 ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
146 ?>
147 </a>
148 </li>
149 <?php
150 }
151 }
152
153 $this->status_widget_order_rows();
154 $this->status_widget_stock_rows();
155
156 do_action( 'woocommerce_after_dashboard_status_widget', $reports );
157 echo '</ul>';
158 }
159
160 /**
161 * Show order data is status widget.
162 */
163 private function status_widget_order_rows() {
164 if ( ! current_user_can( 'edit_shop_orders' ) ) {
165 return;
166 }
167 $on_hold_count = 0;
168 $processing_count = 0;
169
170 foreach ( wc_get_order_types( 'order-count' ) as $type ) {
171 $counts = (array) wp_count_posts( $type );
172 $on_hold_count += isset( $counts['wc-on-hold'] ) ? $counts['wc-on-hold'] : 0;
173 $processing_count += isset( $counts['wc-processing'] ) ? $counts['wc-processing'] : 0;
174 }
175 ?>
176 <li class="processing-orders">
177 <a href="<?php echo esc_url( admin_url( 'edit.php?post_status=wc-processing&post_type=shop_order' ) ); ?>">
178 <?php
179 printf(
180 /* translators: %s: order count */
181 _n( '<strong>%s order</strong> awaiting processing', '<strong>%s orders</strong> awaiting processing', $processing_count, 'woocommerce' ),
182 $processing_count
183 ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
184 ?>
185 </a>
186 </li>
187 <li class="on-hold-orders">
188 <a href="<?php echo esc_url( admin_url( 'edit.php?post_status=wc-on-hold&post_type=shop_order' ) ); ?>">
189 <?php
190 printf(
191 /* translators: %s: order count */
192 _n( '<strong>%s order</strong> on-hold', '<strong>%s orders</strong> on-hold', $on_hold_count, 'woocommerce' ),
193 $on_hold_count
194 ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
195 ?>
196 </a>
197 </li>
198 <?php
199 }
200
201 /**
202 * Show stock data is status widget.
203 */
204 private function status_widget_stock_rows() {
205 global $wpdb;
206
207 // Requires lookup table added in 3.6.
208 if ( version_compare( get_option( 'woocommerce_db_version', null ), '3.6', '<' ) ) {
209 return;
210 }
211
212 $stock = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 1 ) );
213 $nostock = absint( max( get_option( 'woocommerce_notify_no_stock_amount' ), 0 ) );
214
215 $transient_name = 'wc_low_stock_count';
216 $lowinstock_count = get_transient( $transient_name );
217
218 if ( false === $lowinstock_count ) {
219 /**
220 * Status widget low in stock count pre query.
221 *
222 * @since 4.3.0
223 * @param null|string $low_in_stock_count Low in stock count, by default null.
224 * @param int $stock Low stock amount.
225 * @param int $nostock No stock amount
226 */
227 $lowinstock_count = apply_filters( 'woocommerce_status_widget_low_in_stock_count_pre_query', null, $stock, $nostock );
228
229 if ( is_null( $lowinstock_count ) ) {
230 $lowinstock_count = $wpdb->get_var(
231 $wpdb->prepare(
232 "SELECT COUNT( product_id )
233 FROM {$wpdb->wc_product_meta_lookup} AS lookup
234 INNER JOIN {$wpdb->posts} as posts ON lookup.product_id = posts.ID
235 WHERE stock_quantity <= %d
236 AND stock_quantity > %d
237 AND posts.post_status = 'publish'",
238 $stock,
239 $nostock
240 )
241 );
242 }
243
244 set_transient( $transient_name, (int) $lowinstock_count, DAY_IN_SECONDS * 30 );
245 }
246
247 $transient_name = 'wc_outofstock_count';
248 $outofstock_count = get_transient( $transient_name );
249
250 if ( false === $outofstock_count ) {
251 /**
252 * Status widget out of stock count pre query.
253 *
254 * @since 4.3.0
255 * @param null|string $outofstock_count Out of stock count, by default null.
256 * @param int $nostock No stock amount
257 */
258 $outofstock_count = apply_filters( 'woocommerce_status_widget_out_of_stock_count_pre_query', null, $nostock );
259
260 if ( is_null( $outofstock_count ) ) {
261 $outofstock_count = (int) $wpdb->get_var(
262 $wpdb->prepare(
263 "SELECT COUNT( product_id )
264 FROM {$wpdb->wc_product_meta_lookup} AS lookup
265 INNER JOIN {$wpdb->posts} as posts ON lookup.product_id = posts.ID
266 WHERE stock_quantity <= %d
267 AND posts.post_status = 'publish'",
268 $nostock
269 )
270 );
271 }
272
273 set_transient( $transient_name, (int) $outofstock_count, DAY_IN_SECONDS * 30 );
274 }
275 ?>
276 <li class="low-in-stock">
277 <a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-reports&tab=stock&report=low_in_stock' ) ); ?>">
278 <?php
279 printf(
280 /* translators: %s: order count */
281 _n( '<strong>%s product</strong> low in stock', '<strong>%s products</strong> low in stock', $lowinstock_count, 'woocommerce' ),
282 $lowinstock_count
283 ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
284 ?>
285 </a>
286 </li>
287 <li class="out-of-stock">
288 <a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-reports&tab=stock&report=out_of_stock' ) ); ?>">
289 <?php
290 printf(
291 /* translators: %s: order count */
292 _n( '<strong>%s product</strong> out of stock', '<strong>%s products</strong> out of stock', $outofstock_count, 'woocommerce' ),
293 $outofstock_count
294 ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
295 ?>
296 </a>
297 </li>
298 <?php
299 }
300
301 /**
302 * Recent reviews widget.
303 */
304 public function recent_reviews() {
305 global $wpdb;
306
307 $query_from = apply_filters(
308 'woocommerce_report_recent_reviews_query_from',
309 "FROM {$wpdb->comments} comments
310 LEFT JOIN {$wpdb->posts} posts ON (comments.comment_post_ID = posts.ID)
311 WHERE comments.comment_approved = '1'
312 AND comments.comment_type = 'review'
313 AND posts.post_password = ''
314 AND posts.post_type = 'product'
315 AND comments.comment_parent = 0
316 ORDER BY comments.comment_date_gmt DESC
317 LIMIT 5"
318 );
319
320 $comments = $wpdb->get_results(
321 "SELECT posts.ID, posts.post_title, comments.comment_author, comments.comment_author_email, comments.comment_ID, comments.comment_content {$query_from};" // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
322 );
323
324 if ( $comments ) {
325 echo '<ul>';
326 foreach ( $comments as $comment ) {
327
328 echo '<li>';
329
330 echo get_avatar( $comment->comment_author_email, '32' );
331
332 $rating = intval( get_comment_meta( $comment->comment_ID, 'rating', true ) );
333
334 /* translators: %s: rating */
335 echo '<div class="star-rating"><span style="width:' . esc_attr( $rating * 20 ) . '%">' . sprintf( esc_html__( '%s out of 5', 'woocommerce' ), esc_html( $rating ) ) . '</span></div>';
336
337 /* translators: %s: review author */
338 echo '<h4 class="meta"><a href="' . esc_url( get_permalink( $comment->ID ) ) . '#comment-' . esc_attr( absint( $comment->comment_ID ) ) . '">' . esc_html( apply_filters( 'woocommerce_admin_dashboard_recent_reviews', $comment->post_title, $comment ) ) . '</a> ' . sprintf( esc_html__( 'reviewed by %s', 'woocommerce' ), esc_html( $comment->comment_author ) ) . '</h4>';
339 echo '<blockquote>' . wp_kses_data( $comment->comment_content ) . '</blockquote></li>';
340
341 }
342 echo '</ul>';
343 } else {
344 echo '<p>' . esc_html__( 'There are no product reviews yet.', 'woocommerce' ) . '</p>';
345 }
346 }
347
348 /**
349 * Network orders widget.
350 */
351 public function network_orders() {
352 $suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
353 $version = Constants::get_constant( 'WC_VERSION' );
354
355 wp_enqueue_style( 'wc-network-orders', WC()->plugin_url() . '/assets/css/network-order-widget.css', array(), $version );
356
357 wp_enqueue_script( 'wc-network-orders', WC()->plugin_url() . '/assets/js/admin/network-orders' . $suffix . '.js', array( 'jquery', 'underscore' ), $version, true );
358
359 $user = wp_get_current_user();
360 $blogs = get_blogs_of_user( $user->ID );
361 $blog_ids = wp_list_pluck( $blogs, 'userblog_id' );
362
363 wp_localize_script(
364 'wc-network-orders',
365 'woocommerce_network_orders',
366 array(
367 'nonce' => wp_create_nonce( 'wp_rest' ),
368 'sites' => array_values( $blog_ids ),
369 'order_endpoint' => get_rest_url( null, 'wc/v3/orders/network' ),
370 )
371 );
372 ?>
373 <div class="post-type-shop_order">
374 <div id="woocommerce-network-order-table-loading" class="woocommerce-network-order-table-loading is-active">
375 <p>
376 <span class="spinner is-active"></span> <?php esc_html_e( 'Loading network orders', 'woocommerce' ); ?>
377 </p>
378
379 </div>
380 <table id="woocommerce-network-order-table" class="woocommerce-network-order-table">
381 <thead>
382 <tr>
383 <td><?php esc_html_e( 'Order', 'woocommerce' ); ?></td>
384 <td><?php esc_html_e( 'Status', 'woocommerce' ); ?></td>
385 <td><?php esc_html_e( 'Total', 'woocommerce' ); ?></td>
386 </tr>
387 </thead>
388 <tbody id="network-orders-tbody">
389
390 </tbody>
391 </table>
392 <div id="woocommerce-network-orders-no-orders" class="woocommerce-network-orders-no-orders">
393 <p>
394 <?php esc_html_e( 'No orders found', 'woocommerce' ); ?>
395 </p>
396 </div>
397 <?php // @codingStandardsIgnoreStart ?>
398 <script type="text/template" id="network-orders-row-template">
399 <tr>
400 <td>
401 <a href="<%- edit_url %>" class="order-view"><strong>#<%- number %> <%- customer %></strong></a>
402 <br>
403 <em>
404 <%- blog.blogname %>
405 </em>
406 </td>
407 <td>
408 <mark class="order-status status-<%- status %>"><span><%- status_name %></span></mark>
409 </td>
410 <td>
411 <%= formatted_total %>
412 </td>
413 </tr>
414 </script>
415 <?php // @codingStandardsIgnoreEnd ?>
416 </div>
417 <?php
418 }
419 }
420
421 endif;
422
423 return new WC_Admin_Dashboard();
424