Tạo shortcode – Mobile nhận đơn

Eric (kedochanh)
0
08/10/26
08/10/2026

1Nhận đơn – Bộ lọc – Số lượng đơn

Thông tin
1. Nhân đơn (đã loại bỏ shortcode)
2. Bộ lọc đơn + số lượng đơn
3. Không hiển thị đơn hoàn tất + hủy trong bộ lọc TẤT CẢ
4. Chỉ hiển thị đơn trong ngày cho HOÀN TẤT + HỦY
// 1. Hàm hiển thị cấu trúc HTML trực tiếp (Chỉ hoạt động trên Mobile & Tablet)
function bks_render_order_tracker_html($status_requested = 'any') {
    if ( ! wp_is_mobile() ) {
        echo '<!-- Tính năng này chỉ khả dụng trên thiết bị di động -->';
        return;
    }

    wp_enqueue_script('bks-ajax-tracker');

    // CSS Khóa cố định bộ lọc (Sticky) và tiêu đề bảng ổn định, không hiệu ứng nhấp nháy
    $html = '<style>
        .bks-tracker-wrapper { position: relative; font-family: sans-serif; }
        .bks-status-filter-wrapper { 
            position: -webkit-sticky; 
            position: sticky; 
            top: 0; 
            z-index: 100; 
            background: #ffffff; 
            padding: 10px 0; 
            margin-bottom: 5px; 
            overflow-x: auto; 
            white-space: nowrap; 
            -webkit-overflow-scrolling: touch;
            box-shadow: 0 4px 6px -6px rgba(0,0,0,0.1);
        }
        .bks-filter-btn {
            padding: 6px 14px; 
            margin-right: 8px; 
            border: 1px solid #eee; 
            background: #f8f9fa; 
            border-radius: 16px; 
            font-size: 13px; 
            color: #666; 
            cursor: pointer;
            transition: all 0.2s ease;
        }
        .bks-filter-btn.active {
            background: #fff !important; 
            color: #333 !important; 
            border-color: #ccc !important;
            font-weight: bold;
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }
        .bks-table-container { 
            overflow-x: auto; 
            -webkit-overflow-scrolling: touch;
        }
       
    </style>';

    $html .= '<div class="bks-tracker-wrapper">';
    $html .= '<div class="bks-status-filter-wrapper" id="bks-status-filter-container" data-default-status="' . esc_attr($status_requested) . '">';
    $html .= '<button class="bks-filter-btn active" data-filter="' . esc_attr($status_requested) . '">Tất cả</button>';
    $html .= '</div>';

    $html .= '<div id="bks-order-list-container" data-status="' . esc_attr($status_requested) . '">Đang tải đơn hàng...</div>';
    $html .= '</div>';

    echo $html;
}

// 2. Đăng ký Script AJAX cập nhật liên tục thông minh và xử lý sự kiện bấm Tab lọc
function bks_register_tracker_scripts() {
    if ( ! wp_is_mobile() ) {
        return;
    }

    wp_register_script('bks-ajax-tracker', '', [], '', true);

    $js_code = "
        jQuery(document).ready(function($) {
            var container = $('#bks-order-list-container');
            var filterContainer = $('#bks-status-filter-container');
            if (!container.length) return;

            var currentActiveStatus = container.data('status');
            var timer = null;
            var isAjaxRunning = false;

            function fetch_orders_continuous() {
                if (document.hidden) {
                    scheduleNextFetch(5000); 
                    return;
                }

                if (isAjaxRunning) return; 
                isAjaxRunning = true;

                $.ajax({
                    url: '" . admin_url('admin-ajax.php') . "',
                    type: 'POST',
                    data: {
                        action: 'bks_get_live_orders',
                        status: currentActiveStatus,
                        default_status: filterContainer.data('default-status')
                    },
                    success: function(response) {
                        if(response.success) {
                            container.html(response.data.table_html);
                            
                            var currentScrollLeft = filterContainer.scrollLeft();
                            filterContainer.html(response.data.filter_html);
                            filterContainer.scrollLeft(currentScrollLeft);
                        }
                    },
                    complete: function() {
                        isAjaxRunning = false;
                        scheduleNextFetch(10000); 
                    }
                });
            }

            function scheduleNextFetch(delay) {
                clearTimeout(timer);
                timer = setTimeout(fetch_orders_continuous, delay);
            }

            fetch_orders_continuous();

            $(document).on('click', '.bks-filter-btn', function() {
                currentActiveStatus = $(this).data('filter');
                container.html('<div style=\"padding:30px; text-align:center; color:#888;\">Đang tải đơn hàng...</div>');
                fetch_orders_continuous();
            });

            document.addEventListener('visibilitychange', function() {
                if (!document.hidden) {
                    fetch_orders_continuous();
                }
            });
        });
    ";
    
    wp_add_inline_script('bks-ajax-tracker', $js_code);
}
add_action('wp_enqueue_scripts', 'bks_register_tracker_scripts');

