Cara Menambahkan Filter Produk di Halaman Order WooCommerce

  • Install & aktifkan plugin Code Snippets
  • Masuk Snippets → Add New.
  • Isi Title bebas, misalnya: Filter Orders by Product (ID/SKU).
  • Paste kode snippet ini:

/**
 * WooCommerce Orders: Filter by Product (ID atau SKU)
 * - Menambahkan field filter di layar Orders
 * - Bekerja di mode lama (posts) DAN HPOS
 */
add_action('restrict_manage_posts', function($post_type){
    if ($post_type !== 'shop_order') return;

    $current_id  = isset($_GET['_product_id']) ? absint($_GET['_product_id']) : '';
    $current_sku = isset($_GET['_product_sku']) ? sanitize_text_field($_GET['_product_sku']) : '';

    echo '<div style="margin-left:6px;display:inline-block;">';
    echo '<label for="_product_id" style="margin-right:4px;">Product ID:</label>';
    echo '<input type="number" min="1" name="_product_id" id="_product_id" value="'.esc_attr($current_id).'" />';
    echo '</div>';

    echo '<div style="margin-left:6px;display:inline-block;">';
    echo '<label for="_product_sku" style="margin-right:4px;">SKU:</label>';
    echo '<input type="text" name="_product_sku" id="_product_sku" value="'.esc_attr($current_sku).'" />';
    echo '</div>';
}, 20);

/**
 * Utility: Ambil array order_id yang mengandung product_id (atau SKU).
 */
function yb_get_order_ids_by_product( $product_id = 0, $sku = '' ) {
    global $wpdb;

    // Resolve SKU -> product_id jika perlu
    if ( $product_id <= 0 && $sku !== '' ) {
        $product_id = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT p.ID
                 FROM {$wpdb->posts} p
                 INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_sku'
                 WHERE p.post_type IN ('product','product_variation')
                   AND pm.meta_value = %s
                 LIMIT 1",
                $sku
            )
        );
    }

    if ( $product_id <= 0 ) {
        return array(); // tidak ada filter produk
    }

    // Ambil order IDs yang punya line_item dengan _product_id = $product_id
    $order_ids = $wpdb->get_col(
        $wpdb->prepare(
            "SELECT DISTINCT oi.order_id
             FROM {$wpdb->prefix}woocommerce_order_items oi
             INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim
                 ON oim.order_item_id = oi.order_item_id
             WHERE oi.order_item_type = 'line_item'
               AND oim.meta_key = '_product_id'
               AND oim.meta_value = %d",
            $product_id
        )
    );

    // Jika produk yang dimaksud adalah parent variable, sertakan variasi (opsional)
    // Ambil semua variation child dan gabungkan hasilnya
    $variation_ids = $wpdb->get_col(
        $wpdb->prepare(
            "SELECT p.ID FROM {$wpdb->posts} p
             WHERE p.post_type = 'product_variation' AND p.post_parent = %d",
            $product_id
        )
    );

    if ( ! empty( $variation_ids ) ) {
        $in_variations = implode( ',', array_map( 'absint', $variation_ids ) );
        $var_order_ids = $wpdb->get_col(
            "SELECT DISTINCT oi.order_id
             FROM {$wpdb->prefix}woocommerce_order_items oi
             INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim
                 ON oim.order_item_id = oi.order_item_id
             WHERE oi.order_item_type = 'line_item'
               AND oim.meta_key = '_product_id'
               AND oim.meta_value IN ($in_variations)"
        );
        $order_ids = array_unique( array_merge( $order_ids, $var_order_ids ) );
    }

    return array_map( 'absint', $order_ids );
}

/**
 * MODE LAMA (orders sebagai post): filter query list table via pre_get_posts.
 */
add_action('pre_get_posts', function( $q ){
    if ( ! is_admin() || ! $q->is_main_query() ) return;
    if ( $q->get('post_type') !== 'shop_order' ) return;

    $product_id  = isset($_GET['_product_id']) ? absint($_GET['_product_id']) : 0;
    $product_sku = isset($_GET['_product_sku']) ? sanitize_text_field($_GET['_product_sku']) : '';

    if ( ! $product_id && $product_sku === '' ) return;

    $order_ids = yb_get_order_ids_by_product( $product_id, $product_sku );
    // Jika tidak ada, paksa kosong agar list table tidak menampilkan order lain
    $order_ids = empty($order_ids) ? array(0) : $order_ids;

    // Batasi hasil hanya ke order_id yang cocok
    $q->set( 'post__in', $order_ids );
}, 20);

/**
 * HPOS (High-Performance Order Storage): filter args WC_Order_Query untuk list table.
 * WooCommerce akan memanggil hook ini ketika menyiapkan query di layar Orders (HPOS aktif).
 */
add_filter('woocommerce_shop_order_list_table_prepare_items_query_args', function( $args ){
    $screen = function_exists('get_current_screen') ? get_current_screen() : null;
    if ( ! $screen || $screen->id !== 'woocommerce_page_wc-orders' ) {
        return $args;
    }

    $product_id  = isset($_GET['_product_id']) ? absint($_GET['_product_id']) : 0;
    $product_sku = isset($_GET['_product_sku']) ? sanitize_text_field($_GET['_product_sku']) : '';

    if ( ! $product_id && $product_sku === '' ) return $args;

    $order_ids = yb_get_order_ids_by_product( $product_id, $product_sku );
    $order_ids = empty($order_ids) ? array(0) : array_map('absint', $order_ids);

    // WC_Order_Query mendukung 'include' untuk membatasi ID
    $args['include'] = $order_ids;
    return $args;
}, 20);

  • Di bagian Scope/Run snippet, pilih Only run in administration area (agar hanya aktif di wp-admin).
  • Klik Save Changes and Activate.
  • Buka WooCommerce → Orders.
  • Di bar filter atas, akan muncul field Product ID dan SKU.
  • Masukkan Product ID (atau SKU) produk yang ingin difilter → klik Filter.
  • (Opsional) Untuk produk variabel, cukup isi ID parent; variasi akan otomatis ikut terjaring.
  • Jika ingin menonaktifkan: Snippets → toggle off snippet tersebut.
  • Troubleshooting cepat: jika field belum muncul, clear cache, pastikan snippet active, dan WooCommerce aktif (snippet ini kompatibel HPOS maupun mode lama).