JezK
Edit File: premium-dashboard-analytics.php
<?php /** * Plugin Name: Premium Dashboard Analytics * Plugin URI: https://advaxe.com * Description: A premium, clean, and eye-catching WooCommerce analytics dashboard widget with AJAX Load More. * Version: 1.1.0 * Author: advaxe * Author URI: https://advaxe.com * Text Domain: advaxe-analytics */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } /** * Check if WooCommerce is active */ if ( ! in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) { add_action( 'admin_notices', 'advaxe_wc_missing_notice' ); function advaxe_wc_missing_notice() { echo '<div class="error"><p><strong>Premium Dashboard Analytics:</strong> WooCommerce is required. Please install and activate WooCommerce.</p></div>'; } return; } /** * Enqueue Scripts and Styles */ add_action( 'admin_enqueue_scripts', 'advaxe_enqueue_dashboard_scripts' ); function advaxe_enqueue_dashboard_scripts( $hook ) { if ( 'index.php' === $hook ) { wp_enqueue_script( 'chart-js', 'https://cdn.jsdelivr.net/npm/chart.js', array(), '3.9.1', true ); wp_enqueue_style( 'font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css', array(), '6.4.0' ); } } /** * Register Dashboard Widget */ add_action( 'wp_dashboard_setup', 'advaxe_add_dashboard_widgets' ); function advaxe_add_dashboard_widgets() { wp_add_dashboard_widget( 'advaxe_premium_analytics', '<i class="fas fa-chart-pie"></i> Premium Dashboard Analytics', 'advaxe_premium_analytics_render' ); } /** * Get Total Sales (HPOS Compatible) */ function advaxe_get_total_sales_amount() { global $wpdb; $total = 0; // Check if WooCommerce HPOS (High-Performance Order Storage) is enabled if ( class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' ) && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ) { $total = $wpdb->get_var( "SELECT SUM(total_amount) FROM {$wpdb->prefix}wc_orders WHERE status = 'wc-completed'" ); } else { // Legacy Post Meta $total = $wpdb->get_var( " SELECT SUM(meta_value) FROM {$wpdb->postmeta} LEFT JOIN {$wpdb->posts} ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID WHERE meta_key = '_order_total' AND post_status = 'wc-completed' " ); } return $total ? $total : 0; } /** * Render Dashboard Widget Content */ function advaxe_premium_analytics_render() { $completed_orders = wc_orders_count( 'completed' ); $processing_orders = wc_orders_count( 'processing' ); $on_hold_orders = wc_orders_count( 'on-hold' ); $cancelled_orders = wc_orders_count( 'cancelled' ); $refunded_orders = wc_orders_count( 'refunded' ); $total_orders = $completed_orders + $processing_orders + $on_hold_orders + $cancelled_orders + $refunded_orders; $users_query = new WP_User_Query( array( 'role' => 'customer', 'fields' => 'ID' ) ); $total_customers = $users_query->get_total(); $total_sales_raw = advaxe_get_total_sales_amount(); $total_sales = wc_price( $total_sales_raw ); global $wpdb; // Get COD Orders count (Legacy & HPOS approach) if ( class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' ) && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ) { $cod_orders = $wpdb->get_var( "SELECT COUNT(id) FROM {$wpdb->prefix}wc_orders WHERE payment_method = 'cod'" ); } else { $cod_orders = $wpdb->get_var( "SELECT COUNT(post_id) FROM {$wpdb->postmeta} WHERE meta_key = '_payment_method' AND meta_value = 'cod'" ); } $online_orders = max( 0, $total_orders - $cod_orders ); ?> <style> #advaxe_premium_analytics { border: none; box-shadow: 0 10px 30px rgba(0,0,0,0.08); border-radius: 12px; background: #f8f9fc; } #advaxe_premium_analytics h2 { background: #fff; border-bottom: 1px solid #eaecf4; border-radius: 12px 12px 0 0; font-weight: 700; color: #4e73df; padding: 15px 20px; } .advaxe-dashboard { padding: 20px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f8f9fc; } .advaxe-grid-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px; margin-bottom: 30px; } .advaxe-card { background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.04); border-left: 5px solid #4e73df; display: flex; align-items: center; justify-content: space-between; transition: transform 0.2s; } .advaxe-card:hover { transform: translateY(-5px); box-shadow: 0 8px 25px rgba(0,0,0,0.1); } .advaxe-card-info h4 { margin: 0 0 5px 0; font-size: 13px; color: #858796; text-transform: uppercase; font-weight: 700; } .advaxe-card-info h3 { margin: 0; font-size: 24px; color: #5a5c69; font-weight: bold; } .advaxe-card-icon { font-size: 28px; color: #dddfeb; } .card-primary { border-left-color: #4e73df; } .card-primary .advaxe-card-info h4 { color: #4e73df; } .card-success { border-left-color: #1cc88a; } .card-success .advaxe-card-info h4 { color: #1cc88a; } .card-warning { border-left-color: #f6c23e; } .card-warning .advaxe-card-info h4 { color: #f6c23e; } .card-danger { border-left-color: #e74a3b; } .card-danger .advaxe-card-info h4 { color: #e74a3b; } .card-info { border-left-color: #36b9cc; } .card-info .advaxe-card-info h4 { color: #36b9cc; } .card-dark { border-left-color: #5a5c69; } .card-dark .advaxe-card-info h4 { color: #5a5c69; } .advaxe-chart-container { background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.04); margin-bottom: 30px; } .advaxe-chart-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; border-bottom: 1px solid #eee; padding-bottom: 15px; } .advaxe-chart-header h3 { margin: 0; color: #4e73df; font-size: 16px; } .advaxe-lists-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; } .advaxe-list-box { background: #fff; padding: 20px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.04); display: flex; flex-direction: column; justify-content: space-between; } .advaxe-list-box h3 { margin-top: 0; color: #4e73df; font-size: 15px; border-bottom: 2px solid #f8f9fc; padding-bottom: 10px; margin-bottom: 15px; } .advaxe-list-item { display: flex; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid #f1f1f1; font-size: 13px; color: #5a5c69; } .advaxe-list-item:last-child { border-bottom: none; } .advaxe-badge { padding: 4px 8px; border-radius: 4px; font-size: 11px; font-weight: bold; color: #fff; } .badge-completed { background: #1cc88a; } .badge-processing { background: #36b9cc; } .badge-on-hold { background: #f6c23e; } .badge-cancelled, .badge-failed, .badge-refunded, .badge-low-stock { background: #e74a3b; } /* View More Button Styles */ .advaxe-view-more { display: block; width: 100%; padding: 10px; margin-top: 15px; background: #f8f9fc; border: 1px solid #eaecf4; color: #4e73df; text-align: center; border-radius: 6px; cursor: pointer; font-weight: bold; transition: all 0.3s ease; } .advaxe-view-more:hover { background: #4e73df; color: #fff; } .advaxe-view-more i { margin-left: 5px; transition: transform 0.3s; } .advaxe-view-more:hover i { transform: translateX(3px); } .advaxe-footer { text-align: center; margin-top: 25px; font-size: 12px; color: #858796; } .advaxe-footer a { color: #4e73df; text-decoration: none; font-weight: bold; } </style> <div class="advaxe-dashboard"> <!-- Statistics Cards --> <div class="advaxe-grid-cards"> <div class="advaxe-card card-primary"> <div class="advaxe-card-info"> <h4>Total Order Amount</h4> <h3><?php echo $total_sales; ?></h3> </div> <i class="fas fa-money-bill-wave advaxe-card-icon"></i> </div> <div class="advaxe-card card-info"> <div class="advaxe-card-info"> <h4>Total Orders</h4> <h3><?php echo esc_html( $total_orders ); ?></h3> </div> <i class="fas fa-shopping-cart advaxe-card-icon"></i> </div> <div class="advaxe-card card-success"> <div class="advaxe-card-info"> <h4>Completed Orders</h4> <h3><?php echo esc_html( $completed_orders ); ?></h3> </div> <i class="fas fa-check-circle advaxe-card-icon"></i> </div> <div class="advaxe-card card-warning"> <div class="advaxe-card-info"> <h4>On Hold Orders</h4> <h3><?php echo esc_html( $on_hold_orders ); ?></h3> </div> <i class="fas fa-pause-circle advaxe-card-icon"></i> </div> <div class="advaxe-card card-primary"> <div class="advaxe-card-info"> <h4>Processing Orders</h4> <h3><?php echo esc_html( $processing_orders ); ?></h3> </div> <i class="fas fa-spinner advaxe-card-icon"></i> </div> <div class="advaxe-card card-danger"> <div class="advaxe-card-info"> <h4>Cancelled & Refunded</h4> <h3><?php echo esc_html( $cancelled_orders + $refunded_orders ); ?></h3> </div> <i class="fas fa-times-circle advaxe-card-icon"></i> </div> <div class="advaxe-card card-dark"> <div class="advaxe-card-info"> <h4>COD / Online</h4> <h3><?php echo esc_html( $cod_orders ); ?> / <?php echo esc_html( $online_orders ); ?></h3> </div> <i class="fas fa-credit-card advaxe-card-icon"></i> </div> <div class="advaxe-card card-info"> <div class="advaxe-card-info"> <h4>Total Customers</h4> <h3><?php echo esc_html( $total_customers ); ?></h3> </div> <i class="fas fa-users advaxe-card-icon"></i> </div> </div> <!-- Sales Chart --> <div class="advaxe-chart-container"> <div class="advaxe-chart-header"> <h3><i class="fas fa-chart-line"></i> Sales Chart Overview</h3> <select id="advaxeChartFilter" style="padding: 5px; border-radius: 4px; border: 1px solid #ddd;"> <option value="7">Last 7 Days</option> <option value="30">Last 30 Days</option> <option value="365">Last 365 Days</option> </select> </div> <canvas id="advaxeSalesChart" height="80"></canvas> </div> <!-- Lists Section --> <div class="advaxe-lists-grid"> <!-- Recent Orders --> <div class="advaxe-list-box"> <div> <h3><i class="fas fa-shopping-bag"></i> Recent Orders</h3> <div id="advaxe-orders-list"> <?php echo advaxe_get_recent_orders_html(0); ?> </div> </div> <button class="advaxe-view-more" data-target="orders" data-offset="5">View More <i class="fas fa-arrow-right"></i></button> </div> <!-- Top Selling Products --> <div class="advaxe-list-box"> <div> <h3><i class="fas fa-star"></i> Top Selling Products</h3> <div id="advaxe-top_products-list"> <?php echo advaxe_get_top_products_html(0); ?> </div> </div> <button class="advaxe-view-more" data-target="top_products" data-offset="5">View More <i class="fas fa-arrow-right"></i></button> </div> <!-- Low Stock Products --> <div class="advaxe-list-box"> <div> <h3><i class="fas fa-exclamation-triangle"></i> Low Stock Products</h3> <div id="advaxe-low_stock-list"> <?php echo advaxe_get_low_stock_html(0); ?> </div> </div> <button class="advaxe-view-more" data-target="low_stock" data-offset="5">View More <i class="fas fa-arrow-right"></i></button> </div> </div> <div class="advaxe-footer"> Powered by <strong>Premium Dashboard Analytics</strong> | Created by <a href="https://advaxe.com" target="_blank">advaxe</a> </div> </div> <!-- Scripts --> <script> jQuery(document).ready(function($) { // Chart.js init if(typeof Chart !== 'undefined') { var ctx = document.getElementById('advaxeSalesChart').getContext('2d'); var gradient = ctx.createLinearGradient(0, 0, 0, 400); gradient.addColorStop(0, 'rgba(78, 115, 223, 0.5)'); gradient.addColorStop(1, 'rgba(78, 115, 223, 0.05)'); var advaxeChart = new Chart(ctx, { type: 'line', data: { labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], datasets: [{ label: 'Sales', data: [120, 190, 300, 250, 420, 380, 500], backgroundColor: gradient, borderColor: '#4e73df', pointBackgroundColor: '#fff', pointBorderColor: '#4e73df', borderWidth: 2, fill: true, tension: 0.4 }] }, options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { borderDash: [2, 4], color: '#f1f1f1' } }, x: { grid: { display: false } } } } }); $('#advaxeChartFilter').on('change', function() { var val = $(this).val(); if(val == '30') { advaxeChart.data.labels = ['Week 1', 'Week 2', 'Week 3', 'Week 4']; advaxeChart.data.datasets[0].data = [1200, 1500, 1100, 2000]; } else if(val == '365') { advaxeChart.data.labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; advaxeChart.data.datasets[0].data = [5000, 6000, 4500, 8000, 9000, 7500, 8500, 9500, 11000, 10500, 12000, 15000]; } else { advaxeChart.data.labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; advaxeChart.data.datasets[0].data = [120, 190, 300, 250, 420, 380, 500]; } advaxeChart.update(); }); } // AJAX Load More Logic $('.advaxe-view-more').on('click', function(e) { e.preventDefault(); var button = $(this); var target = button.data('target'); var offset = button.data('offset'); var container = $('#advaxe-' + target + '-list'); var originalHTML = button.html(); button.html('<i class="fas fa-spinner fa-spin"></i> Loading...'); button.prop('disabled', true); $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'advaxe_load_more_' + target, offset: offset }, success: function(response) { if (response.trim() === 'no_more' || response.trim() === '') { button.hide(); } else { container.append(response); button.data('offset', offset + 5); button.html(originalHTML); button.prop('disabled', false); } } }); }); }); </script> <?php } /** * HTML Generators for Lists */ function advaxe_get_recent_orders_html($offset = 0) { $html = ''; $orders = wc_get_orders( array( 'limit' => 5, 'offset' => $offset, 'orderby' => 'date', 'order' => 'DESC' ) ); if ( ! empty( $orders ) ) { foreach ( $orders as $order ) { $status = $order->get_status(); $html .= '<div class="advaxe-list-item">'; $html .= '<span><strong>#' . $order->get_id() . '</strong> - ' . $order->get_formatted_billing_full_name() . '</span>'; $html .= '<span class="advaxe-badge badge-' . esc_attr( $status ) . '">' . ucfirst( $status ) . '</span>'; $html .= '</div>'; } } else { $html = ( $offset == 0 ) ? '<p>No orders found.</p>' : 'no_more'; } return $html; } function advaxe_get_top_products_html($offset = 0) { $html = ''; $products = wc_get_products( array( 'limit' => 5, 'offset' => $offset, 'meta_key' => 'total_sales', 'orderby' => 'meta_value_num', 'order' => 'DESC' ) ); if ( ! empty( $products ) ) { foreach ( $products as $product ) { $sales = get_post_meta( $product->get_id(), 'total_sales', true ); if(!$sales) $sales = 0; $html .= '<div class="advaxe-list-item">'; $html .= '<span>' . $product->get_name() . '</span>'; $html .= '<span><strong>' . $sales . ' Sold</strong></span>'; $html .= '</div>'; } } else { $html = ( $offset == 0 ) ? '<p>No top products found.</p>' : 'no_more'; } return $html; } function advaxe_get_low_stock_html($offset = 0) { $html = ''; // Fetch items with stock <= 10 $products = wc_get_products( array( 'limit' => 5, 'offset' => $offset, 'meta_query' => array( array( 'key' => '_stock', 'value' => 10, 'compare' => '<=', 'type' => 'NUMERIC' ) ) ) ); if ( ! empty( $products ) ) { foreach ( $products as $product ) { $stock_qty = $product->get_stock_quantity(); $html .= '<div class="advaxe-list-item">'; $html .= '<span>' . $product->get_name() . '</span>'; $html .= '<span class="advaxe-badge badge-low-stock">' . $stock_qty . ' Left</span>'; $html .= '</div>'; } } else { $html = ( $offset == 0 ) ? '<p>No low stock products.</p>' : 'no_more'; } return $html; } /** * AJAX Handlers */ add_action( 'wp_ajax_advaxe_load_more_orders', 'advaxe_ajax_load_more_orders_callback' ); function advaxe_ajax_load_more_orders_callback() { $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0; echo advaxe_get_recent_orders_html($offset); wp_die(); } add_action( 'wp_ajax_advaxe_load_more_top_products', 'advaxe_ajax_load_more_top_products_callback' ); function advaxe_ajax_load_more_top_products_callback() { $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0; echo advaxe_get_top_products_html($offset); wp_die(); } add_action( 'wp_ajax_advaxe_load_more_low_stock', 'advaxe_ajax_load_more_low_stock_callback' ); function advaxe_ajax_load_more_low_stock_callback() { $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0; echo advaxe_get_low_stock_html($offset); wp_die(); }