Woocommerce change role by total of user orders - php

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' );

Related

Update Custom product meta when order completed

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.

Change woocommerce status with callable function

This function is made to be called with ajax through a button click to change the woocommerce order status. However I was wondering if this function could just be called as a function itself for example in an if statement. I tried putting the code inside an if statement but failed. The code needs to work after an eForm submission which changes the status of that order_id
function update_order_installer_status() { check_ajax_referer( 'nonce_update_order_installer_status', 'nonce' ); // we are safe now
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-pending' // Only orders with status "pending"
) );
foreach ( $customer_orders as $customer_order ) {
// Updated compatibility with WooCommerce 3+
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
$order = wc_get_order( $customer_order );
// Iterating through each current customer products bought in the order
foreach ($order->get_items() as $item) {
// WC 3+ compatibility
if ( version_compare( WC_VERSION, '3.0', '<' ) )
$product_id = $item['product_id'];
else
$product_id = $item->get_product_id();
// Your condition related to your 2 specific products Ids
if ( in_array( $product_id ) )
$order = new WC_Order($_POST['id']); $order->update_status('wc-completed');
$order->status = wc_get_order_status_name($order->get_status()); wp_send_json($order); } } }
add_action( 'wp_ajax_update_order_installer_status', 'update_order_installer_status' );
add_action( 'wp_ajax_nopriv_update_order_installer_status', 'update_order_installer_status' );
I tried the following:
if($this->form_id="109"){ $customer_orders = get_posts( array( 'numberposts' => -1, 'meta_key' => '_customer_user', 'meta_value' => get_current_user_id(), 'post_type' => 'shop_order', 'post_status' => 'wc-pending' ) ); foreach ( $customer_orders as $customer_order ) { $order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id; $order = wc_get_order( $customer_order );
// Iterating through each current customer products bought in the order
foreach ($order->get_items() as $item) {
// WC 3+ compatibility
if ( version_compare( WC_VERSION, '3.0', '<' ) )
$product_id = $item['product_id'];
else
$product_id = $item->get_product_id();
// Your condition related to your 2 specific products Ids
if ( in_array( $product_id ) )
$order = new WC_Order($_POST['id']); $order->update_status('wc-completed'); }

Add order note to new customer orders in WooCommerce

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

How to show order details (my-account) for a specific product (id) on a separate page in Woocommerce?

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

Change the user role on nth number of orders after successful order placement

I previously implemented a solution to change the user role on registration, but seem to be missing something this time around.
Does anyone out there have a solution for this that still works or be able to point me in the right direction as to what I'm missing or doing wrong?
Does is what I have tried so far.
add_action('woocommerce_thankyou', 'change_user_role_on_order_success');
function change_user_role_on_order_success($order_id ) {
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed' // Only orders with status "completed"
) );
// Count number of orders
$count = count( $customer_orders );
// return "true" when customer has already one order
if ( $count >= 1 ) {
$user = new WP_User( $order->get_user_id() );
// our new role name
$role = 'editor';
//set the new role to our customer
$user->set_role($role);
}
}
Maybe you could try to use the hook woocommerce_order_status_completed instead. It should fire as soon as your customer really completed the order and removes the need for you to check for the status.
function change_user_role_on_order_status_completed( $order_id ) {
$order = new WC_Order( $order_id );
$user_id = $order->user_id;
$total_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_order',
) );
if ( $total_orders > 1 ) {
$user = new WP_User( $order->user_id );
// Set role editor
$user->set_role( 'editor' );
}
}
add_action( 'woocommerce_order_status_completed', 'change_user_role_on_order_status_completed', 10, 1 );

Categories