skip to Main Content

My intention is to hide orders that contains a specific product id (5).
This in the WooCommmerce "My account" orders table

What I have done are the steps as described in the /myaccount/orders.php
template file. Namely copied the file to my theme folder.
(mytheme/woocommerce/myaccount/orders.php.)

There I replaced

<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>

With

<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>

Although this has no error messages, it does not produce the desired result.

Can someone give some advice? oh, and if there is a solution via hooks instead of
overwriting the template file I’d really appreciate it.

2

Answers


  1. To answer your question via hooks, you can use the woocommerce_my_account_my_orders_query filter hook.

    The code below is copied from /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,
            )
        );
    }
    

    As you can see, via the hook, you can modify the arguments used by the wc_get_orders function. Which in turn is used by the wc_get_template function. The function that calls the /myaccount/orders.php template file and pass the arguments.

    wc_get_orders allows us to exclude orderIDs. But no productIDs. That’s why we’re going to use a workaround so we can still pass the necessary orderIDs to exclude as argument.

    The function to get all orders IDs for a given product ID, processed in my answer is based on Woocommerce: Get all orders for a product answer code.


    So to answer your question, you get:

    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 );
    
    Login or Signup to reply.
  2. If you look at WC_Order->get_items this retuns WC_Order_Item not always WC_Order_Item_Product (which has get_product_id). So I would try something like this:

    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>
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search