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
/**
2015-11-03 12:28:01 +00:00
* WC_Admin_Dashboard Class .
2013-07-25 14:00:23 +00:00
*/
class WC_Admin_Dashboard {
/**
* Hook in tabs .
*/
public function __construct () {
// Only hook in admin parts if the user has admin access
2014-01-11 00:18:28 +00:00
if ( current_user_can ( 'view_woocommerce_reports' ) || current_user_can ( 'manage_woocommerce' ) || current_user_can ( 'publish_shop_orders' ) ) {
2013-07-25 14:00:23 +00:00
add_action ( 'wp_dashboard_setup' , array ( $this , 'init' ) );
2014-01-11 00:18:28 +00:00
}
2013-07-25 14:00:23 +00:00
}
/**
2015-11-03 12:28:01 +00:00
* Init dashboard widgets .
2013-07-25 14:00:23 +00:00
*/
public function init () {
2017-06-08 14:26:30 +00:00
if ( current_user_can ( 'publish_shop_orders' ) && post_type_supports ( 'product' , 'comments' ) ) {
2016-10-12 10:16:30 +00:00
wp_add_dashboard_widget ( 'woocommerce_dashboard_recent_reviews' , __ ( 'WooCommerce recent reviews' , 'woocommerce' ), array ( $this , 'recent_reviews' ) );
2013-07-25 14:00:23 +00:00
}
2016-10-12 10:16:30 +00:00
wp_add_dashboard_widget ( 'woocommerce_dashboard_status' , __ ( 'WooCommerce status' , 'woocommerce' ), array ( $this , 'status_widget' ) );
2017-10-24 19:08:34 +00:00
2017-11-15 01:59:20 +00:00
// Network Order Widget.
2017-11-06 16:30:44 +00:00
if ( is_multisite () ) {
2017-11-15 01:59:20 +00:00
wp_add_dashboard_widget ( 'woocommerce_network_orders' , __ ( 'WooCommerce network orders' , 'woocommerce' ), array ( $this , 'network_orders' ) );
2017-11-06 16:30:44 +00:00
}
2013-07-25 14:00:23 +00:00
}
/**
2016-10-25 10:43:44 +00:00
* Get top seller from DB .
* @ return object
2013-07-25 14:00:23 +00:00
*/
2016-10-25 10:43:44 +00:00
private function get_top_seller () {
2013-07-25 14:00:23 +00:00
global $wpdb ;
2014-05-28 14:19:16 +00:00
$query = array ();
$query [ 'fields' ] = " SELECT SUM( order_item_meta.meta_value ) as qty, order_item_meta_2.meta_value as product_id
FROM { $wpdb -> posts } as posts " ;
2014-05-30 17:29:53 +00:00
$query [ 'join' ] = " INNER JOIN { $wpdb -> prefix } woocommerce_order_items AS order_items ON posts.ID = order_id " ;
2014-05-28 14:19:16 +00:00
$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 " ;
2014-07-25 14:48:37 +00:00
$query [ 'where' ] = " WHERE posts.post_type IN ( ' " . implode ( " ',' " , wc_get_order_types ( 'order-count' ) ) . " ' ) " ;
2014-06-03 10:29:01 +00:00
$query [ 'where' ] .= " AND posts.post_status IN ( 'wc- " . implode ( " ','wc- " , apply_filters ( 'woocommerce_reports_order_statuses' , array ( 'completed' , 'processing' , 'on-hold' ) ) ) . " ' ) " ;
2014-05-28 14:19:16 +00:00
$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 " ;
2016-10-25 10:43:44 +00:00
return $wpdb -> get_row ( implode ( ' ' , apply_filters ( 'woocommerce_dashboard_status_widget_top_seller_query' , $query ) ) );
}
2013-07-25 14:00:23 +00:00
2016-10-25 10:43:44 +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 ();
}
/**
* Show status widget .
*/
public function status_widget () {
include_once ( dirname ( __FILE__ ) . '/reports/class-wc-admin-report.php' );
$reports = new WC_Admin_Report ();
echo '<ul class="wc_status_list">' ;
if ( current_user_can ( 'view_woocommerce_reports' ) && ( $report_data = $this -> get_sales_report_data () ) ) {
?>
< li class = " sales-this-month " >
< 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>'
);
?>
2016-10-25 10:43:44 +00:00
</ a >
</ li >
< ? php
}
if ( current_user_can ( 'view_woocommerce_reports' ) && ( $top_seller = $this -> get_top_seller () ) && $top_seller -> qty ) {
?>
< li class = " best-seller-this-month " >
< 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
);
?>
2016-10-25 10:43:44 +00:00
</ a >
</ li >
< ? php
}
$this -> status_widget_order_rows ();
$this -> status_widget_stock_rows ();
do_action ( 'woocommerce_after_dashboard_status_widget' , $reports );
echo '</ul>' ;
}
/**
* Show order data is status widget .
*/
private function status_widget_order_rows () {
if ( ! current_user_can ( 'edit_shop_orders' ) ) {
return ;
}
2014-07-11 11:43:42 +00:00
$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 ;
2014-07-11 18:03:34 +00:00
$processing_count += isset ( $counts [ 'wc-processing' ] ) ? $counts [ 'wc-processing' ] : 0 ;
2014-07-11 11:43:42 +00:00
}
2016-10-25 10:43:44 +00:00
?>
< li class = " processing-orders " >
< 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
);
?>
2016-10-25 10:43:44 +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
);
?>
2016-10-25 10:43:44 +00:00
</ a >
</ li >
< ? php
}
/**
* Show stock data is status widget .
*/
private function status_widget_stock_rows () {
global $wpdb ;
2013-07-25 14:00:23 +00:00
// Get products using a query - this is too advanced for get_posts :(
2015-03-09 11:07:49 +00:00
$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 );
}
2013-07-25 14:00:23 +00:00
?>
2016-10-25 10:43:44 +00:00
< li class = " low-in-stock " >
< 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
);
?>
2016-10-25 10:43:44 +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
);
?>
2016-10-25 10:43:44 +00:00
</ a >
</ li >
2013-07-25 14:00:23 +00:00
< ? php
}
/**
2015-11-03 12:28:01 +00:00
* Recent reviews widget .
2013-07-25 14:00:23 +00:00
*/
public function recent_reviews () {
global $wpdb ;
2017-06-08 11:21:55 +00:00
2017-03-01 17:34:42 +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 )
2017-02-13 12:58:42 +00:00
WHERE comments . comment_approved = '1'
AND comments . comment_type = ''
AND posts . post_password = ''
AND posts . post_type = 'product'
2017-05-29 09:09:17 +00:00
AND comments . comment_parent = 0
2017-02-13 12:58:42 +00:00
ORDER BY comments . comment_date_gmt DESC
LIMIT 5
" );
2017-06-08 11:21:55 +00:00
2017-03-01 17:34:42 +00:00
$comments = $wpdb -> get_results ( "
2017-06-08 11:21:55 +00:00
SELECT posts . ID , posts . post_title , comments . comment_author , comments . comment_ID , comments . comment_content
2017-03-01 17:34:42 +00:00
{ $query_from };
" );
2013-07-25 14:00:23 +00:00
if ( $comments ) {
echo '<ul>' ;
foreach ( $comments as $comment ) {
echo '<li>' ;
echo get_avatar ( $comment -> comment_author , '32' );
2015-05-21 08:15:07 +00:00
$rating = intval ( get_comment_meta ( $comment -> comment_ID , 'rating' , true ) );
2013-07-25 14:00:23 +00:00
2016-10-29 10:16:03 +00:00
/* translators: %s: rating */
2016-11-04 15:40:15 +00:00
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
2016-10-29 10:16:03 +00:00
/* translators: %s: review author */
2016-10-24 07:33:32 +00:00
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>' ;
2017-06-08 11:21:55 +00:00
echo '<blockquote>' . wp_kses_data ( $comment -> comment_content ) . '</blockquote></li>' ;
2013-07-25 14:00:23 +00:00
}
echo '</ul>' ;
} else {
echo '<p>' . __ ( 'There are no product reviews yet.' , 'woocommerce' ) . '</p>' ;
}
}
2017-10-24 19:08:34 +00:00
/**
2017-11-15 01:59:20 +00:00
* Network orders widget .
2017-10-24 19:08:34 +00:00
*/
public function network_orders () {
2017-11-06 17:08:07 +00:00
$suffix = defined ( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ;
2017-11-17 22:54:44 +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
$user = wp_get_current_user ();
$blogs = get_blogs_of_user ( $user -> ID );
$blog_ids = wp_list_pluck ( $blogs , 'userblog_id' );
2017-11-17 22:54:44 +00:00
wp_localize_script ( 'wc-network-orders' , 'woocommerce_network_orders' , array (
2017-10-24 19:08:34 +00:00
'nonce' => wp_create_nonce ( 'wp_rest' ),
2017-10-25 03:45:34 +00:00
'sites' => array_values ( $blog_ids ),
2017-10-24 19:08:34 +00:00
'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-06 17:44:55 +00:00
< table id = " woocommerce-network-order-table " class = " woocommerce-network-order-table wp-list-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 >
< a href = " <%- edit_url %> " class = " order-view " >< strong > #<%- id %> <%- buyer %></strong></a>
< 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
}
2013-07-25 14:00:23 +00:00
}
endif ;
2014-01-11 00:14:27 +00:00
return new WC_Admin_Dashboard ();