Change woocommerce status with callable function - php

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

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.

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

Only allow a customer to buy a certain product once, even if they aren't logged in

I'm trying to stop customers buying a certain product more than once, even if they aren't logged in.
I've tried a few different functions.
<?php
add_action('woocommerce_after_checkout_validation', custom_after_checkout_validation');
function custom_after_checkout_validation( $posted ) {
$address = $order->get_billing_address_1();
$email = $order->get_billing_email();
// Set HERE ine the array your specific target product IDs
$prod_arr = array( '19861', '19908' );
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_billing_email',
'meta_value' => $email,
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed' // Only orders with status "completed"
) );
foreach ( $customer_orders as $customer_order ) {
// Updated compatibility with WooCommerce 3+
//$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;----------------
$orders = wc_get_order( $customer_order );
foreach ($orders as $order2) {
$address2 = $order->get_billing_address_1();
foreach($order2->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, $prod_arr ) ) {
if ($address == $address2) {
wc_add_notice( __( "You have already purchased this product.", 'woocommerce' ), 'error' );
}
}
}
}
}
}
?>
This one is returning an internal server error. Please Help! TIA
You're passing a variable named $posted and inside the function you're using the $order class, which is not defined.
Change $posted to $order in the fourth line and it should work.
Edit: If it still doesn't work, the function may gets passed just the order-id instead of the class. In this case you could insert $order = wc_get_order( $posted ); after line four.

Woocommerce change role by total of user orders

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

Categories