prepare() placeholders. // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Caching is applied at the caller level for hot paths (admin dashboard widgets, frontend product listings); per-query wp_cache_get/set would add complexity for one-off admin queries. // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange -- Schema changes are intentional and run only during plugin activation via dbDelta() or controlled migrations. // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Only internal, plugin-owned table names are interpolated into queries (e.g. {$wpdb->prefix}boxcart_orders); user-supplied values always go through prepare() placeholders. // phpcs:disable WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $wpdb->prepare() is still valid with zero placeholders when we only need its auto-escaping of an array. // phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter -- Interpolated values are internal table-name constants, not user input. // Authorization gate: the WordPress admin menu already requires the // `manage_options` capability to load this view (see BoxCart_Admin_Menus), // but we double-check here so the view itself cannot be reached by an // unprivileged user even if it's ever included directly. if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to access this page.', 'boxcart' ) ); } // Get current data. global $wpdb; $orders_table = $wpdb->prefix . 'boxcart_orders'; $locations_table = $wpdb->prefix . 'boxcart_locations'; $slots_table = $wpdb->prefix . 'boxcart_slots'; // Get today's date. $today = current_time( 'Y-m-d' ); // Check if we have any orders at all. $total_orders = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$orders_table}" ); $has_orders = $total_orders > 0; // Get stat counts. $todays_orders = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$orders_table} WHERE slot_date = %s AND status != 'cancelled'", $today ) ); $pending_orders = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$orders_table} WHERE status = 'pending'" ); $ready_orders = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$orders_table} WHERE status = 'ready'" ); // Get recent orders (5 most recent). $recent_orders = $wpdb->get_results( "SELECT o.*, l.name as location_name FROM {$orders_table} o LEFT JOIN {$locations_table} l ON o.location_id = l.id ORDER BY o.created_at DESC LIMIT 5", ARRAY_A ); // Get active locations with today's slot data. $locations_data = BoxCart_Location::get_all_active(); $today_availability = array(); // Get day of week as integer (0=Sunday, 6=Saturday). $day_of_week = (int) gmdate( 'w', strtotime( $today ) ); foreach ( $locations_data as $location_row ) { $location = new BoxCart_Location( $location_row['id'] ); if ( ! $location->get_id() ) { continue; } $slots = $location->get_slots_for_day( $day_of_week ); if ( empty( $slots ) ) { continue; } $total_capacity = 0; $total_booked = 0; foreach ( $slots as $slot ) { $capacity = $location->get_slot_capacity( $slot['id'], $today ); $booked = BoxCart_Order::count_orders_for_slot( $location->get_id(), $today, $slot['time_start'], $slot['time_end'] ); $total_capacity += $capacity; $total_booked += $booked; } $today_availability[] = array( 'location' => $location, 'capacity' => $total_capacity, 'booked' => $total_booked, 'slots' => count( $slots ), ); } // Get product and location counts for empty state. $products_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'boxcart_product' AND post_status = 'publish'" ); $locations_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$locations_table} WHERE is_active = 1" ); // Status badge classes. $status_classes = array( 'pending' => 'boxcart-badge--warning', 'processing' => 'boxcart-badge--info', 'ready' => 'boxcart-badge--success', 'completed' => 'boxcart-badge--neutral', 'cancelled' => 'boxcart-badge--danger', ); ?>

v

$bc_setup_status['has_product'], 'title' => __( 'Add Your Products', 'boxcart' ), 'desc' => BoxCart_Helpers::prices_enabled() ? __( 'Create your product catalogue with prices and images.', 'boxcart' ) : __( 'Create your product catalogue with images.', 'boxcart' ), ), array( 'done' => $bc_setup_status['has_location'], 'title' => __( 'Set Up Collection', 'boxcart' ), 'desc' => __( 'Add your pickup location, opening hours, and time slots.', 'boxcart' ), ), array( 'done' => $bc_setup_status['pages_done'], 'title' => __( 'Create Your Storefront Pages', 'boxcart' ), 'desc' => __( 'Use Guided Setup to create the Shop, Basket, Checkout, and My Account pages in one click, or add the shortcodes to your own pages.', 'boxcart' ), ), array( 'done' => $bc_setup_status['pages_done'], 'title' => __( 'Configure Settings', 'boxcart' ), 'desc' => __( 'Assign your pages, set up emails, and customise your store under Settings.', 'boxcart' ), ), array( 'done' => $has_orders, 'title' => __( 'Start Taking Orders', 'boxcart' ), 'desc' => __( 'Customers can browse, add to basket, and place orders.', 'boxcart' ), ), ); $bc_step_num = 0; foreach ( $bc_steps as $bc_step ) : $bc_step_num++; ?>

—

0 ? min( 100, ( $booked / $capacity ) * 100 ) : 0; // Determine progress bar colour. $progress_class = 'boxcart-progress--success'; if ( $percentage >= 90 ) { $progress_class = 'boxcart-progress--danger'; } elseif ( $percentage >= 70 ) { $progress_class = 'boxcart-progress--warning'; } ?>
get_name() ); ?>