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.
CodePudding user response:
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 );
CodePudding user response:
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>
}
}