I'm trying to add in a feature where an admin order note will be added for all first time customers.
The code I am trying is:
add_action('woocommerce_thankyou', 'is_returning_customer', 10, 1);
function is_returning_customer($order_id)
{
if (!$order_id) {
return;
}
if(is_user_logged_in()) {
$order_status = array('wc-on-hold,','wc-processing', 'wc-completed');
$customer_id = get_current_user_id();
$customer_orders=get_posts( array(
'meta_key' => '_customer_user',
'meta_value' => $customer_id,
'post_type' => 'shop_order',
'post_status' => $order_status,
'numberposts' => -1
)
);
}
if (count($customer_orders) => 1) {
$order = wc_get_order( $order_id );
$note = '*** New Customer ***';
$order->add_order_note($note);
$order->save();
}
}
However, the problem it's adding the new customer note on every order. Any advice?
Your code looks fine except for syntax errors here. I revised your code. try the below code.
Changed
if (count($customer_orders) => 1) {
To
if (count($customer_orders) >= 1) {
Changed
$order_status = array( 'wc-on-hold,','wc-processing', 'wc-completed' );
To
$order_status = array( 'wc-on-hold', 'wc-processing', 'wc-completed' );
for check customer is first time trying below condition.
if ( count( $customer_orders ) < 1 ) {
for check customer is a return. try the below condition.
if ( count( $customer_orders ) > 0 ) {
Complete code. for returning customer
function is_returning_customer( $order_id ) {
if ( !$order_id ) {
return;
}
if( is_user_logged_in() ) {
$order_status = array( 'wc-on-hold,','wc-processing', 'wc-completed' );
$customer_id = get_current_user_id();
$customer_orders = get_posts( array(
'meta_key' => '_customer_user',
'meta_value' => $customer_id,
'post_type' => 'shop_order',
'post_status' => $order_status,
'numberposts' => -1
)
);
}
if ( count( $customer_orders ) > 0 ) {
$order = wc_get_order( $order_id );
$note = '*** New Customer ***';
$order->add_order_note($note);
$order->save();
}
}
add_action( 'woocommerce_thankyou', 'is_returning_customer', 10, 1 );
Complete code for first time customer
function is_first_time_customer( $order_id ) {
if ( !$order_id ) {
return;
}
if( is_user_logged_in() ) {
$order_status = array( 'wc-on-hold,','wc-processing', 'wc-completed' );
$customer_id = get_current_user_id();
$customer_orders = get_posts( array(
'meta_key' => '_customer_user',
'meta_value' => $customer_id,
'post_type' => 'shop_order',
'post_status' => $order_status,
'numberposts' => -1
)
);
}
if ( count( $customer_orders ) < 1 ) {
$order = wc_get_order( $order_id );
$note = '*** New Customer ***';
$order->add_order_note($note);
$order->save();
}
}
add_action( 'woocommerce_thankyou', 'is_first_time_customer', 10, 1 );
Actually it is not necessary to go through the orders, as there is already a function for this in WooCommerce, namely wc_get_customer_order_count() - Get total orders by customer.
Only the issue here is, just like with your current code, that this would only work for logged in users.
To make this also work for 'guests' you can use the following:
function action_woocommerce_thankyou( $order_id ) {
// Get $order object
$order = wc_get_order( $order_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Get user id
$user_id = $order->get_user_id();
// Set variable
$count = 0;
// Not a guest
if ( $user_id > 0 ) {
// Get the total orders by a customer.
$count = wc_get_customer_order_count( $user_id );
} else {
// Guest 'user', don't have a user id so we will determine the previous orders based on the billing email
// Get billing email
$billing_email = $order->get_billing_email();
if ( ! empty ( $billing_email ) ) {
// Call function
$count = has_guest_bought_by_email( $billing_email );
}
}
// Output
if ( $count == 1 ) {
$note = '** New Customer **';
$order->add_order_note( $note );
}
}
}
add_action( 'woocommerce_thankyou', 'action_woocommerce_thankyou', 10, 1 );
// Based on https://stackoverflow.com/a/46216073/11987538
function has_guest_bought_by_email( $email ) {
global $wpdb;
// Get all order statuses.
$order_statuses = array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) );
$results = $wpdb->get_col( "
SELECT p.ID FROM {$wpdb->prefix}posts AS p
INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
WHERE p.post_status IN ( '" . implode( "','", $order_statuses ) . "' )
AND p.post_type LIKE 'shop_order'
AND pm.meta_key = '_billing_email'
AND pm.meta_value = '$email'
" );
// Return result
return count( $results );
}
Related: How to add a first order message after the buyer name in WooCommerce admin order list
Related
I am trying to update a product meta for all products of each order that gets completed. Can you have a look at my approach below? Any help on why it is not working will be appreciated. I am new to all this php customizing.
add_action( 'woocommerce_order_status_completed', 'update_product_meta', 20, 2 );
function update_product_meta ( $order_id, $order ) {
// GET USER ORDERS (COMPLETED + PROCESSING)
$args = array(
'post_status' => array('wc-completed')
);
$done_orders = wc_get_orders( $args );
// LOOP THROUGH ORDERS AND GET PRODUCT IDS
if ( $done_orders ) {
$product_ids = array();
foreach ( $done_orders as $done_order ) {
$order = wc_get_order( $done_order->ID );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item->get_product_id();
}
}
add_action( 'woocommerce_process_product_meta', 'action_save_product_meta' );
function action_save_product_meta( $product_id ) {
update_post_meta($product_id, 'Stav', 'Vypůjčeno' );
}
}
}
Well you're pretty close, you just have to remove the nonsense at the end.
Something along the lines of:
<?php
add_action( 'woocommerce_order_status_completed', function ( $order_id, $order ) {
$args = array(
'post_status' => array('wc-completed')
);
$done_orders = wc_get_orders( $args );
if ( ! empty( $done_orders ) ) {
foreach ( $done_orders as $done_order ) {
$order = wc_get_order( $done_order->ID );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item->get_product_id();
update_post_meta( $product_id, 'Stav', 'Vypůjčeno' );
};
};
};
}, 20, 2 );
You should think of limiting it to a specific amount because right now your query will request ALL items ever completed. be careful.
I want to display the order table found in woocommerce my-account recent orders for a specific product id on a separate page. To be more precise, display all recent orders for current user if the order has a product with the product_id of X.
I am trying to use these references:
Woocommerce - How to show Order details (my-account) on a separate page
Get all Orders IDs from a product ID in Woocommerce
Woocommerce: Get all orders for a product
But I am not able to relate $product_id to $user_id = get_current_user_id(); so that all the orders of the current user for a particular product id can be displayed on a separate page.
Edit: added code. I tried this code but its not working.
function orders_from_product_id( $product_id ) {
$order_statuses = array('wc-on-hold', 'wc-processing', 'wc-completed');
$customer_user_id = get_current_user_id(); // current user ID here for example
$customer_orders = wc_get_orders( array(
'meta_key' => '_customer_user',
'meta_value' => $customer_user_id,
'post_status' => $order_statuses,
'numberposts' => -1
) );
foreach($customer_orders as $order ){
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
foreach($order->get_items() as $item_id => $item){
$product_id = method_exists( $item, 'get_product_id' ) ? $item->get_product_id() : $item['product_id'];
if ( $product_id == 326 ) {
ob_start();
wc_get_template( 'myaccount/my-orders.php', array(
'current_user' => get_user_by( 'id', $user_id),
'order_count' => $order_count
) );
return ob_get_clean();
} else {
echo '<p> You donot have any orders.</p>';
}
}
}
}
add_shortcode('woocommerce_orders', 'orders_from_product_id');
From this code you to get the Current user-product id which product purchased by the user.
// GET CURR USER
$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) return;
// GET USER ORDERS (COMPLETED + PROCESSING)
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $current_user->ID,
'post_type' => wc_get_order_types(),
'post_status' => array_keys( wc_get_is_paid_statuses() ),
) );
// LOOP THROUGH ORDERS AND GET PRODUCT IDS
if ( ! $customer_orders ) return;
$product_ids = array();
foreach ( $customer_orders as $customer_order ) {
$order = wc_get_order( $customer_order->ID );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item->get_product_id();
$product_ids[] = $product_id;
}
}
$product_ids = array_unique( $product_ids );
When I try to get my order items for an order via my functions.php I'm getting this issue here:
Uncaught Error: Call to undefined method WC_Order::get_order_items()
This is my code (I can't find the problem):
add_filter( 'wp_nav_menu_objects', 'set_navigation_user_name' );
function set_navigation_user_name( $menu_items ) {
//Get current user
$current_user = wp_get_current_user();
foreach ( $menu_items as $menu_item ) {
if ( '{user_name}' === $menu_item->title ) {
//Get first and lastname from current user
$user_firstname = $current_user->user_firstname;
$user_lastname = $current_user->user_lastname;
$menu_item->title = $user_firstname . ' ' . $user_lastname;
} elseif ( '{available_pay}' === $menu_item->title ) {
$available_pay = 0;
$order_states = array(
'wc-completed',
'wc-pending'
);
$orders = wc_get_orders( array(
'numberposts' => - 1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_status' => $order_states
) );
foreach ( $orders as $order ) {
if ( count( $order->get_order_items() ) > 0 ) {
foreach ( $order->get_order_items() as $item_id => $item ) {
//Order pay
$order_pay = wc_get_order_item_meta( $item_id, '_line_total', true );
//Add order pay to available pay
$available_pay += $order_pay;
}
}
}
$menu_item->title = 'Order pay sum: ' . wc_price( $available_pay );
}
}
return $menu_items;
}
You need to use instead the WC_Order method get_items()…
as WC_Order get_order_items() method doesn't exist for Woocommerce…
Also since Woocommerce 3 you can use WC_Order_Item_Product get_total() method instead of wc_get_order_item_meta( $item_id, '_line_total', true );
So inside your code you will change the following:
foreach ( $orders as $order ) {
if ( count( $order->get_items() ) > 0 ) {
foreach ( $order->get_items() as $item_id => $item ) {
// Add order pay to available pay
$available_pay += $item->get_total();
}
}
}
Related threads:
Get Order items and WC_Order_Item_Product in Woocommerce 3
How to get WooCommerce order details
I have a problem with php realization of automaticaly changing role of user.
So i have custom role dovclient. First time user ordering get role Customer.
I need to change user role if he has buy products total 500$.
So i have a function
function wpa_120656_convert_paying_customer( $order_id ) {
$order = new WC_Order( $order_id );
$user_id = $order->user_id;
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_order',
) );
$total = 0;
foreach ( $customer_orders as $customer_order ) {
$order = wc_get_order( $customer_order );
$total += $order->get_total();
}
return $total;
if ( $total > 500 ) {
update_user_meta( $order->user_id, 'paying_customer', 1 );
$user = new WP_User( $order->user_id );
$user->remove_role( 'customer' );
$user->add_role( 'dovclient10' );
}
}
add_action( 'woocommerce_order_status_completed', 'wpa_120656_convert_paying_customer' );
I know, that $customer_orders are counting, and i make function working by count of orders. I mean if $customer_orders > 2 for ex., so change role.
But with total of order prices i have a problem. Role changes not. I don't know why. Maybe problem is in foreach...
Please help me!
Amazing help! 0... ok. I have done it.
function wpa_120656_convert_paying_customer( $order_id ) {
$order = new WC_Order( $order_id );
$user_id = $order->user_id;
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_order',
) );
$totall = 0;
foreach ( $customer_orders as $customer_order ) {
$order = wc_get_order( $customer_order );
$totall += $order->get_total();
}
if ( $totall > 500 ) {
update_user_meta( $order->user_id, 'paying_customer', 1 );
$user = new WP_User( $order->user_id );
if( get_role('customer') ){
$user->remove_role( 'customer' );
$user->add_role( 'dovclient' );
}
}
}
add_action( 'woocommerce_order_status_completed', 'wpa_120656_convert_paying_customer' );
In my Woocommerce website, I have a maximum order capacity of 50.
I am trying to communicate to the customer in their cart of the orders left before we close the ordering.
I need to get the total number of items already processing in each order + new orders in cart subtracted from the 50 maximum.
I have try it using this code:
function display_woocommerce_order_count() {
global $woocommerce;
$args = array(
'post_type' => 'shop_order',
'post_status' => 'publish',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'shop_order_status',
'field' => 'slug',
'terms' => array('processing')
)
)
);
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$order_id = $loop->post->ID;
$order = new WC_Order($order_id);
$order_count = 0;
foreach( $order as $product ) {
$order_item = $product['qty'];
if($qty) {
$order_count += $order_item;
}
}
ob_start();
//Echo the number of items in cart.
$count = $woocommerce->cart->cart_contents_count;
//Difference max - orders processing - cart items
$total_diff = 50 - number_format($order_count) - $count;
echo $total_diff;
return ob_get_clean();
}
How can I make this works as expected?
Thanks
To get your remaining order calculation from existing customer "processing" orders items and actual cart items, you can try this custom function (with an optional $user_id argument).
This is the code:
function get_remaining_orders( $user_id = null ){
if( empty($user_id) && is_user_logged_in() )
$user_id = get_current_user_id();
if( ! empty($user_id) && ! is_admin() ){
$order_max = 50;
$processing_orders_items_count = 0;
$cart_count = 0;
$customer_orders = get_posts( array(
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_order',
'numberposts' => -1,
'post_status' => 'wc-processing' // 'processing' order status only
) );
if(!empty($customer_orders))
foreach($customer_orders as $customer_order_values){
$customer_order = wc_get_order( $customer_order_values->ID );
$processing_orders_items_count += $customer_order->get_item_count('line_item');
}
if(!WC()->cart->is_empty())
$cart_count = WC()->cart->get_cart_contents_count( );
$ouput = $order_max - ($processing_orders_items_count + $cart_count);
return $ouput;
}
}
// USAGE: for a specific user ID (here for example $user_id is 22):
get_remaining_orders( 22 );
// USAGE: returning the value in a variable for current user:
$remaining_orders = get_remaining_orders();
// USAGE: displaying the value for current user (example):
echo 'Total remaining orders are ' . get_remaining_orders();
Code goes in function.php file of your active child theme (or theme). Or also in any plugin php files.
This code is tested and functional.
Update for a "not user specific case":
function get_remaining_orders(){
if( !is_admin() ){
$order_max = 50;
$processing_orders_items_count = 0;
$cart_count = 0;
$customer_orders = get_posts( array(
'post_type' => 'shop_order',
'numberposts' => -1,
'post_status' => 'wc-processing' // 'processing' order status only
) );
if(!empty($customer_orders))
foreach($customer_orders as $customer_order_values){
$customer_order = wc_get_order( $customer_order_values->ID );
$processing_orders_items_count += $customer_order->get_item_count('line_item');
}
if(!WC()->cart->is_empty())
$cart_count = WC()->cart->get_cart_contents_count( );
$ouput = $order_max - ($processing_orders_items_count + $cart_count);
return $ouput;
}
}
// USAGE: returning the value in a variable:
$remaining_orders = get_remaining_orders();
// USAGE: displaying the value (example):
echo 'Total remaining orders are ' . get_remaining_orders();
This should work as you expect…