Edit File by line
/home/zeestwma/richards.../wp-conte.../plugins/woocomme.../includes/admin
File: class-wc-admin-dashboard.php
<?php
[0] Fix | Delete
/**
[1] Fix | Delete
* Admin Dashboard
[2] Fix | Delete
*
[3] Fix | Delete
* @package WooCommerce\Admin
[4] Fix | Delete
* @version 2.1.0
[5] Fix | Delete
*/
[6] Fix | Delete
[7] Fix | Delete
use Automattic\Jetpack\Constants;
[8] Fix | Delete
use Automattic\WooCommerce\Admin\Features\Features;
[9] Fix | Delete
use Automattic\WooCommerce\Enums\OrderStatus;
[10] Fix | Delete
use Automattic\WooCommerce\Enums\OrderInternalStatus;
[11] Fix | Delete
use Automattic\WooCommerce\Utilities\OrderUtil;
[12] Fix | Delete
[13] Fix | Delete
if ( ! defined( 'ABSPATH' ) ) {
[14] Fix | Delete
exit; // Exit if accessed directly.
[15] Fix | Delete
}
[16] Fix | Delete
[17] Fix | Delete
if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) :
[18] Fix | Delete
[19] Fix | Delete
/**
[20] Fix | Delete
* WC_Admin_Dashboard Class.
[21] Fix | Delete
*/
[22] Fix | Delete
class WC_Admin_Dashboard {
[23] Fix | Delete
[24] Fix | Delete
/**
[25] Fix | Delete
* Hook in tabs.
[26] Fix | Delete
*/
[27] Fix | Delete
public function __construct() {
[28] Fix | Delete
// Only hook in admin parts if the user has admin access.
[29] Fix | Delete
if ( $this->should_display_widget() ) {
[30] Fix | Delete
// If on network admin, only load the widget that works in that context and skip the rest.
[31] Fix | Delete
if ( is_multisite() && is_network_admin() ) {
[32] Fix | Delete
add_action( 'wp_network_dashboard_setup', array( $this, 'register_network_order_widget' ) );
[33] Fix | Delete
} else {
[34] Fix | Delete
add_action( 'wp_dashboard_setup', array( $this, 'init' ) );
[35] Fix | Delete
}
[36] Fix | Delete
}
[37] Fix | Delete
}
[38] Fix | Delete
[39] Fix | Delete
/**
[40] Fix | Delete
* Init dashboard widgets.
[41] Fix | Delete
*/
[42] Fix | Delete
public function init() {
[43] Fix | Delete
// Reviews Widget.
[44] Fix | Delete
if ( current_user_can( 'publish_shop_orders' ) && post_type_supports( 'product', 'comments' ) ) {
[45] Fix | Delete
wp_add_dashboard_widget( 'woocommerce_dashboard_recent_reviews', __( 'WooCommerce Recent Reviews', 'woocommerce' ), array( $this, 'recent_reviews' ) );
[46] Fix | Delete
}
[47] Fix | Delete
wp_add_dashboard_widget( 'woocommerce_dashboard_status', __( 'WooCommerce Status', 'woocommerce' ), array( $this, 'status_widget' ) );
[48] Fix | Delete
[49] Fix | Delete
// Network Order Widget.
[50] Fix | Delete
if ( is_multisite() && is_main_site() ) {
[51] Fix | Delete
$this->register_network_order_widget();
[52] Fix | Delete
}
[53] Fix | Delete
}
[54] Fix | Delete
[55] Fix | Delete
/**
[56] Fix | Delete
* Register the network order dashboard widget.
[57] Fix | Delete
*/
[58] Fix | Delete
public function register_network_order_widget() {
[59] Fix | Delete
wp_add_dashboard_widget( 'woocommerce_network_orders', __( 'WooCommerce Network Orders', 'woocommerce' ), array( $this, 'network_orders' ) );
[60] Fix | Delete
}
[61] Fix | Delete
[62] Fix | Delete
/**
[63] Fix | Delete
* Check to see if we should display the widget.
[64] Fix | Delete
*
[65] Fix | Delete
* @return bool
[66] Fix | Delete
*/
[67] Fix | Delete
private function should_display_widget() {
[68] Fix | Delete
if ( ! WC()->is_wc_admin_active() ) {
[69] Fix | Delete
return false;
[70] Fix | Delete
}
[71] Fix | Delete
[72] Fix | Delete
$has_permission = current_user_can( 'view_woocommerce_reports' ) || current_user_can( 'manage_woocommerce' ) || current_user_can( 'publish_shop_orders' );
[73] Fix | Delete
$task_completed_or_hidden = 'yes' === get_option( 'woocommerce_task_list_complete' ) || 'yes' === get_option( 'woocommerce_task_list_hidden' );
[74] Fix | Delete
return $task_completed_or_hidden && $has_permission;
[75] Fix | Delete
}
[76] Fix | Delete
[77] Fix | Delete
/**
[78] Fix | Delete
* Get top seller from DB.
[79] Fix | Delete
*
[80] Fix | Delete
* @return object
[81] Fix | Delete
*/
[82] Fix | Delete
private function get_top_seller() {
[83] Fix | Delete
global $wpdb;
[84] Fix | Delete
[85] Fix | Delete
$hpos_enabled = OrderUtil::custom_orders_table_usage_is_enabled();
[86] Fix | Delete
$orders_table = OrderUtil::get_table_for_orders();
[87] Fix | Delete
$orders_column_id = $hpos_enabled ? 'id' : 'ID';
[88] Fix | Delete
$orders_column_type = $hpos_enabled ? 'type' : 'post_type';
[89] Fix | Delete
$orders_column_status = $hpos_enabled ? 'status' : 'post_status';
[90] Fix | Delete
$orders_column_date = $hpos_enabled ? 'date_created_gmt' : 'post_date_gmt';
[91] Fix | Delete
[92] Fix | Delete
$query = array();
[93] Fix | Delete
$query['fields'] = "SELECT SUM( order_item_meta.meta_value ) as qty, order_item_meta_2.meta_value as product_id FROM {$orders_table} AS orders";
[94] Fix | Delete
$query['join'] = "INNER JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON orders.{$orders_column_id} = order_id ";
[95] Fix | Delete
$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 ";
[96] Fix | Delete
$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 ";
[97] Fix | Delete
$query['where'] = "WHERE orders.{$orders_column_type} IN ( '" . implode( "','", wc_get_order_types( 'order-count' ) ) . "' ) ";
[98] Fix | Delete
[99] Fix | Delete
/**
[100] Fix | Delete
* Allows modifying the order statuses used in the top seller query inside the dashboard status widget.
[101] Fix | Delete
*
[102] Fix | Delete
* @since 2.2.0
[103] Fix | Delete
*
[104] Fix | Delete
* @param string[] $order_statuses Order statuses.
[105] Fix | Delete
*/
[106] Fix | Delete
$order_statuses = apply_filters( 'woocommerce_reports_order_statuses', array( OrderStatus::COMPLETED, OrderStatus::PROCESSING, OrderStatus::ON_HOLD ) );
[107] Fix | Delete
$query['where'] .= "AND orders.{$orders_column_status} IN ( 'wc-" . implode( "','wc-", $order_statuses ) . "' ) ";
[108] Fix | Delete
[109] Fix | Delete
$query['where'] .= "AND order_item_meta.meta_key = '_qty' ";
[110] Fix | Delete
$query['where'] .= "AND order_item_meta_2.meta_key = '_product_id' ";
[111] Fix | Delete
$query['where'] .= "AND orders.{$orders_column_date} >= '" . gmdate( 'Y-m-01', current_time( 'timestamp' ) ) . "' "; // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
[112] Fix | Delete
$query['where'] .= "AND orders.{$orders_column_date} <= '" . gmdate( 'Y-m-d H:i:s', current_time( 'timestamp' ) ) . "' "; // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
[113] Fix | Delete
$query['groupby'] = 'GROUP BY product_id';
[114] Fix | Delete
$query['orderby'] = 'ORDER BY qty DESC';
[115] Fix | Delete
$query['limits'] = 'LIMIT 1';
[116] Fix | Delete
[117] Fix | Delete
/**
[118] Fix | Delete
* Allows modification of the query to determine the top seller product in the dashboard status widget.
[119] Fix | Delete
*
[120] Fix | Delete
* @since 2.2.0
[121] Fix | Delete
*
[122] Fix | Delete
* @param array $query SQL query parts.
[123] Fix | Delete
*/
[124] Fix | Delete
$query = apply_filters( 'woocommerce_dashboard_status_widget_top_seller_query', $query );
[125] Fix | Delete
[126] Fix | Delete
$sql = implode( ' ', $query );
[127] Fix | Delete
return $wpdb->get_row( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
[128] Fix | Delete
}
[129] Fix | Delete
[130] Fix | Delete
/**
[131] Fix | Delete
* Show status widget.
[132] Fix | Delete
*/
[133] Fix | Delete
public function status_widget() {
[134] Fix | Delete
$suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
[135] Fix | Delete
$version = Constants::get_constant( 'WC_VERSION' );
[136] Fix | Delete
[137] Fix | Delete
wp_enqueue_script( 'wc-status-widget', WC()->plugin_url() . '/assets/js/admin/wc-status-widget' . $suffix . '.js', array( 'jquery', 'wc-flot' ), $version, true );
[138] Fix | Delete
wp_enqueue_script( 'wc-status-widget-async', WC()->plugin_url() . '/assets/js/admin/wc-status-widget-async' . $suffix . '.js', array( 'jquery' ), $version, true );
[139] Fix | Delete
[140] Fix | Delete
wp_localize_script(
[141] Fix | Delete
'wc-status-widget-async',
[142] Fix | Delete
'wc_status_widget_params',
[143] Fix | Delete
array(
[144] Fix | Delete
'ajax_url' => admin_url( 'admin-ajax.php' ),
[145] Fix | Delete
'security' => wp_create_nonce( 'wc-status-widget' ),
[146] Fix | Delete
'error_message' => esc_html__( 'Error loading widget', 'woocommerce' ),
[147] Fix | Delete
)
[148] Fix | Delete
);
[149] Fix | Delete
[150] Fix | Delete
// Display loading placeholder.
[151] Fix | Delete
echo '<div id="wc-status-widget-loading" class="wc-status-widget-loading">';
[152] Fix | Delete
echo '<p>' . esc_html__( 'Loading status data...', 'woocommerce' ) . ' <span class="spinner is-active"></span></p>';
[153] Fix | Delete
echo '</div>';
[154] Fix | Delete
echo '<div id="wc-status-widget-content" style="display:none;"></div>';
[155] Fix | Delete
}
[156] Fix | Delete
[157] Fix | Delete
/**
[158] Fix | Delete
* Generate the actual status widget content.
[159] Fix | Delete
* This contains the original content of the status_widget() method.
[160] Fix | Delete
*/
[161] Fix | Delete
public function status_widget_content() {
[162] Fix | Delete
//phpcs:ignore
[163] Fix | Delete
$is_wc_admin_disabled = apply_filters( 'woocommerce_admin_disabled', false ) || ! Features::is_enabled( 'analytics' );
[164] Fix | Delete
[165] Fix | Delete
$status_widget_reports = array(
[166] Fix | Delete
'net_sales_link' => 'admin.php?page=wc-admin&path=%2Fanalytics%2Frevenue&chart=net_revenue&orderby=net_revenue&period=month&compare=previous_period',
[167] Fix | Delete
'top_seller_link' => 'admin.php?page=wc-admin&filter=single_product&path=%2Fanalytics%2Fproducts&products=',
[168] Fix | Delete
'lowstock_link' => 'admin.php?page=wc-admin&type=lowstock&path=%2Fanalytics%2Fstock',
[169] Fix | Delete
'outofstock_link' => 'admin.php?page=wc-admin&type=outofstock&path=%2Fanalytics%2Fstock',
[170] Fix | Delete
'report_data' => null,
[171] Fix | Delete
'get_sales_sparkline' => array( $this, 'get_sales_sparkline' ),
[172] Fix | Delete
);
[173] Fix | Delete
[174] Fix | Delete
if ( $is_wc_admin_disabled ) {
[175] Fix | Delete
/**
[176] Fix | Delete
* Filter to change the reports of the status widget on the Dashboard page.
[177] Fix | Delete
*
[178] Fix | Delete
* Please note that this filter is mainly for backward compatibility with the legacy reports.
[179] Fix | Delete
* It's not recommended to use this filter to change the data of this widget.
[180] Fix | Delete
*
[181] Fix | Delete
* @since 9.5.0
[182] Fix | Delete
*/
[183] Fix | Delete
$status_widget_reports = apply_filters( 'woocommerce_dashboard_status_widget_reports', $status_widget_reports );
[184] Fix | Delete
} else {
[185] Fix | Delete
$status_widget_reports['report_data'] = $this->get_wc_admin_performance_data();
[186] Fix | Delete
}
[187] Fix | Delete
[188] Fix | Delete
echo '<ul class="wc_status_list">';
[189] Fix | Delete
[190] Fix | Delete
if ( current_user_can( 'view_woocommerce_reports' ) ) {
[191] Fix | Delete
$report_data = $status_widget_reports['report_data'];
[192] Fix | Delete
$get_sales_sparkline = $status_widget_reports['get_sales_sparkline'];
[193] Fix | Delete
$net_sales_link = $status_widget_reports['net_sales_link'];
[194] Fix | Delete
$top_seller_link = $status_widget_reports['top_seller_link'];
[195] Fix | Delete
[196] Fix | Delete
$days = max( 7, (int) gmdate( 'd', current_time( 'timestamp' ) ) ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
[197] Fix | Delete
[198] Fix | Delete
$sparkline_allowed_html = array(
[199] Fix | Delete
'span' => array(
[200] Fix | Delete
'class' => array(),
[201] Fix | Delete
'data-color' => array(),
[202] Fix | Delete
'data-tip' => array(),
[203] Fix | Delete
'data-barwidth' => array(),
[204] Fix | Delete
'data-sparkline' => array(),
[205] Fix | Delete
),
[206] Fix | Delete
);
[207] Fix | Delete
[208] Fix | Delete
if ( $report_data && is_callable( $get_sales_sparkline ) ) {
[209] Fix | Delete
$sparkline = call_user_func_array( $get_sales_sparkline, array( '', $days ) );
[210] Fix | Delete
$sparkline = $this->sales_sparkline_markup( 'sales', $days, $sparkline['total'], $sparkline['data'] );
[211] Fix | Delete
?>
[212] Fix | Delete
<li class="sales-this-month">
[213] Fix | Delete
<a href="<?php echo esc_url( admin_url( $net_sales_link ) ); ?>">
[214] Fix | Delete
<?php echo wp_kses( $sparkline, $sparkline_allowed_html ); ?>
[215] Fix | Delete
<?php
[216] Fix | Delete
printf(
[217] Fix | Delete
/* translators: %s: net sales */
[218] Fix | Delete
esc_html__( '%s net sales this month', 'woocommerce' ),
[219] Fix | Delete
'<strong>' . wc_price( $report_data->net_sales ) . '</strong>'
[220] Fix | Delete
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
[221] Fix | Delete
?>
[222] Fix | Delete
</a>
[223] Fix | Delete
</li>
[224] Fix | Delete
<?php
[225] Fix | Delete
}
[226] Fix | Delete
[227] Fix | Delete
$top_seller = $this->get_top_seller();
[228] Fix | Delete
if ( $top_seller && $top_seller->qty && is_callable( $get_sales_sparkline ) ) {
[229] Fix | Delete
$sparkline = call_user_func_array( $get_sales_sparkline, array( $top_seller->product_id, $days, 'count' ) );
[230] Fix | Delete
$sparkline = $this->sales_sparkline_markup( 'count', $days, $sparkline['total'], $sparkline['data'] );
[231] Fix | Delete
?>
[232] Fix | Delete
<li class="best-seller-this-month">
[233] Fix | Delete
<a href="<?php echo esc_url( admin_url( $top_seller_link . $top_seller->product_id ) ); ?>">
[234] Fix | Delete
<?php echo wp_kses( $sparkline, $sparkline_allowed_html ); ?>
[235] Fix | Delete
<?php
[236] Fix | Delete
printf(
[237] Fix | Delete
/* translators: 1: top seller product title 2: top seller quantity */
[238] Fix | Delete
esc_html__( '%1$s top seller this month (sold %2$d)', 'woocommerce' ),
[239] Fix | Delete
'<strong>' . get_the_title( $top_seller->product_id ) . '</strong>',
[240] Fix | Delete
$top_seller->qty
[241] Fix | Delete
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
[242] Fix | Delete
?>
[243] Fix | Delete
</a>
[244] Fix | Delete
</li>
[245] Fix | Delete
<?php
[246] Fix | Delete
}
[247] Fix | Delete
}
[248] Fix | Delete
[249] Fix | Delete
$this->status_widget_order_rows();
[250] Fix | Delete
if ( get_option( 'woocommerce_manage_stock' ) === 'yes' ) {
[251] Fix | Delete
$this->status_widget_stock_rows( $status_widget_reports['lowstock_link'], $status_widget_reports['outofstock_link'] );
[252] Fix | Delete
}
[253] Fix | Delete
[254] Fix | Delete
/**
[255] Fix | Delete
* Filter to change the first argument passed to the `woocommerce_after_dashboard_status_widget` action.
[256] Fix | Delete
*
[257] Fix | Delete
* Please note that this filter is mainly for backward compatibility with the legacy reports.
[258] Fix | Delete
* It's not recommended to use this filter as it will soon be deprecated along with the retiring of the legacy reports.
[259] Fix | Delete
*
[260] Fix | Delete
* @since 9.5.0
[261] Fix | Delete
*/
[262] Fix | Delete
$reports = apply_filters( 'woocommerce_after_dashboard_status_widget_parameter', null );
[263] Fix | Delete
do_action( 'woocommerce_after_dashboard_status_widget', $reports );
[264] Fix | Delete
echo '</ul>';
[265] Fix | Delete
}
[266] Fix | Delete
[267] Fix | Delete
/**
[268] Fix | Delete
* Show order data is status widget.
[269] Fix | Delete
*/
[270] Fix | Delete
private function status_widget_order_rows() {
[271] Fix | Delete
if ( ! current_user_can( 'edit_shop_orders' ) ) {
[272] Fix | Delete
return;
[273] Fix | Delete
}
[274] Fix | Delete
$on_hold_count = 0;
[275] Fix | Delete
$processing_count = 0;
[276] Fix | Delete
[277] Fix | Delete
foreach ( wc_get_order_types( 'order-count' ) as $type ) {
[278] Fix | Delete
$counts = OrderUtil::get_count_for_type( $type );
[279] Fix | Delete
$on_hold_count += $counts[ OrderInternalStatus::ON_HOLD ];
[280] Fix | Delete
$processing_count += $counts[ OrderInternalStatus::PROCESSING ];
[281] Fix | Delete
}
[282] Fix | Delete
?>
[283] Fix | Delete
<li class="processing-orders">
[284] Fix | Delete
<a href="<?php echo esc_url( admin_url( 'edit.php?post_status=wc-processing&post_type=shop_order' ) ); ?>">
[285] Fix | Delete
<?php
[286] Fix | Delete
printf(
[287] Fix | Delete
/* translators: %s: order count */
[288] Fix | Delete
_n( '<strong>%s order</strong> awaiting processing', '<strong>%s orders</strong> awaiting processing', $processing_count, 'woocommerce' ),
[289] Fix | Delete
$processing_count
[290] Fix | Delete
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
[291] Fix | Delete
?>
[292] Fix | Delete
</a>
[293] Fix | Delete
</li>
[294] Fix | Delete
<li class="on-hold-orders">
[295] Fix | Delete
<a href="<?php echo esc_url( admin_url( 'edit.php?post_status=wc-on-hold&post_type=shop_order' ) ); ?>">
[296] Fix | Delete
<?php
[297] Fix | Delete
printf(
[298] Fix | Delete
/* translators: %s: order count */
[299] Fix | Delete
_n( '<strong>%s order</strong> on-hold', '<strong>%s orders</strong> on-hold', $on_hold_count, 'woocommerce' ),
[300] Fix | Delete
$on_hold_count
[301] Fix | Delete
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
[302] Fix | Delete
?>
[303] Fix | Delete
</a>
[304] Fix | Delete
</li>
[305] Fix | Delete
<?php
[306] Fix | Delete
}
[307] Fix | Delete
[308] Fix | Delete
/**
[309] Fix | Delete
* Show stock data is status widget.
[310] Fix | Delete
*
[311] Fix | Delete
* @param string $lowstock_link Low stock link.
[312] Fix | Delete
* @param string $outofstock_link Out of stock link.
[313] Fix | Delete
*/
[314] Fix | Delete
private function status_widget_stock_rows( $lowstock_link, $outofstock_link ) {
[315] Fix | Delete
global $wpdb;
[316] Fix | Delete
[317] Fix | Delete
// Requires lookup table added in 3.6.
[318] Fix | Delete
if ( version_compare( get_option( 'woocommerce_db_version', null ), '3.6', '<' ) ) {
[319] Fix | Delete
return;
[320] Fix | Delete
}
[321] Fix | Delete
[322] Fix | Delete
$stock = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 1 ) );
[323] Fix | Delete
$nostock = absint( max( get_option( 'woocommerce_notify_no_stock_amount' ), 0 ) );
[324] Fix | Delete
[325] Fix | Delete
$transient_name = 'wc_low_stock_count';
[326] Fix | Delete
$lowinstock_count = get_transient( $transient_name );
[327] Fix | Delete
[328] Fix | Delete
if ( false === $lowinstock_count ) {
[329] Fix | Delete
/**
[330] Fix | Delete
* Status widget low in stock count pre query.
[331] Fix | Delete
*
[332] Fix | Delete
* @since 4.3.0
[333] Fix | Delete
* @param null|string $low_in_stock_count Low in stock count, by default null.
[334] Fix | Delete
* @param int $stock Low stock amount.
[335] Fix | Delete
* @param int $nostock No stock amount
[336] Fix | Delete
*/
[337] Fix | Delete
$lowinstock_count = apply_filters( 'woocommerce_status_widget_low_in_stock_count_pre_query', null, $stock, $nostock );
[338] Fix | Delete
[339] Fix | Delete
if ( is_null( $lowinstock_count ) ) {
[340] Fix | Delete
$lowinstock_count = $wpdb->get_var(
[341] Fix | Delete
$wpdb->prepare(
[342] Fix | Delete
"SELECT COUNT( product_id )
[343] Fix | Delete
FROM {$wpdb->wc_product_meta_lookup} AS lookup
[344] Fix | Delete
INNER JOIN {$wpdb->posts} as posts ON lookup.product_id = posts.ID
[345] Fix | Delete
WHERE stock_quantity <= %d
[346] Fix | Delete
AND stock_quantity > %d
[347] Fix | Delete
AND posts.post_status = 'publish'",
[348] Fix | Delete
$stock,
[349] Fix | Delete
$nostock
[350] Fix | Delete
)
[351] Fix | Delete
);
[352] Fix | Delete
}
[353] Fix | Delete
[354] Fix | Delete
set_transient( $transient_name, (int) $lowinstock_count, DAY_IN_SECONDS * 30 );
[355] Fix | Delete
}
[356] Fix | Delete
[357] Fix | Delete
$transient_name = 'wc_outofstock_count';
[358] Fix | Delete
$outofstock_count = get_transient( $transient_name );
[359] Fix | Delete
$lowstock_url = $lowstock_link ? admin_url( $lowstock_link ) : '#';
[360] Fix | Delete
$outofstock_url = $outofstock_link ? admin_url( $outofstock_link ) : '#';
[361] Fix | Delete
[362] Fix | Delete
if ( false === $outofstock_count ) {
[363] Fix | Delete
/**
[364] Fix | Delete
* Status widget out of stock count pre query.
[365] Fix | Delete
*
[366] Fix | Delete
* @since 4.3.0
[367] Fix | Delete
* @param null|string $outofstock_count Out of stock count, by default null.
[368] Fix | Delete
* @param int $nostock No stock amount
[369] Fix | Delete
*/
[370] Fix | Delete
$outofstock_count = apply_filters( 'woocommerce_status_widget_out_of_stock_count_pre_query', null, $nostock );
[371] Fix | Delete
[372] Fix | Delete
if ( is_null( $outofstock_count ) ) {
[373] Fix | Delete
$outofstock_count = (int) $wpdb->get_var(
[374] Fix | Delete
$wpdb->prepare(
[375] Fix | Delete
"SELECT COUNT( product_id )
[376] Fix | Delete
FROM {$wpdb->wc_product_meta_lookup} AS lookup
[377] Fix | Delete
INNER JOIN {$wpdb->posts} as posts ON lookup.product_id = posts.ID
[378] Fix | Delete
WHERE stock_quantity <= %d
[379] Fix | Delete
AND posts.post_status = 'publish'",
[380] Fix | Delete
$nostock
[381] Fix | Delete
)
[382] Fix | Delete
);
[383] Fix | Delete
}
[384] Fix | Delete
[385] Fix | Delete
set_transient( $transient_name, (int) $outofstock_count, DAY_IN_SECONDS * 30 );
[386] Fix | Delete
}
[387] Fix | Delete
?>
[388] Fix | Delete
<li class="low-in-stock">
[389] Fix | Delete
<a href="<?php echo esc_url( $lowstock_url ); ?>">
[390] Fix | Delete
<?php
[391] Fix | Delete
printf(
[392] Fix | Delete
/* translators: %s: order count */
[393] Fix | Delete
_n( '<strong>%s product</strong> low in stock', '<strong>%s products</strong> low in stock', $lowinstock_count, 'woocommerce' ),
[394] Fix | Delete
$lowinstock_count
[395] Fix | Delete
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
[396] Fix | Delete
?>
[397] Fix | Delete
</a>
[398] Fix | Delete
</li>
[399] Fix | Delete
<li class="out-of-stock">
[400] Fix | Delete
<a href="<?php echo esc_url( $outofstock_url ); ?>">
[401] Fix | Delete
<?php
[402] Fix | Delete
printf(
[403] Fix | Delete
/* translators: %s: order count */
[404] Fix | Delete
_n( '<strong>%s product</strong> out of stock', '<strong>%s products</strong> out of stock', $outofstock_count, 'woocommerce' ),
[405] Fix | Delete
$outofstock_count
[406] Fix | Delete
); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
[407] Fix | Delete
?>
[408] Fix | Delete
</a>
[409] Fix | Delete
</li>
[410] Fix | Delete
<?php
[411] Fix | Delete
}
[412] Fix | Delete
[413] Fix | Delete
/**
[414] Fix | Delete
* Recent reviews widget: legacy implementation.
[415] Fix | Delete
*/
[416] Fix | Delete
private function legacy_recent_reviews(): void {
[417] Fix | Delete
global $wpdb;
[418] Fix | Delete
[419] Fix | Delete
/**
[420] Fix | Delete
* Filters the from-clause used for fetching latest product reviews.
[421] Fix | Delete
*
[422] Fix | Delete
* @since 3.1.0
[423] Fix | Delete
*
[424] Fix | Delete
* @param string $clause The from-clause.
[425] Fix | Delete
*/
[426] Fix | Delete
$query_from = apply_filters(
[427] Fix | Delete
'woocommerce_report_recent_reviews_query_from',
[428] Fix | Delete
"FROM {$wpdb->comments} comments
[429] Fix | Delete
LEFT JOIN {$wpdb->posts} posts ON (comments.comment_post_ID = posts.ID)
[430] Fix | Delete
WHERE comments.comment_approved = '1'
[431] Fix | Delete
AND comments.comment_type = 'review'
[432] Fix | Delete
AND posts.post_password = ''
[433] Fix | Delete
AND posts.post_type = 'product'
[434] Fix | Delete
AND comments.comment_parent = 0
[435] Fix | Delete
ORDER BY comments.comment_date_gmt DESC
[436] Fix | Delete
LIMIT 5"
[437] Fix | Delete
);
[438] Fix | Delete
[439] Fix | Delete
$comments = $wpdb->get_results(
[440] Fix | Delete
"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
[441] Fix | Delete
);
[442] Fix | Delete
[443] Fix | Delete
if ( $comments ) {
[444] Fix | Delete
echo '<ul>';
[445] Fix | Delete
foreach ( $comments as $comment ) {
[446] Fix | Delete
[447] Fix | Delete
echo '<li>';
[448] Fix | Delete
[449] Fix | Delete
echo get_avatar( $comment->comment_author_email, '32' );
[450] Fix | Delete
[451] Fix | Delete
/**
[452] Fix | Delete
* Filters the product name for display in the latest reviews.
[453] Fix | Delete
*
[454] Fix | Delete
* @param string $product_title The product name.
[455] Fix | Delete
* @param \stdClass $comment The comment.
[456] Fix | Delete
* @since 2.1.0
[457] Fix | Delete
*/
[458] Fix | Delete
$product_title = apply_filters( 'woocommerce_admin_dashboard_recent_reviews', $comment->post_title, $comment );
[459] Fix | Delete
$rating = intval( get_comment_meta( $comment->comment_ID, 'rating', true ) );
[460] Fix | Delete
[461] Fix | Delete
/* translators: %s: rating */
[462] Fix | Delete
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>';
[463] Fix | Delete
[464] Fix | Delete
/* translators: %s: review author */
[465] Fix | Delete
echo '<h4 class="meta"><a href="' . esc_url( get_permalink( $comment->ID ) ) . '#comment-' . esc_attr( absint( $comment->comment_ID ) ) . '">' . esc_html( $product_title ) . '</a> ' . sprintf( esc_html__( 'reviewed by %s', 'woocommerce' ), esc_html( $comment->comment_author ) ) . '</h4>';
[466] Fix | Delete
echo '<blockquote>' . wp_kses_data( $comment->comment_content ) . '</blockquote></li>';
[467] Fix | Delete
[468] Fix | Delete
}
[469] Fix | Delete
echo '</ul>';
[470] Fix | Delete
} else {
[471] Fix | Delete
echo '<p>' . esc_html__( 'There are no product reviews yet.', 'woocommerce' ) . '</p>';
[472] Fix | Delete
}
[473] Fix | Delete
}
[474] Fix | Delete
[475] Fix | Delete
/**
[476] Fix | Delete
* Recent reviews widget: placeholder.
[477] Fix | Delete
*/
[478] Fix | Delete
public function recent_reviews() {
[479] Fix | Delete
$suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
[480] Fix | Delete
$version = Constants::get_constant( 'WC_VERSION' );
[481] Fix | Delete
[482] Fix | Delete
wp_enqueue_script( 'wc-recent-reviews-widget-async', WC()->plugin_url() . '/assets/js/admin/wc-recent-reviews-widget-async' . $suffix . '.js', array( 'jquery' ), $version, true );
[483] Fix | Delete
wp_localize_script(
[484] Fix | Delete
'wc-recent-reviews-widget-async',
[485] Fix | Delete
'wc_recent_reviews_widget_params',
[486] Fix | Delete
array(
[487] Fix | Delete
'ajax_url' => admin_url( 'admin-ajax.php' ),
[488] Fix | Delete
'security' => wp_create_nonce( 'wc-recent-reviews-widget' ),
[489] Fix | Delete
'error_message' => esc_html__( 'Error loading widget', 'woocommerce' ),
[490] Fix | Delete
)
[491] Fix | Delete
);
[492] Fix | Delete
[493] Fix | Delete
// Display loading placeholder.
[494] Fix | Delete
echo '<div id="wc-recent-reviews-widget-loading" class="wc-recent-reviews-widget-loading">';
[495] Fix | Delete
echo '<p>' . esc_html__( 'Loading reviews data...', 'woocommerce' ) . ' <span class="spinner is-active"></span></p>';
[496] Fix | Delete
echo '</div>';
[497] Fix | Delete
echo '<div id="wc-recent-reviews-widget-content" style="display:none;"></div>';
[498] Fix | Delete
}
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function