在 WooCommerce "My account" 订单 table 中隐藏包含特定产品的订单

Hide orders that contains a specific product in WooCommmerce "My account" orders table

我的目的是隐藏包含特定产品 ID (5) 的订单。 这在WooCommmerce“我的帐户”订单table

我所做的是/myaccount/orders.php中描述的步骤 模板文件。即将该文件复制到我的主题文件夹中。 (mytheme/woocommerce/myaccount/orders.php.)

那里我换了

<tbody>
     <?php
     foreach ( $customer_orders->orders as $customer_order ) {
         $order      = wc_get_order( $customer_order ); // phpcs:ignore
WordPress.WP.GlobalVariablesOverride.Prohibited
         $item_count = $order->get_item_count() -
$order->get_item_count_refunded();
         ?>
         <tr class="woocommerce-orders-table__row
woocommerce-orders-table__row--status-<?php echo esc_attr(
$order->get_status() ); ?> order">
         ...
         </tr>
         <?php
     }
     ?>
</tbody>

<tbody>
     <?php
     foreach ( $customer_orders->orders as $customer_order ) {
         $order      = wc_get_order( $customer_order ); // phpcs:ignore
WordPress.WP.GlobalVariablesOverride.Prohibited
         $item_count = $order->get_item_count() -
$order->get_item_count_refunded();

         foreach( $order->get_items() as $item ) {
             $product_id = $item->get_product_id();

             if ( $product_id != 5 ) {
                 ?>
                 <tr class="woocommerce-orders-table__row
woocommerce-orders-table__row--status-<?php echo esc_attr(
$order->get_status() ); ?> order">
                 ...
                 </tr>
                 <?php
             }
         }
     }
     ?>
</tbody>

虽然这没有错误消息,但它不会产生预期的结果。

有人可以给点建议吗?哦,如果有通过钩子而不是 覆盖模板文件我真的很感激。

要通过挂钩回答您的问题,您可以使用 woocommerce_my_account_my_orders_query 过滤器挂钩。

下面的代码是从/includes/wc-template-functions.php line 3159 - 3185 @version 2.5.0

复制的
/**
 * My Account > Orders template.
 *
 * @param int $current_page Current page number.
 */
function woocommerce_account_orders( $current_page ) {
    $current_page    = empty( $current_page ) ? 1 : absint( $current_page );
    $customer_orders = wc_get_orders(
        apply_filters(
            'woocommerce_my_account_my_orders_query',
            array(
                'customer' => get_current_user_id(),
                'page'     => $current_page,
                'paginate' => true,
            )
        )
    );

    wc_get_template(
        'myaccount/orders.php',
        array(
            'current_page'    => absint( $current_page ),
            'customer_orders' => $customer_orders,
            'has_orders'      => 0 < $customer_orders->total,
        )
    );
}

如您所见,通过钩子,您可以修改 wc_get_orders 函数使用的参数。 wc_get_template 函数又使用它。调用 /myaccount/orders.php 模板文件并传递参数的函数。

wc_get_orders 允许我们排除 orderID。但没有产品 ID。这就是我们要使用解决方法的原因,这样我们仍然可以传递必要的 orderID 作为参数排除。

获取给定产品 ID 的所有订单 ID 的功能,在我的回答中处理是基于 回答代码。


所以要回答你的问题,你会得到:

function get_orders_ids_by_product_id( $product_id ) {
    global $wpdb;
    
    $statuses = array_keys( wc_get_order_statuses() );
    $statuses = implode( "','", $statuses );

    $results = $wpdb->get_col("
        SELECT order_items.order_id
        FROM {$wpdb->prefix}woocommerce_order_items as order_items
        LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta as order_item_meta ON order_items.order_item_id = order_item_meta.order_item_id
        LEFT JOIN {$wpdb->posts} AS posts ON order_items.order_id = posts.ID
        WHERE posts.post_type = 'shop_order'
        AND posts.post_status IN ('$statuses')
        AND order_items.order_item_type = 'line_item'
        AND order_item_meta.meta_key = '_product_id'
        AND order_item_meta.meta_value = '$product_id'
    ");

    return $results;
}

function filter_woocommerce_my_account_my_orders_query( $args ) {   
    // Get all orders IDs for a given product ID
    $orders_ids = get_orders_ids_by_product_id( 5 );
    
    // Existing args
    $customer = $args['customer'];
    $current_page = $args['page'];
    $paginate = $args['paginate'];

    // Get orders that aren't the current order.
    $args = array(
        'customer' => $customer,
        'page'     => $current_page,
        'paginate' => $paginate,
        'exclude'  => $orders_ids,
    );
    
    return $args;
}
add_filter( 'woocommerce_my_account_my_orders_query', 'filter_woocommerce_my_account_my_orders_query', 10, 1 );

如果您查看 WC_Order->get_items this retuns WC_Order_Item not always WC_Order_Item_Product(其中有 get_product_id)。所以我会尝试这样的事情:

foreach ($customer_orders as $customer_order) {
    $order      = wc_get_order($customer_order); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
    $item_count = $order->get_item_count();

    // Always show orders by default
    $show_order = true;

    // Check if order has specific product ids
    foreach ($order->get_items() as $item) {
        if (is_a($item, 'WC_Order_Item_Product')) {
            $product_id  = $item->get_product_id();
            $product_ids = array(5); // Enter product ids here

            if (in_array($product_id, $product_ids)) {
                // Hide order
                $show_order = false;
            }
        }
    }

    if ($show_order) {
        // <tr>
        // ...
        // </tr>
    }
}