I'm currently working on a project where I need to build a page to showcase specific details of WooCommerce orders. These details include the Order ID, order status (limited to completed orders), delivery date, expense amount, and the corresponding expense reason.
To make this happen, I've added custom meta fields called 'expense' and 'expense_reason' to my WooCommerce orders.
Here's the challenge I'm facing:
When I attempt to display all orders, everything runs smoothly without any issues. However, the problem arises when I try to filter and display only those orders that have associated expenses. Unfortunately, I'm struggling to pinpoint the source of this error.
Here is the code that I am using:
<?php
/**add_action('woocommerce_account_dashboard', 'run_on_specific_page',10);
function run_on_specific_page(){ */
if ( is_user_logged_in()) {
$current_user = wp_get_current_user();
$user_id = $current_user->ID;
$user_roles = $current_user->roles;
if(in_array('driver', $user_roles)){
//echo'<style>nav.woocommerce-MyAccount-navigation{ display:none;}.woocommerce-MyAccount-content{width: 100% !important;}';
//echo'.woocommerce-MyAccount-content p:nth-child(3){display:none}</style>';
$args = array(
'numberposts' => -1,
'relation' => 'AND',
array(
'meta_key' => 'Driver Expense',
'compare' => 'EXISTS',
),
array(
'key' => 'lddfw_driverid',
'value' => $user_id,
'compare' => '=',
),
'status' => 'completed',
);
$orders = wc_get_orders($args); ?>
<style>.text-white{color:#fff;}</style>
<table style="width:100%">
<tr style="background-color:#111;">
<td colspan="1"><h4 style="color:#fff;">Driver Detail</h4></td>
<td colspan="3"><h4 style="color:#fff;"><?php echo $current_user->user_email; ?></h4></td>
<td colspan="3"><h4 style="color:#fff;"><?php echo $user_id; ?></h4></td>
</tr>
<tr style="background-color:#111;">
<td class="text-white">Order No.</td>
<td class="text-white">Order Status</td>
<td class="text-white">Order Payment Method</td>
<td class="text-white">Delivery Date</td>
<td class="text-white">Expense Amount</td>
<td class="text-white">Expense Reason</td>
<td class="text-white">Expense Change Reason</td>
</tr>
<?php
foreach ($orders as $order) {
$order_id = $order->get_id();
$order_status = $order->get_status();
$order_total = $order->get_total();
$payment_method = $order->get_payment_method();
$delivery_date = $order->get_meta('Delivery Date');
$driver_expense = $order->get_meta('Driver Expense');
$driver_expense_reason = $order->get_meta('Driver Expense Reason');
$expense_change_reason = $order->get_meta('Expense Change Reason');
/**$meta_datas = get_post_meta($order_id);
$cod_meta = array();
foreach ($meta_datas as $meta_data) {
//print_r($meta_data);
if ($meta_data[0] === 'cod') {
$cod_meta[] = $meta_data[0];
$cod_value= $cod_meta[0];
//echo $cod_value;
}
}*/
?>
<tr>
<td><?php echo $order_id; ?></td>
<td><?php echo $order_status; ?></td>
<td><?php echo $payment_method; ?></td>
<td><?php echo $delivery_date; ?></td>
<td><?php echo $driver_expense; ?></td>
<td><?php echo $driver_expense_reason; ?></td>
<td><?php echo $expense_change_reason; ?></td>
</tr>
<?php
} ?>
</table> <?php
}
}
?>
If anyone can shed light on what might be causing this error or offer a more efficient approach to achieve this task, I would greatly appreciate your assistance.
Your WC_Order_query
need something additional to handle multiple custom fields (handling a meta query). Below you will find a function that extend the wc_get_orders()
to work with your custom fields:
// Extend WooCommerce WC_Order_Query parameters (custom fields)
add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_order_custom_query_vars', 10, 2 );
function handle_order_custom_query_vars( $query, $query_vars ) {
if ( isset($query_vars['expense']) && ! empty($query_vars['expense']) && $query_vars['expense'] === 'EXISTS' ) {
$query['meta_query'][] = array(
'key' => 'Driver Expense',
'compare' => 'EXISTS',
);
}
if ( isset($query_vars['driver-id']) && ! empty($query_vars['driver-id']) ) {
$query['meta_query'][] = array(
'key' => 'lddfw_driverid',
'value' => esc_attr($query_vars['driver-id']),
);
}
return $query;
}
Code goes in functions.php file of your child theme (or in a plugin).
Related: WC_Order_Query where meta data does not exist or is not equal to
Now your working orders query will be as follows:
$orders = wc_get_orders( array(
'limit' => -1,
'status' => 'completed',
'expense' => 'EXISTS',
'driver-id' => $current_user->ID,
) );
Below I have revisited and optimized your code:
add_action('woocommerce_account_dashboard', 'run_on_specific_page',10);
function run_on_specific_page(){
global $current_user;
if ( $current_user > 0 && in_array('driver', $current_user->roles) ){ ?>
<style>
table.drivers{width:100%;}
tr.bg-dark, tr.bg-dark td {background-color:#111 !important;}
table.drivers h4, table.drivers .white{color:white;}
</style>
<table class="drivers">
<tr class="bg-dark">
<td colspan="1"><h4><?php _e('Driver Detail'); ?></h4></td>
<td colspan="3"><h4><?php echo $current_user->user_email; ?></h4></td>
<td colspan="3"><h4><?php echo $current_user->ID; ?></h4></td>
</tr>
<tr class="bg-dark">
<td class="white"><?php _e('Order No'); ?></td>
<td class="white"><?php _e('Order Status'); ?></td>
<td class="white"><?php _e('Order Payment Method'); ?></td>
<td class="white"><?php _e('Delivery Date'); ?></td>
<td class="white"><?php _e('Expense Amount'); ?></td>
<td class="white"><?php _e('Expense Reason'); ?></td>
<td class="white"><?php _e('Expense Change Reason'); ?></td>
</tr>
<?php
$orders = wc_get_orders( array(
'limit' => -1,
'status' => 'completed',
'expense' => 'EXISTS',
'driver-id' => $current_user->ID,
) );
foreach ($orders as $order) { ?>
<tr>
<td><?php echo $order->get_order_number(); ?></td>
<td><?php echo $order->get_status(); ?></td>
<td><?php echo $order->get_payment_method(); ?></td>
<td><?php echo $order->get_meta('Delivery Date'); ?></td>
<td><?php echo $order->get_meta('Driver Expense'); ?></td>
<td><?php echo $order->get_meta('Driver Expense Reason'); ?></td>
<td><?php echo $order->get_meta('Expense Change Reason'); ?></td>
</tr><?php
} ?>
</table><?php
}
}
Code goes in functions.php file of your child theme (or in a plugin). Tested and works.
Related: