2013-07-25 14:00:23 +00:00
< ? php
/**
2015-11-03 13:53:50 +00:00
* Admin Dashboard
2013-07-25 14:00:23 +00:00
*
2014-11-30 06:52:32 +00:00
* @ author WooThemes
* @ category Admin
* @ package WooCommerce / Admin
2013-07-25 14:00:23 +00:00
* @ version 2.1 . 0
*/
2014-09-20 19:52:30 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ; // Exit if accessed directly
}
2013-07-25 14:00:23 +00:00
2017-02-16 11:46:01 +00:00
if ( ! class_exists ( 'WC_Admin_Dashboard' , false ) ) :
2013-07-25 14:00:23 +00:00
/**
2018-03-05 18:59:17 +00:00
* WC_Admin_Dashboard Class .
2013-07-25 14:00:23 +00:00
*/
2018-03-05 18:59:17 +00:00
class WC_Admin_Dashboard {
/**
* Hook in tabs .
*/
public function __construct () {
// Only hook in admin parts if the user has admin access
if ( current_user_can ( 'view_woocommerce_reports' ) || current_user_can ( 'manage_woocommerce' ) || current_user_can ( 'publish_shop_orders' ) ) {
// If on network admin, only load the widget that works in that context and skip the rest.
if ( is_multisite () && is_network_admin () ) {
add_action ( 'wp_network_dashboard_setup' , array ( $this , 'register_network_order_widget' ) );
} else {
add_action ( 'wp_dashboard_setup' , array ( $this , 'init' ) );
}
2017-11-18 00:00:48 +00:00
}
2014-01-11 00:18:28 +00:00
}
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
/**
* Init dashboard widgets .
*/
public function init () {
if ( current_user_can ( 'publish_shop_orders' ) && post_type_supports ( 'product' , 'comments' ) ) {
2018-11-14 17:34:15 +00:00
wp_add_dashboard_widget ( 'woocommerce_dashboard_recent_reviews' , __ ( 'WooCommerce Recent Reviews' , 'woocommerce' ), array ( $this , 'recent_reviews' ) );
2018-03-05 18:59:17 +00:00
}
2018-11-14 17:34:15 +00:00
wp_add_dashboard_widget ( 'woocommerce_dashboard_status' , __ ( 'WooCommerce Status' , 'woocommerce' ), array ( $this , 'status_widget' ) );
2017-10-24 19:08:34 +00:00
2018-03-05 18:59:17 +00:00
// Network Order Widget.
if ( is_multisite () ) {
$this -> register_network_order_widget ();
}
2017-11-06 16:30:44 +00:00
}
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
/**
* Register the network order dashboard widget .
*/
public function register_network_order_widget () {
2018-11-14 17:34:15 +00:00
wp_add_dashboard_widget ( 'woocommerce_network_orders' , __ ( 'WooCommerce Network Orders' , 'woocommerce' ), array ( $this , 'network_orders' ) );
2018-03-05 18:59:17 +00:00
}
2017-11-18 00:00:48 +00:00
2018-03-05 18:59:17 +00:00
/**
* Get top seller from DB .
*
* @ return object
*/
private function get_top_seller () {
global $wpdb ;
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
$query = array ();
$query [ 'fields' ] = " SELECT SUM( order_item_meta.meta_value ) as qty, order_item_meta_2.meta_value as product_id
2014-05-28 14:19:16 +00:00
FROM { $wpdb -> posts } as posts " ;
2018-03-05 18:59:17 +00:00
$query [ 'join' ] = " INNER JOIN { $wpdb -> prefix } woocommerce_order_items AS order_items ON posts.ID = order_id " ;
$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 " ;
$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 " ;
$query [ 'where' ] = " WHERE posts.post_type IN ( ' " . implode ( " ',' " , wc_get_order_types ( 'order-count' ) ) . " ' ) " ;
$query [ 'where' ] .= " AND posts.post_status IN ( 'wc- " . implode ( " ','wc- " , apply_filters ( 'woocommerce_reports_order_statuses' , array ( 'completed' , 'processing' , 'on-hold' ) ) ) . " ' ) " ;
$query [ 'where' ] .= " AND order_item_meta.meta_key = '_qty' " ;
$query [ 'where' ] .= " AND order_item_meta_2.meta_key = '_product_id' " ;
$query [ 'where' ] .= " AND posts.post_date >= ' " . date ( 'Y-m-01' , current_time ( 'timestamp' ) ) . " ' " ;
$query [ 'where' ] .= " AND posts.post_date <= ' " . date ( 'Y-m-d H:i:s' , current_time ( 'timestamp' ) ) . " ' " ;
$query [ 'groupby' ] = 'GROUP BY product_id' ;
$query [ 'orderby' ] = 'ORDER BY qty DESC' ;
$query [ 'limits' ] = 'LIMIT 1' ;
return $wpdb -> get_row ( implode ( ' ' , apply_filters ( 'woocommerce_dashboard_status_widget_top_seller_query' , $query ) ) );
}
2016-10-25 10:43:44 +00:00
2018-03-05 18:59:17 +00:00
/**
* Get sales report data .
*
* @ return object
*/
private function get_sales_report_data () {
include_once dirname ( __FILE__ ) . '/reports/class-wc-report-sales-by-date.php' ;
$sales_by_date = new WC_Report_Sales_By_Date ();
$sales_by_date -> start_date = strtotime ( date ( 'Y-m-01' , current_time ( 'timestamp' ) ) );
$sales_by_date -> end_date = current_time ( 'timestamp' );
$sales_by_date -> chart_groupby = 'day' ;
$sales_by_date -> group_by_query = 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)' ;
return $sales_by_date -> get_report_data ();
}
2016-10-25 10:43:44 +00:00
2018-03-05 18:59:17 +00:00
/**
* Show status widget .
*/
public function status_widget () {
include_once dirname ( __FILE__ ) . '/reports/class-wc-admin-report.php' ;
2016-10-25 10:43:44 +00:00
2018-03-05 18:59:17 +00:00
$reports = new WC_Admin_Report ();
2016-10-25 10:43:44 +00:00
2018-03-05 18:59:17 +00:00
echo '<ul class="wc_status_list">' ;
2016-10-25 10:43:44 +00:00
2018-03-05 18:59:17 +00:00
if ( current_user_can ( 'view_woocommerce_reports' ) && ( $report_data = $this -> get_sales_report_data () ) ) {
?>
< li class = " sales-this-month " >
2016-10-25 10:43:44 +00:00
< a href = " <?php echo admin_url( 'admin.php?page=wc-reports&tab=orders&range=month' ); ?> " >
< ? php echo $reports -> sales_sparkline ( '' , max ( 7 , date ( 'd' , current_time ( 'timestamp' ) ) ) ); ?>
2016-10-29 10:16:03 +00:00
< ? php
/* translators: %s: net sales */
printf (
__ ( '%s net sales this month' , 'woocommerce' ),
'<strong>' . wc_price ( $report_data -> net_sales ) . '</strong>'
2018-03-05 18:59:17 +00:00
);
?>
</ a >
</ li >
< ? php
}
2016-10-25 10:43:44 +00:00
2018-03-05 18:59:17 +00:00
if ( current_user_can ( 'view_woocommerce_reports' ) && ( $top_seller = $this -> get_top_seller () ) && $top_seller -> qty ) {
?>
< li class = " best-seller-this-month " >
2016-10-25 10:43:44 +00:00
< a href = " <?php echo admin_url( 'admin.php?page=wc-reports&tab=orders&report=sales_by_product&range=month&product_ids=' . $top_seller->product_id ); ?> " >
< ? php echo $reports -> sales_sparkline ( $top_seller -> product_id , max ( 7 , date ( 'd' , current_time ( 'timestamp' ) ) ), 'count' ); ?>
2016-10-29 10:16:03 +00:00
< ? php
/* translators: 1: top seller product title 2: top seller quantity */
printf (
__ ( '%1$s top seller this month (sold %2$d)' , 'woocommerce' ),
'<strong>' . get_the_title ( $top_seller -> product_id ) . '</strong>' ,
$top_seller -> qty
);
2018-03-05 18:59:17 +00:00
?>
</ a >
</ li >
< ? php
}
2016-10-25 10:43:44 +00:00
2018-03-05 18:59:17 +00:00
$this -> status_widget_order_rows ();
$this -> status_widget_stock_rows ();
2016-10-25 10:43:44 +00:00
2018-03-05 18:59:17 +00:00
do_action ( 'woocommerce_after_dashboard_status_widget' , $reports );
echo '</ul>' ;
2016-10-25 10:43:44 +00:00
}
2014-07-11 11:43:42 +00:00
2018-03-05 18:59:17 +00:00
/**
* Show order data is status widget .
*/
private function status_widget_order_rows () {
if ( ! current_user_can ( 'edit_shop_orders' ) ) {
return ;
}
$on_hold_count = 0 ;
$processing_count = 0 ;
foreach ( wc_get_order_types ( 'order-count' ) as $type ) {
$counts = ( array ) wp_count_posts ( $type );
$on_hold_count += isset ( $counts [ 'wc-on-hold' ] ) ? $counts [ 'wc-on-hold' ] : 0 ;
$processing_count += isset ( $counts [ 'wc-processing' ] ) ? $counts [ 'wc-processing' ] : 0 ;
}
?>
< li class = " processing-orders " >
2016-10-25 10:43:44 +00:00
< a href = " <?php echo admin_url( 'edit.php?post_status=wc-processing&post_type=shop_order' ); ?> " >
2016-10-29 10:16:03 +00:00
< ? php
/* translators: %s: order count */
printf (
_n ( '<strong>%s order</strong> awaiting processing' , '<strong>%s orders</strong> awaiting processing' , $processing_count , 'woocommerce' ),
$processing_count
);
?>
2018-03-05 18:59:17 +00:00
</ a >
</ li >
< li class = " on-hold-orders " >
< a href = " <?php echo admin_url( 'edit.php?post_status=wc-on-hold&post_type=shop_order' ); ?> " >
2016-10-29 10:16:03 +00:00
< ? php
/* translators: %s: order count */
printf (
_n ( '<strong>%s order</strong> on-hold' , '<strong>%s orders</strong> on-hold' , $on_hold_count , 'woocommerce' ),
$on_hold_count
);
?>
2018-03-05 18:59:17 +00:00
</ a >
</ li >
< ? php
2015-03-09 11:07:49 +00:00
}
2018-03-05 18:59:17 +00:00
/**
* Show stock data is status widget .
*/
private function status_widget_stock_rows () {
global $wpdb ;
// Get products using a query - this is too advanced for get_posts :(
$stock = absint ( max ( get_option ( 'woocommerce_notify_low_stock_amount' ), 1 ) );
$nostock = absint ( max ( get_option ( 'woocommerce_notify_no_stock_amount' ), 0 ) );
$transient_name = 'wc_low_stock_count' ;
if ( false === ( $lowinstock_count = get_transient ( $transient_name ) ) ) {
$query_from = apply_filters (
'woocommerce_report_low_in_stock_query_from' ,
" FROM { $wpdb -> posts } as posts
INNER JOIN { $wpdb -> postmeta } AS postmeta ON posts . ID = postmeta . post_id
INNER JOIN { $wpdb -> postmeta } AS postmeta2 ON posts . ID = postmeta2 . post_id
WHERE 1 = 1
AND posts . post_type IN ( 'product' , 'product_variation' )
AND posts . post_status = 'publish'
AND postmeta2 . meta_key = '_manage_stock' AND postmeta2 . meta_value = 'yes'
AND postmeta . meta_key = '_stock' AND CAST ( postmeta . meta_value AS SIGNED ) <= '{$stock}'
AND postmeta . meta_key = '_stock' AND CAST ( postmeta . meta_value AS SIGNED ) > '{$nostock}' "
);
$lowinstock_count = absint ( $wpdb -> get_var ( " SELECT COUNT( DISTINCT posts.ID ) { $query_from } ; " ) );
set_transient ( $transient_name , $lowinstock_count , DAY_IN_SECONDS * 30 );
}
$transient_name = 'wc_outofstock_count' ;
if ( false === ( $outofstock_count = get_transient ( $transient_name ) ) ) {
$query_from = apply_filters (
'woocommerce_report_out_of_stock_query_from' ,
" FROM { $wpdb -> posts } as posts
INNER JOIN { $wpdb -> postmeta } AS postmeta ON posts . ID = postmeta . post_id
INNER JOIN { $wpdb -> postmeta } AS postmeta2 ON posts . ID = postmeta2 . post_id
WHERE 1 = 1
AND posts . post_type IN ( 'product' , 'product_variation' )
AND posts . post_status = 'publish'
AND postmeta2 . meta_key = '_manage_stock' AND postmeta2 . meta_value = 'yes'
AND postmeta . meta_key = '_stock' AND CAST ( postmeta . meta_value AS SIGNED ) <= '{$nostock}' "
);
$outofstock_count = absint ( $wpdb -> get_var ( " SELECT COUNT( DISTINCT posts.ID ) { $query_from } ; " ) );
set_transient ( $transient_name , $outofstock_count , DAY_IN_SECONDS * 30 );
}
?>
< li class = " low-in-stock " >
2016-10-25 10:43:44 +00:00
< a href = " <?php echo admin_url( 'admin.php?page=wc-reports&tab=stock&report=low_in_stock' ); ?> " >
2016-10-29 10:16:03 +00:00
< ? php
/* translators: %s: order count */
printf (
_n ( '<strong>%s product</strong> low in stock' , '<strong>%s products</strong> low in stock' , $lowinstock_count , 'woocommerce' ),
$lowinstock_count
);
?>
2018-03-05 18:59:17 +00:00
</ a >
</ li >
< li class = " out-of-stock " >
< a href = " <?php echo admin_url( 'admin.php?page=wc-reports&tab=stock&report=out_of_stock' ); ?> " >
2016-10-29 10:16:03 +00:00
< ? php
/* translators: %s: order count */
printf (
_n ( '<strong>%s product</strong> out of stock' , '<strong>%s products</strong> out of stock' , $outofstock_count , 'woocommerce' ),
$outofstock_count
);
?>
2018-03-05 18:59:17 +00:00
</ a >
</ li >
< ? php
}
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
/**
* Recent reviews widget .
*/
public function recent_reviews () {
global $wpdb ;
2017-06-08 11:21:55 +00:00
2018-03-05 18:59:17 +00:00
$query_from = apply_filters (
'woocommerce_report_recent_reviews_query_from' ,
" FROM { $wpdb -> comments } comments
LEFT JOIN { $wpdb -> posts } posts ON ( comments . comment_post_ID = posts . ID )
WHERE comments . comment_approved = '1'
2018-10-26 11:16:16 +00:00
AND comments . comment_type = 'review'
2018-03-05 18:59:17 +00:00
AND posts . post_password = ''
AND posts . post_type = 'product'
AND comments . comment_parent = 0
ORDER BY comments . comment_date_gmt DESC
LIMIT 5 "
);
2017-06-08 11:21:55 +00:00
2018-03-05 18:59:17 +00:00
$comments = $wpdb -> get_results (
" SELECT posts.ID, posts.post_title, comments.comment_author, comments.comment_ID, comments.comment_content { $query_from } ; "
);
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
if ( $comments ) {
echo '<ul>' ;
foreach ( $comments as $comment ) {
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
echo '<li>' ;
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
echo get_avatar ( $comment -> comment_author , '32' );
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
$rating = intval ( get_comment_meta ( $comment -> comment_ID , 'rating' , true ) );
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
/* translators: %s: rating */
echo '<div class="star-rating"><span style="width:' . ( $rating * 20 ) . '%">' . sprintf ( __ ( '%s out of 5' , 'woocommerce' ), $rating ) . '</span></div>' ;
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
/* translators: %s: review author */
echo '<h4 class="meta"><a href="' . get_permalink ( $comment -> ID ) . '#comment-' . absint ( $comment -> comment_ID ) . '">' . esc_html ( apply_filters ( 'woocommerce_admin_dashboard_recent_reviews' , $comment -> post_title , $comment ) ) . '</a> ' . sprintf ( __ ( 'reviewed by %s' , 'woocommerce' ), esc_html ( $comment -> comment_author ) ) . '</h4>' ;
echo '<blockquote>' . wp_kses_data ( $comment -> comment_content ) . '</blockquote></li>' ;
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
}
echo '</ul>' ;
} else {
echo '<p>' . __ ( 'There are no product reviews yet.' , 'woocommerce' ) . '</p>' ;
2013-07-25 14:00:23 +00:00
}
}
2017-10-24 19:08:34 +00:00
2018-03-05 18:59:17 +00:00
/**
* Network orders widget .
*/
public function network_orders () {
$suffix = defined ( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ;
2017-11-06 17:08:07 +00:00
2018-03-05 18:59:17 +00:00
wp_enqueue_style ( 'wc-network-orders' , WC () -> plugin_url () . '/assets/css/network-order-widget.css' , array (), WC_VERSION );
2017-11-17 23:44:17 +00:00
2018-03-05 18:59:17 +00:00
wp_enqueue_script ( 'wc-network-orders' , WC () -> plugin_url () . '/assets/js/admin/network-orders' . $suffix . '.js' , array ( 'jquery' , 'underscore' ), WC_VERSION , true );
2017-10-25 03:45:34 +00:00
2018-03-05 18:59:17 +00:00
$user = wp_get_current_user ();
$blogs = get_blogs_of_user ( $user -> ID );
$blog_ids = wp_list_pluck ( $blogs , 'userblog_id' );
2017-10-25 03:45:34 +00:00
2018-03-05 18:59:17 +00:00
wp_localize_script (
'wc-network-orders' , 'woocommerce_network_orders' , array (
'nonce' => wp_create_nonce ( 'wp_rest' ),
'sites' => array_values ( $blog_ids ),
'order_endpoint' => get_rest_url ( null , 'wc/v2/orders/network' ),
)
);
?>
< div class = " post-type-shop_order " >
2017-11-06 17:44:55 +00:00
< div id = " woocommerce-network-order-table-loading " class = " woocommerce-network-order-table-loading is-active " >
2017-11-06 17:30:32 +00:00
< p >
2017-11-15 02:04:45 +00:00
< span class = " spinner is-active " ></ span > < ? php esc_html_e ( 'Loading network orders' , 'woocommerce' ); ?>
2017-11-06 17:30:32 +00:00
</ p >
</ div >
2017-11-18 00:06:24 +00:00
< table id = " woocommerce-network-order-table " class = " woocommerce-network-order-table " >
2017-10-24 19:08:34 +00:00
< thead >
< tr >
2017-11-15 02:05:44 +00:00
< td >< ? php esc_html_e ( 'Order' , 'woocommerce' ); ?> </td>
< td >< ? php esc_html_e ( 'Status' , 'woocommerce' ); ?> </td>
< td >< ? php esc_html_e ( 'Total' , 'woocommerce' ); ?> </td>
2017-10-24 19:08:34 +00:00
</ tr >
</ thead >
< tbody id = " network-orders-tbody " >
</ tbody >
</ table >
2017-11-06 17:44:55 +00:00
< div id = " woocommerce-network-orders-no-orders " class = " woocommerce-network-orders-no-orders " >
< p >
2017-11-15 01:59:20 +00:00
< ? php esc_html_e ( 'No orders found' , 'woocommerce' ); ?>
2017-11-06 17:44:55 +00:00
</ p >
</ div >
2017-10-24 19:08:34 +00:00
< script type = " text/template " id = " network-orders-row-template " >
< tr >
< td >
2018-06-08 15:59:27 +00:00
< a href = " <%- edit_url %> " class = " order-view " >< strong > #<%- number %> <%- customer %></strong></a>
2017-10-24 19:08:34 +00:00
< br >
< em >
<%- blog . blogname %>
</ em >
</ td >
< td >
< mark class = " order-status status-<%- status %> " >< span ><%- status_name %></ span ></ mark >
</ td >
< td >
<%= formatted_total %>
</ td >
</ tr >
</ script >
</ div >
< ? php
2018-03-05 18:59:17 +00:00
}
2017-10-24 19:08:34 +00:00
2018-03-05 18:59:17 +00:00
}
2013-07-25 14:00:23 +00:00
endif ;
2014-01-11 00:14:27 +00:00
return new WC_Admin_Dashboard ();