// 3. Xử lý dữ liệu trả về: Loại bỏ đơn huỷ/hoàn thành khỏi tab "Tất cả"
function bks_handle_live_orders_ajax() {
    if ( ! class_exists( 'WooCommerce' ) ) {
        wp_send_json_error('WooCommerce chưa được kích hoạt.');
    }

    global $wpdb;

    $status_requested = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : 'any';
    $default_status   = isset($_POST['default_status']) ? sanitize_text_field($_POST['default_status']) : 'any';
    
    $today_start = date('Y-m-d 00:00:00');

    // Kiểm tra cấu hình HPOS
    $is_hpos = function_exists( 'wc_get_container' ) && wc_get_container()->get( \Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled();
    
    if ( $is_hpos ) {
        $table_name = $wpdb->prefix . 'wc_orders';
        $status_col = 'status';
        $date_col   = 'date_updated_gmt';
        $where_type = "WHERE type = 'shop_order'";
    } else {
        $table_name = $wpdb->posts;
        $status_col = 'post_status';
        $date_col   = 'post_modified_gmt';
        $where_type = "WHERE post_type = 'shop_order'";
    }

    // Đếm số lượng đơn hàng nhóm theo trạng thái
    $raw_counts = $wpdb->get_results("SELECT $status_col AS status, COUNT(*) AS count FROM $table_name $where_type GROUP BY $status_col", ARRAY_A);
    
    $counts = array();
    foreach ( $raw_counts as $row ) {
        $clean_status = str_replace('wc-', '', $row['status']);
        $counts[$clean_status] = (int) $row['count'];
    }

    // Đếm riêng lượng đơn huỷ và hoàn thành trong ngày
    $today_gmt = gmdate('Y-m-d 00:00:00');
    $counts['cancelled'] = (int) $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table_name $where_type AND $status_col = %s AND $date_col >= %s", $is_hpos ? 'cancelled' : 'wc-cancelled', $today_gmt));
    $counts['completed'] = (int) $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table_name $where_type AND $status_col = %s AND $date_col >= %s", $is_hpos ? 'completed' : 'wc-completed', $today_gmt));

    // Đếm tổng số đơn hiển thị ở tab "Tất cả" (Loại trừ completed và cancelled để khớp logic ẩn đơn)
    $total_visible = 0;
    $all_statuses_list = wc_get_order_statuses();
    foreach ( $all_statuses_list as $key => $name ) {
        $slug = str_replace('wc-', '', $key);
        if ( $slug !== 'completed' && $slug !== 'cancelled' && isset($counts[$slug]) ) {
            $total_visible += $counts[$slug];
        }
    }

    // Render HTML cho thanh Tabs bộ lọc kèm số lượng chuẩn
    $filter_active_class = ($status_requested === $default_status) ? ' active' : '';
    $filter_html = '<button class="bks-filter-btn' . $filter_active_class . '" data-filter="' . esc_attr($default_status) . '">Tất cả (' . $total_visible . ')</button>';
    
    foreach ( $all_statuses_list as $key => $name ) {
        $status_slug = str_replace('wc-', '', $key);
        if ( $default_status !== 'any' && strpos($default_status, $status_slug) === false ) {
            continue;
        }
        
        $count_badge = isset($counts[$status_slug]) ? $counts[$status_slug] : 0;
        $active_class = ($status_requested === $status_slug) ? ' active' : '';

        if ( $status_slug === 'cancelled' || $status_slug === 'completed' ) {
            $display_name = esc_html($name) . ' (Trong ngày) (' . $count_badge . ')';
        } else {
            $display_name = esc_html($name) . ' (' . $count_badge . ')';
        }
        
        $filter_html .= '<button class="bks-filter-btn' . $active_class . '" data-filter="' . esc_attr($status_slug) . '">' . $display_name . '</button>';
    }

    // Thiết lập điều kiện truy vấn database cho bảng dữ liệu
    $args = array(
        'limit'    => 30, 
        'orderby'  => 'date_modified', 
        'order'    => 'DESC',
    );

    if ( $status_requested === 'any' ) {
        // TỐI ƯU: Nếu chọn tab "Tất cả", lấy tất cả trạng thái nhưng LOẠI TRỪ hẳn completed và cancelled khỏi câu lệnh SQL
        $all_slugs = array_map(function($status) { return str_replace('wc-', '', $status); }, array_keys($all_statuses_list));
        $args['status'] = array_diff($all_slugs, array('completed', 'cancelled'));
    } elseif ( $status_requested === 'cancelled' ) {
        $args['status'] = 'cancelled';
        $args['date_modified'] = '>=' . $today_start;
    } elseif ( $status_requested === 'completed' ) {
        $args['status'] = 'completed';
        $args['date_modified'] = '>=' . $today_start;
    } else {
        $args['status'] = $status_requested;
    }
    
    $query = new WC_Order_Query($args);
    $orders = $query->get_orders();

     $status_colors = array(
		'pending'   => array('bg' => '#e6f0fa', 'text' => '#005a9c'), // Xanh dương
        'on-hold' => array('bg' => '#fbeaeA', 'text' => '#a80000'), // Đỏ
        'processing'  => array('bg' => '#f3f2f1', 'text' => '#605e5c'), // Xám
		'transfer'    => array('bg' => '#f3f2f1', 'text' => '#0073aa'), // Xanh dương
        'cook'      => array('bg' => '#fffae6', 'text' => '#b38600'), // Vàng nhạt
		'cook-done' => array('bg' => '#fff0e6', 'text' => '#d96a00'), // Cam
        'shipper'   => array('bg' => '#ed4700', 'text' => '#fff0e6'), // Cam đậm
        'cancelled'    => array('bg' => '#fde7e9', 'text' => '#a80000'), // Đỏ đậm
		'completed'   => array('bg' => '#e6f9ed', 'text' => '#107c41'), // Xanh lá
		
);
	
	 // Giao diện bảng
    $table_html = '<div style="overflow-x:auto;">';
    $table_html .= '<table style="width: 95%;border-collapse: collapse;margin-left: 10px;">';
    $table_html .= '<tr style="background:#f8f9fa; text-align:left; border-bottom: 2px solid #eaeaea;">';
    $table_html .= '<th style="padding:12px 10px;">Đơn</th>';
    $table_html .= '<th style="padding:12px 10px;">Giờ</th>'; 
    $table_html .= '<th style="padding:12px 10px;">T.Tin</th>'; 
    $table_html .= '<th style="padding:12px 10px; text-align:center;width:25%;">T.Thái</th>';
    $table_html .= '</tr>';

if ( ! empty( $orders ) ) {
    foreach ( $orders as $order ) {
        $current_status = $order->get_status();
        $order_id       = $order->get_id();
        $order_key      = $order->get_order_key();
        $date_modified  = $order->get_date_modified();
        $time_updated   = $date_modified ? $date_modified->date('H:i - d/m') : '---';
        $created  = $order->get_date_created() ? $order->get_date_created()->date_i18n('d/m/Y H:i') : '';
        $order_admin_url = admin_url( 'post.php?post=' . $order_id . '&action=edit' );
        if ( $is_hpos ) {
            $order_admin_url = admin_url( 'admin.php?page=wc-orders&action=edit&id=' . $order_id );
        }
        
        $button = '';
        if ( $order->has_status( array( 'cook' ) ) ) {
            $pdf_url = get_site_url( null, 'wcpdf/packing-slip/' . $order_id . '/' . $order_key . '/pdf', 'http' );
            $button  = '<br><a target="_blank" href="' . esc_url( $pdf_url ) . '" class="prs" style="display:inline-block; margin-top:5px; padding:2px 6px; background:#0073aa; color:#fff; font-size:11px; border-radius:3px; text-decoration:none;">📄 Phiếu chế biến</a>';
        }
        
        $colors = isset($status_colors[$current_status]) ? $status_colors[$current_status] : array('bg' => '#f3f2f1', 'text' => '#605e5c');
        
        // Cấu trúc hàng dữ liệu chuẩn chỉnh trên di động
		 $table_html .= '<tr>';
           $table_html .= '<td style="padding:12px 10px; font-weight:bold; color:#333;">#' . $order_id . '</td>';
           $table_html .= '<td style="padding:12px 10px; color:#666; font-size:13px;">' . esc_html( $time_updated ) . '</td>';
          $table_html .= '<td style="padding:12px 10px;">';
        $table_html .= '<a href="https://95deli.fship.vn/dashboard/details?order_id='.$order_id.'" style="color:#0073aa; text-decoration:none; font-weight:500;" target="_blank"><i class="fa-solid fa-circle-info lin"></i></a>';           
           /* $html .= $button; */
         $table_html .= '</td>';
        $table_html .= '<td style="padding:12px 10px; text-align:center;">';
        $table_html .= '<span style="display: inline-block;padding:5px 10px; border-radius:20px;font-weight:600; background-color:' . $colors['bg'] . '; color:' . $colors['text'] . ';width:-webkit-fill-available;white-space: nowrap;">';
          $table_html .= wc_get_order_status_name( $current_status );
         $table_html .= '</span>';
         $table_html .= '</td>';
		$table_html .= '<tr style="border-bottom: 4px solid #ddd;"><td colspan="4"><div class="flex justify-between items-end">'.$created.''.$button.'<div style="text-align:right;">Cập nhật '.$time_updated.'</div></div></td</tr>';
            $table_html .= '</tr>';  
    }
} else {
    // SỬA LỖI: Bọc chuỗi thông báo trống vào đúng cấu trúc tr -> td để không làm lệch bảng
    $table_html .= '<tr style="background: #fff;"><td colspan="4" style="padding: 30px; text-align:center; color:#888;">Không tìm thấy đơn hàng khả dụng nào ở trạng thái này.</td></tr>';
}

$table_html .= '</table>';
$table_html .= '</div>';

wp_send_json_success(array(
    'table_html'  => $table_html,
    'filter_html' => $filter_html
));
}
add_action('wp_ajax_bks_get_live_orders', 'bks_handle_live_orders_ajax');
add_action('wp_ajax_nopriv_bks_get_live_orders', 'bks_handle_live_orders_ajax');

2Nhận đơn – Bộ lọc cao cấp

Thông tin
1. Nhân đơn (Loại bỏ shortcode)
2. Bộ lọc đơn (Chỉ hiển thị đơn trong ngày cho HOÀN TẤT + HỦY)
// 1. Hàm hiển thị cấu trúc HTML trực tiếp thay cho Shortcode (Chỉ hoạt động trên Mobile & Tablet)
function bks_render_order_tracker_html($status_requested = 'any') {
    // Nếu KHÔNG PHẢI mobile/tablet thì chặn hiển thị để nhẹ server
    if ( ! wp_is_mobile() ) {
        echo '<!-- Tính năng này chỉ khả dụng trên thiết bị di động -->';
        return;
    }

    // Tự động kích hoạt gọi script AJAX cho trang có chèn hàm này
    wp_enqueue_script('bks-ajax-tracker');

    $all_statuses = wc_get_order_statuses();
    
    // Giao diện Thanh bộ lọc trạng thái bằng Tab kiểu di động
    $html = '<div class="bks-status-filter-wrapper">';
    $html .= '<button class="bks-filter-btn active" data-filter="' . esc_attr($status_requested) . '">Tất cả</button>';
    
   foreach ( $all_statuses as $key => $name ) {
        $status_slug = str_replace('wc-', '', $key);
        if ( $status_requested !== 'any' && strpos($status_requested, $status_slug) === false ) {
            continue;
        }
        
        // Thêm hậu tố trực quan cho các tab đặc biệt chỉ hiển thị trong ngày
        if ( $status_slug === 'cancelled' ) {
            $display_name = esc_html($name) . '';
        } elseif ( $status_slug === 'completed' ) {
            $display_name = esc_html($name) . '';
        } else {
            $display_name = esc_html($name);
        }
        
        $html .= '<button class="bks-filter-btn" data-filter="' . esc_attr($status_slug) . '">' . $display_name . '</button>';
    }
    $html .= '</div>';

    // Thẻ div chứa danh sách đơn hàng được cập nhật qua AJAX Pull
    $html .= '<div id="bks-order-list-container" data-status="' . esc_attr($status_requested) . '">Đang tải đơn hàng...</div>';

    echo $html;
}

// 2. Đăng ký Script AJAX cập nhật liên tục thông minh và xử lý sự kiện bấm Tab lọc
function bks_register_tracker_scripts() {
    if ( ! wp_is_mobile() ) {
        return;
    }

    wp_register_script('bks-ajax-tracker', '', [], '', true);

    $js_code = "
        jQuery(document).ready(function($) {
            var container = $('#bks-order-list-container');
            if (!container.length) return;

            var currentActiveStatus = container.data('status');
            var timer = null;
            var isAjaxRunning = false;

            function fetch_orders_continuous() {
                if (document.hidden) {
                    scheduleNextFetch(5000); 
                    return;
                }

                if (isAjaxRunning) return; 
                isAjaxRunning = true;

                $.ajax({
                    url: '" . admin_url('admin-ajax.php') . "',
                    type: 'POST',
                    data: {
                        action: 'bks_get_live_orders',
                        status: currentActiveStatus
                    },
                    success: function(response) {
                        if(response.success) {
                            container.html(response.data);
                        }
                    },
                    complete: function() {
                        isAjaxRunning = false;
                        scheduleNextFetch(100000); 
                    }
                });
            }

            function scheduleNextFetch(delay) {
                clearTimeout(timer);
                timer = setTimeout(fetch_orders_continuous, delay);
            }

            fetch_orders_continuous();

            $(document).on('click', '.bks-filter-btn', function() {
                $('.bks-filter-btn').removeClass('active').css({'background': '#f8f9fa', 'color': '#666', 'border-color': '#eee'});
                $(this).addClass('active').css({'background': '#fff', 'color': '#333', 'border-color': '#ccc'});
                
                currentActiveStatus = $(this).data('filter');
                
                container.html('Đang tải đơn hàng...');
                fetch_orders_continuous();
            });

            document.addEventListener('visibilitychange', function() {
                if (!document.hidden) {
                    fetch_orders_continuous();
                }
            });
        });
    ";
    
    wp_add_inline_script('bks-ajax-tracker', $js_code);
}
add_action('wp_enqueue_scripts', 'bks_register_tracker_scripts');

// 3. Xử lý dữ liệu trả về từ Database dựa theo Tab trạng thái chọn + Lọc đơn huỷ trong ngày
function bks_handle_live_orders_ajax() {
  
    $status_requested = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : 'any';
    
    if ( $status_requested !== 'any' && strpos($status_requested, ',') !== false ) {
        $status_filter = array_map('trim', explode(',', $status_requested));
    } else {
        $status_filter = $status_requested;
    }

    $args = array(
        'limit'    => 20, 
        'orderby'  => 'date_modified', 
        'order'    => 'DESC',
    );

    $today_start = date('Y-m-d 00:00:00'); // Mốc thời gian 0h00 đầu ngày hôm nay

    // Xử lý bộ lọc SQL tối ưu khi nhân viên bấm đích danh từng Tab lẻ
    if ( $status_filter === 'cancelled' ) {
        $args['status'] = 'cancelled';
        $args['date_modified'] = '>=' . $today_start;
    } elseif ( $status_filter === 'completed' ) {
        $args['status'] = 'completed';
        $args['date_modified'] = '>=' . $today_start;
    } else {
        $args['status'] = $status_filter;
    }
    
    $query = new WC_Order_Query($args);
    $orders = $query->get_orders();

  // Bảng định nghĩa màu sắc đầy đủ cho mọi trạng thái (Đã thêm lại Completed)
    $status_colors = array(
		'pending'   => array('bg' => '#e6f0fa', 'text' => '#005a9c'), // Xanh dương
        'on-hold' => array('bg' => '#fbeaeA', 'text' => '#a80000'), // Đỏ
        'processing'  => array('bg' => '#f3f2f1', 'text' => '#605e5c'), // Xám
		'transfer'    => array('bg' => '#f3f2f1', 'text' => '#0073aa'), // Xanh dương
        'cook'      => array('bg' => '#fffae6', 'text' => '#b38600'), // Vàng nhạt
		'cook-done' => array('bg' => '#fff0e6', 'text' => '#d96a00'), // Cam
        'shipper'   => array('bg' => '#ed4700', 'text' => '#fff0e6'), // Cam đậm
        'cancelled'    => array('bg' => '#fde7e9', 'text' => '#a80000'), // Đỏ đậm
		'completed'   => array('bg' => '#e6f9ed', 'text' => '#107c41'), // Xanh lá
		
    );

    // Giao diện bảng
    $html = '<div style="overflow-x:auto;">';
    $html .= '<table style="width: 95%;border-collapse: collapse;margin-left: 10px;">';
    $html .= '<tr style="background:#f8f9fa; text-align:left; border-bottom: 2px solid #eaeaea;">';
    $html .= '<th style="padding:12px 10px;">Đơn</th>';
    $html .= '<th style="padding:12px 10px;">Giờ</th>'; 
    $html .= '<th style="padding:12px 10px;">T.Tin</th>'; 
    $html .= '<th style="padding:12px 10px; text-align:center;width:25%;">T.Thái</th>';
    $html .= '</tr>';
    $has_visible_order = false;

    if ( ! empty( $orders ) ) {
        foreach ( $orders as $order ) {
            $current_status = $order->get_status();

            // KIỂM TRA CHO TAB "TẤT CẢ" (status=any): Loại bỏ đơn hủy và đơn hoàn thành của ngày hôm trước
            if ( $status_filter === 'any' ) {
                if ( $current_status === 'cancelled' || $current_status === 'completed' ) {
                    $date_modified_timestamp = $order->get_date_modified() ? $order->get_date_modified()->getTimestamp() : 0;
                    if ( $date_modified_timestamp < $today_timestamp ) {
                        continue; // Bỏ qua, không in hàng này ra bảng
                    }
                }
            }

            $has_visible_order = true; 
         $order_id       = $order->get_id();
            $order_key      = $order->get_order_key();
            
			$created  = $order->get_date_created() ? $order->get_date_created()->date_i18n('d/m/Y H:i') : '';
            $date_modified  = $order->get_date_modified();
            $time_updated   = $date_modified ? $date_modified->date('H:i') : '---';
			$button = '';

            if ( $order->has_status( array( 'cook' ) ) ) {
                $pdf_url = get_site_url( null, 'wcpdf/packing-slip/' . $order_id . '/' . $order_key . '/pdf', 'http' );
                $button  = '<br><a target="_blank" href="' . esc_url( $pdf_url ) . '" class="prs" style="display:inline-block; margin-top:5px; padding:2px 6px; background:#0073aa; color:#fff; font-size:11px; border-radius:3px; text-decoration:none;">📄 Phiếu chế biến</a>';
            }

            $colors = isset($status_colors[$current_status]) ? $status_colors[$current_status] : array('bg' => '#f3f2f1', 'text' => '#605e5c');

            $html .= '<tr>';
            $html .= '<td style="padding:12px 10px; font-weight:bold; color:#333;">#' . $order_id . '</td>';
            $html .= '<td style="padding:12px 10px; color:#666; font-size:13px;">' . esc_html( $time_updated ) . '</td>';
            $html .= '<td style="padding:12px 10px;">';
            $html .= '<a href="https://95deli.fship.vn/dashboard/details?order_id='.$order_id.'" style="color:#0073aa; text-decoration:none; font-weight:500;" target="_blank"><i class="fa-solid fa-circle-info lin"></i></a>';           
            /*$html .= $button; */
         /*   $html .= '</td>';
            $html .= '<td style="padding:12px 10px; text-align:center;">';
            $html .= '<span style="display: inline-block;padding:5px 10px; border-radius:20px;font-weight:600; background-color:' . $colors['bg'] . '; color:' . $colors['text'] . ';width:-webkit-fill-available;white-space: nowrap;">';
            $html .= wc_get_order_status_name( $current_status );
            $html .= '</span>';
            $html .= '</td>';
			$html .= '<tr style="border-bottom: 4px solid #ddd;"><td colspan="4"><div class="flex justify-between items-end">'.$created.''.$button.'<div style="text-align:right;">Cập nhật '.$time_updated.'</div></div></td</tr>';
            $html .= '</tr>';
        }
    } else {
        $html .= '<tr><td colspan="4" style="padding: 30px; text-align:center; color:#888;">Không có đơn hàng nào ở trạng thái này.</td></tr>';
    }
    $html .= '</table>';
    $html .= '</div>';

    wp_send_json_success($html);
}
add_action('wp_ajax_bks_get_live_orders', 'bks_handle_live_orders_ajax');
add_action('wp_ajax_nopriv_bks_get_live_orders', 'bks_handle_live_orders_ajax'); 

3Nhận đơn + Bộ lọc

Thông tin
1. Nhân đơn
2. Bộ lọc đơn
3. Có shortcode [cap_nhat_don_hang]
// 1. Tạo Shortcode hỗ trợ bộ lọc trạng thái (Chỉ hoạt động trên Mobile & Tablet)
function bks_order_tracker_shortcode($atts) {
    if ( ! wp_is_mobile() ) {
        return '<!-- Tính năng này chỉ khả dụng trên thiết bị di động -->';
    }

    $atts = shortcode_atts(array(
        'status' => 'any', 
    ), $atts, 'cap_nhat_don_hang');

    wp_enqueue_script('bks-ajax-tracker');

    // Lấy danh sách tất cả các trạng thái có trong hệ thống để tạo thanh bộ lọc
    $all_statuses = wc_get_order_statuses();
    
    // Giao diện Thanh bộ lọc trạng thái bằng Tab kiểu di động
    $html = '<div class="bks-status-filter-wrapper" style="margin-bottom: 15px; overflow-x: auto; white-space: nowrap; padding-bottom: 8px; -webkit-overflow-scrolling: touch;">';
    $html .= '<button class="bks-filter-btn active" data-filter="' . esc_attr($atts['status']) . '" style="padding: 6px 14px; margin-right: 8px; border: 1px solid #ccc; background: #fff; border-radius: 16px; font-size: 13px; font-weight: bold; color: #333; cursor: pointer;">Tất cả</button>';
    
    foreach ( $all_statuses as $key => $name ) {
        $status_slug = str_replace('wc-', '', $key);
        // Nếu shortcode chỉ định 1 nhóm trạng thái cụ thể, chỉ hiển thị các tab thuộc nhóm đó
        if ( $atts['status'] !== 'any' && strpos($atts['status'], $status_slug) === false ) {
            continue;
        }
        $html .= '<button class="bks-filter-btn" data-filter="' . esc_attr($status_slug) . '" style="padding: 6px 14px; margin-right: 8px; border: 1px solid #eee; background: #f8f9fa; border-radius: 16px; font-size: 13px; color: #666; cursor: pointer;">' . esc_html($name) . '</button>';
    }
    $html .= '</div>';

    // Bảng chứa dữ liệu đơn hàng
    $html .= '<div id="bks-order-list-container" data-status="' . esc_attr($atts['status']) . '">Đang tải đơn hàng...</div>';

    return $html;
}
add_shortcode('cap_nhat_don_hang', 'bks_order_tracker_shortcode');

// 2. Đăng ký Script AJAX cập nhật liên tục thông minh và xử lý sự kiện bấm Tab lọc
function bks_register_tracker_scripts() {
    if ( ! wp_is_mobile() ) {
        return;
    }

    wp_register_script('bks-ajax-tracker', '', [], '', true);

    $js_code = "
        jQuery(document).ready(function($) {
            var container = $('#bks-order-list-container');
            if (!container.length) return;

            // Mặc định lấy trạng thái từ shortcode cấu hình ban đầu
            var currentActiveStatus = container.data('status');
            var timer = null;
            var isAjaxRunning = false;

            function fetch_orders_continuous() {
                if (document.hidden) {
                    scheduleNextFetch(5000); 
                    return;
                }

                if (isAjaxRunning) return; 
                isAjaxRunning = true;

                $.ajax({
                    url: '" . admin_url('admin-ajax.php') . "',
                    type: 'POST',
                    data: {
                        action: 'bks_get_live_orders',
                        status: currentActiveStatus
                    },
                    success: function(response) {
                        if(response.success) {
                            container.html(response.data);
                        }
                    },
                    complete: function() {
                        isAjaxRunning = false;
                        scheduleNextFetch(100000); // Tự động cập nhật lại sau 10 giây
                    }
                });
            }

            function scheduleNextFetch(delay) {
                clearTimeout(timer);
                timer = setTimeout(fetch_orders_continuous, delay);
            }

            // Kích hoạt chạy lần đầu tiên
            fetch_orders_continuous();

            // Xử lý sự kiện khi người dùng bấm vào các Tab bộ lọc trạng thái
            $(document).on('click', '.bks-filter-btn', function() {
                $('.bks-filter-btn').removeClass('active').css({'background': '#f8f9fa', 'color': '#666', 'border-color': '#eee'});
                $(this).addClass('active').css({'background': '#fff', 'color': '#333', 'border-color': '#ccc'});
                
                // Thay đổi trạng thái cần lọc hiện tại
                currentActiveStatus = $(this).data('filter');
                
                // Đưa bảng về trạng thái chờ tải và gọi AJAX ngay lập tức
                container.html('Đang tải đơn hàng...');
                fetch_orders_continuous();
            });

            // Tự động chạy lại khi bật điện thoại lên / quay lại tab trình duyệt
            document.addEventListener('visibilitychange', function() {
                if (!document.hidden) {
                    fetch_orders_continuous();
                }
            });
        });
    ";
    
    wp_add_inline_script('bks-ajax-tracker', $js_code);
}
add_action('wp_enqueue_scripts', 'bks_register_tracker_scripts');

// 3. Xử lý dữ liệu trả về từ Database dựa theo Tab trạng thái đang được chọn
function bks_handle_live_orders_ajax() {
   
    $status_requested = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : 'any';
    
    if ( $status_requested !== 'any' && strpos($status_requested, ',') !== false ) {
        $status_filter = array_map('trim', explode(',', $status_requested));
    } else {
        $status_filter = $status_requested;
    }

    $args = array(
        'limit'    => 20, 
        'orderby'  => 'date_modified', 
        'order'    => 'DESC',
        'status'   => $status_filter,
    );
    
    $query = new WC_Order_Query($args);
    $orders = $query->get_orders();

    // Bảng định nghĩa màu sắc đầy đủ cho mọi trạng thái (Đã thêm lại Completed)
    $status_colors = array(
        'cook'      => array('bg' => '#fffae6', 'text' => '#b38600'), // Vàng nhạt
        'shipper'   => array('bg' => '#e6f9ed', 'text' => '#107c41'), // Xanh lá
        'cook-done' => array('bg' => '#fff0e6', 'text' => '#d96a00'), // Cam
        'pending'   => array('bg' => '#e6f0fa', 'text' => '#005a9c'), // Xanh dương
        'on-hold' => array('bg' => '#fbeaeA', 'text' => '#a80000'), // Đỏ
        'processing'  => array('bg' => '#f3f2f1', 'text' => '#605e5c'), // Xám
        'failed'    => array('bg' => '#fde7e9', 'text' => '#a80000'), // Đỏ đậm
    );

    // Giao diện bảng
    $html = '<div style="overflow-x:auto;">';
    $html .= '<table style="width:100%; border-collapse: collapse; font-family: sans-serif; font-size: 14px; box-shadow: 0 2px 5px rgba(0,0,0,0.05);">';
    $html .= '<tr style="background:#f8f9fa; text-align:left; border-bottom: 2px solid #eaeaea;">';
    $html .= '<th style="padding:12px 10px;">Đơn</th>';
    $html .= '<th style="padding:12px 10px;">Giờ</th>'; 
    $html .= '<th style="padding:12px 10px;">T.Tin</th>'; 
    $html .= '<th style="padding:12px 10px; text-align:center;width:25%;">T.Thái</th>';
    $html .= '</tr>';

    if ( ! empty( $orders ) ) {
        foreach ( $orders as $order ) {
            $current_status = $order->get_status();
            $order_id       = $order->get_id();
            $order_key      = $order->get_order_key();
            
			$created  = $order->get_date_created() ? $order->get_date_created()->date_i18n('d/m/Y H:i') : '';
            $date_modified  = $order->get_date_modified();
            $time_updated   = $date_modified ? $date_modified->date('H:i') : '---';

            if ( $order->has_status( array( 'cook' ) ) ) {
                $pdf_url = get_site_url( null, 'wcpdf/packing-slip/' . $order_id . '/' . $order_key . '/pdf', 'http' );
                $button  = '<br><a target="_blank" href="' . esc_url( $pdf_url ) . '" class="prs" style="display:inline-block; margin-top:5px; padding:2px 6px; background:#0073aa; color:#fff; font-size:11px; border-radius:3px; text-decoration:none;">📄 Phiếu chế biến</a>';
            }

            $colors = isset($status_colors[$current_status]) ? $status_colors[$current_status] : array('bg' => '#f3f2f1', 'text' => '#605e5c');

            $html .= '<tr>';
            $html .= '<td style="padding:12px 10px; font-weight:bold; color:#333;">#' . $order_id . '</td>';
            $html .= '<td style="padding:12px 10px; color:#666; font-size:13px;">' . esc_html( $time_updated ) . '</td>';
            $html .= '<td style="padding:12px 10px;">';
            $html .= '<a href="https://95deli.fship.vn/dashboard/details?order_id='.$order_id.'" style="color:#0073aa; text-decoration:none; font-weight:500;" target="_blank"><i class="fa-solid fa-circle-info lin"></i></a>';           
         
            $html .= '</td>';
            $html .= '<td style="padding:12px 10px; text-align:center;">';
            $html .= '<span style="display:inline-block; padding:5px 12px; border-radius:20px; font-size:12px; font-weight:600; background-color:' . $colors['bg'] . '; color:' . $colors['text'] . ';width:-webkit-fill-available;white-space: nowrap;">';
            $html .= wc_get_order_status_name( $current_status );
            $html .= '</span>';
            $html .= '</td>';
			$html .= '<tr style="border-bottom: 4px solid #eee;"><td colspan="4"><div class="flex justify-between items-end">'.$created.''.$button.'<div style="text-align:right;">Cập nhật '.$time_updated.'</div></div></td</tr>';
            $html .= '</tr>';
        }
    } else {
        $html .= '<tr><td colspan="4" style="padding: 30px; text-align:center; color:#888;">Không có đơn hàng nào ở trạng thái này.</td></tr>';
    }
    $html .= '</table>';
    $html .= '</div>';

    wp_send_json_success($html);
}
add_action('wp_ajax_bks_get_live_orders', 'bks_handle_live_orders_ajax');
add_action('wp_ajax_nopriv_bks_get_live_orders', 'bks_handle_live_orders_ajax');
*/
//** DOASHBOASD **//
/*// 1. Tạo Shortcode hỗ trợ bộ lọc trạng thái
function bks_order_tracker_shortcode($atts) {
    $atts = shortcode_atts(array(
        'status' => 'any', 
    ), $atts, 'cap_nhat_don_hang');

    wp_enqueue_script('bks-ajax-tracker');

    return '<div id="bks-order-list-container" data-status="' . esc_attr($atts['status']) . '">Đang tải đơn hàng...</div>';
}
add_shortcode('cap_nhat_don_hang', 'bks_order_tracker_shortcode');

// 2. Đăng ký Script AJAX cập nhật liên tục
function bks_register_tracker_scripts() {
    wp_register_script('bks-ajax-tracker', '', [], '', true);

    $js_code = "
        jQuery(document).ready(function($) {
            function fetch_orders_continuous() {
                var container = $('#bks-order-list-container');
                if (!container.length) return;

                var orderStatus = container.data('status');

                $.ajax({
                    url: '" . admin_url('admin-ajax.php') . "',
                    type: 'POST',
                    data: {
                        action: 'bks_get_live_orders',
                        status: orderStatus
                    },
                    success: function(response) {
                        if(response.success) {
                            container.html(response.data);
                        }
                    }
                });
            }

            fetch_orders_continuous();
            setInterval(fetch_orders_continuous, 10000); // Tự động cập nhật mỗi 10 giây
        });
    ";
    
    wp_add_inline_script('bks-ajax-tracker', $js_code);
}
add_action('wp_enqueue_scripts', 'bks_register_tracker_scripts');

// 3. Xử lý dữ liệu trả về và Phân biệt màu sắc theo trạng thái
function bks_handle_live_orders_ajax() {
    if ( ! class_exists( 'WooCommerce' ) ) {
        wp_send_json_error('WooCommerce chưa được kích hoạt.');
    }

    $status_requested = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : 'any';
    
    if ( $status_requested !== 'any' && strpos($status_requested, ',') !== false ) {
        $status_filter = array_map('trim', explode(',', $status_requested));
    } else {
        $status_filter = $status_requested;
    }

    $args = array(
        'limit'    =>-1,
        'orderby'  => 'date',
        'order'    => 'DESC',
        'status'   => $status_filter,
    );
    
    $query = new WC_Order_Query($args);
    $orders = $query->get_orders();

    // Định nghĩa bảng màu cho từng trạng thái đơn hàng WooCommerce
    $status_colors = array(
        'pending'    => array('bg' => '#fffae6', 'text' => '#b38600'), // Vàng nhạt - Chờ thanh toán
        'processing' => array('bg' => '#e6f9ed', 'text' => '#107c41'), // Xanh lá - Đang xử lý
        'on-hold'    => array('bg' => '#fff0e6', 'text' => '#d96a00'), // Cam - Tạm giữ
        'completed'  => array('bg' => '#e6f0fa', 'text' => '#005a9c'), // Xanh dương - Đã hoàn thành
        'cancelled'  => array('bg' => '#fbeaeA', 'text' => '#a80000'), // Đỏ - Đã hủy
        'refunded'   => array('bg' => '#f3f2f1', 'text' => '#605e5c'), // Xám - Đã hoàn tiền
        'failed'     => array('bg' => '#fde7e9', 'text' => '#a80000'), // Đỏ đậm - Thất bại
    );

    // Giao diện bảng
    $html = '<table style="width:100%; border-collapse: collapse; font-family: sans-serif; font-size: 14px; box-shadow: 0 2px 5px rgba(0,0,0,0.05);">';
    $html .= '<tr style="background:#f8f9fa; text-align:left; border-bottom: 2px solid #eaeaea;">';
    $html .= '<th style="padding:12px 10px;">Mã Đơn</th>';
    $html .= '<th style="padding:12px 10px;">Khách Hàng</th>';
    $html .= '<th style="padding:12px 10px; text-align:center;">Trạng Thái</th>';
    $html .= '<th style="padding:12px 10px; text-align:right;">Tổng Tiền</th>';
    $html .= '</tr>';

    if ( ! empty( $orders ) ) {
		foreach ( $orders as $order ) {
            $current_status = $order->get_status();
			{$statuses = array( 'cook' ); // Define order statuses
    if ($order->has_status($statuses)) {
       $button = '<a target="_blank" href="' .get_site_url( null, 'wcpdf/packing-slip/'.$order_id.'/'.$order_key.'/pdf', 'http' ). '" class="prs">Phiếu chế biến</a>';}}
				{$statuses = array( 'shipper' ); // Define order statuses
    if ($order->has_status($statuses)) {
       $button = '';}}
            
            // Lấy màu sắc tương ứng, nếu không có trong danh sách thì dùng màu xám mặc định
            $colors = isset($status_colors[$current_status]) ? $status_colors[$current_status] : array('bg' => '#f3f2f1', 'text' => '#605e5c');

            $html .= '<tr style="border-bottom: 1px solid #eee; transition: background 0.3s;">';
            $html .= '<td style="padding:12px 10px; font-weight:bold; color:#333;">#' . $order->get_id() . '</td>';
            $html .= '<td style="padding:12px 10px; color:#555;">' . esc_html( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ) . ''.$button.'</td>';
            
            // Cột Trạng thái với Badge màu sắc động
            $html .= '<td style="padding:12px 10px; text-align:center;">';
            $html .= '<span style="display:inline-block; padding:5px 12px; border-radius:20px; font-size:12px; font-weight:600; background-color:' . $colors['bg'] . '; color:' . $colors['text'] . ';">';
            $html .= wc_get_order_status_name( $current_status );
            $html .= '</span>';
            $html .= '</td>';
            
            $html .= '<td style="padding:12px 10px; text-align:right; font-weight:bold; color:#111;">' . $order->get_formatted_order_total() . '</td>';
            $html .= '</tr>';
        }
    } else {
        $html .= '<tr><td colspan="4" style="padding: 30px; text-align:center; color:#888;">Không tìm thấy đơn hàng nào với trạng thái này.</td></tr>';
    }
    $html .= '</table>';

    wp_send_json_success($html);
}
add_action('wp_ajax_bks_get_live_orders', 'bks_handle_live_orders_ajax');
add_action('wp_ajax_nopriv_bks_get_live_orders', 'bks_handle_live_orders_ajax');
Tags :
Tags: