Hook woocommerce price in backend order edition - php

I need to change item product prices in Woocommerce Backend Order. I tried tu use the following hook, but I have a problem trying to obtain the order id. Any suggestion? Thanks in advance!
function my_custom_prices ($price, $product)
{
if ( !is_admin() || ( is_admin() && is_post_type_archive() ) ) return $price;
global $post, $woocommerce;
$order = new WC_Order( $post_id );
$user_id = $order->user_id;
$user = get_user_by('id', $user_id);
if ( in_array( 'my_role', (array) $user->roles ) ) {
return $price * 2;
}
else {
return $price;
}
}
add_filter('woocommerce_get_price', 'my_custom_prices ', 10, 2);
Complete problem:
The complete problem is as follows. I am using a plugin that adds a field to the product called wholesale price. If the customer has the wholesale customer role, the order uses those prices. The plugin works fine, but it does not take the price in the backend. I talked to the author and it's something they do not plan to change yet. My client needs to modify the orders. But when it enters the backend, it takes the common price, not the wholesaler. I need to do something in the backend that allows me to detect if the order is from a client with a wholesale customer role. If yes, take the correct price when adding products. There is more information on the discussion with the author here. https://wordpress.org/support/topic/wholesale-prices-in-backend-editing-orders/ Thank you very much for the help you can give me.
Options:
woocommerce_get_price: does not work because I cannot obtain the customer id
woocommerce_ajax_add_order_item_meta: nice option, but I could not find a sample
Button: nice option, but I do not know how can I change the price. I tryed the follow:
add_action( 'woocommerce_order_item_add_action_buttons', 'action_aplicar_mayoristas', 10, 1);
function action_aplicar_mayoristas( $order )
{
echo '<button type="button" onclick="document.post.submit();" class="button button-primary generate-items">Aplicar precios mayoristas</button>';
echo '<input type="hidden" value="1" name="aplicar_mayoristas" />';
};
add_action('save_post', 'aplicar_mayoristas', 10, 3);
function aplicar_mayoristas($post_id, $post, $update){
$slug = 'shop_order';
if(is_admin()){
if ( $slug != $post->post_type ) {
return;
}
if(isset($_POST['aplicar_mayoristas']) && $_POST['aplicar_mayoristas']){
$order = wc_get_order( $post_id);
//$order_id = $order->get_user_id();
// Iterating through each "line" items in the order
foreach ($order->get_items() as $item_id => $item_data) {
//$item_data->set_subtotal("798");
$item_data->set_price("798");
//->set_price($custom_price);
}
}
}
}

Updated
The hook that you are using is not for orders, but only for products, and is made to change the displayed prices only. So you will not get the order ID with it.
You could change the price display in many hooks, but if you want to change order item prices for real (not only the displayed formatted prices), you should trigger this prices changes when order is updated for example.
In this case you can use a custom function hooked in save_post action hook:
add_action( 'save_post', 'change_order_item_prices', 11, 1 );
function change_order_item_prices( $post_id ) {
// If this is an autosave (has not been submitted).
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
// Check the user's permissions.
if ( 'shop_order' == $_POST[ 'post_type' ] ){
if ( ! current_user_can( 'edit_shop_order', $post_id ) )
return $post_id;
} else {
if ( ! current_user_can( 'edit_post', $post_id ) )
return $post_id;
}
## ------------------- Changing prices Start code ------------------- ##
## ===> HERE define the targeted user role
$user_role = 'my_role';
## ===> HERE define the rate multiplier (for price calculations)
$multiplier = 2;
// If this Order items prices have already been updated, we exit
$items_prices_updated = get_post_meta( $post_id, 'line_item_updated', true );
if( ! empty( $items_prices_updated ) ) return $post_id; // Exit
$order = new WC_Order( $post_id ); // Get the order object
$user_id = $order->get_user_id(); // Get the user ID
$user_data = get_userdata( $user_id ); // Get the user data
// Check the user role
if ( ! in_array( $user_role, $user_data->roles ) ) return;
// Loop through order items
foreach( $order->get_items() as $item_id => $item ){
$item_data = $item->get_data(); // The item data
$taxes = array();
foreach( $item_data['taxes'] as $key_tax => $values ){
if( ! empty( $values ) ){
foreach( $values as $key => $tax_price ){
$taxes[$key_tax][$key] = floatval($tax_price) * $multiplier;
}
}
}
$new_line_subtotal = floatval( $item_data['subtotal'] ) * $multiplier;
$new_line_subt_tax = floatval( $item_data['subtotal_tax'] ) * $multiplier;
$new_line_total = floatval( $item_data['total'] ) * $multiplier;
$new_line_total_tax = floatval( $item_data['total_tax'] ) * $multiplier;
// Update Order item prices
$item->set_subtotal($new_line_subtotal);
$item->set_subtotal_tax($new_line_subt_tax);
$item->set_total($new_line_total);
$item->set_total_tax($new_line_total_tax);
$item->set_taxes($taxes);
// Save the updated data
$item->save();
}
// Udpate order totals and cache
$order->calculate_totals();
// We mark the order as updated (to avoid repetition)
update_post_meta( $post_id, 'line_item_updated', true );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and and finally works.
I have added a security to avoid the order items to be updated twice.
The method $order->calculate_totals(); slow down the process a little bit… It's normal as it will calculate totals, update data and refresh caches.

Your code needs to be debugged.
$post_id - there is not such variable or parameter inside your function. So, use $post->ID instead.
do
var_dump( (array) $user->roles);
before the
if (in_array( 'my_role', (array) $user->roles ) )
line. And make sure that my_role exists in that array.
Temporary comment this line for debugging purpose:
// if (is_admin() && is_post_type_archive())
Then you will see the reason and able to be fix it.

Related

Automatic order currency change and recalculate [duplicate]

In WooCommerce, when creating and saving a manual order via Admin, I am trying to replace the order currency value with a custom meta data value (which meta key is _wcj_order_currency)
Here are 2 screenshots of the related meta data (key/value pairs):
The order currency:
The custom currency (from Booster plugin):
So I would like to replace the order currency EUR to the custom currency USD from _order_currency meta key on save.
References I used:
How can I populate meta fields of a Woocommerce manual order
WooCommerce admin order edit save post
My code attempt:
// Saving (Updating) or doing an action when submitting
add_action( 'save_post', 'update_order_custom_field_value' );
function update_order_custom_field_value( $post_id ){
// Only for shop order
// if ( 'shop_order' != $_POST[ 'post_type' ] )
if ( 'shop_order')
return $post_id;
// Checking that is not an autosave
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
// Check the user’s permissions (for 'shop_manager' and 'administrator' user roles)
if ( ! current_user_can( 'edit_shop_order', $post_id ) )
return $post_id;
//Up to above is fine for Admin order
// Updating custom field data
if( isset( $_POST['_wcj_order_currency'] ) ) {
$order = wc_get_order( $post_id );
// Replacing and updating the value
update_post_meta( $post_id, '_order_currency', $_POST['_wcj_order_currency'] );
}}
// Testing output in order edit pages (below billing address):
//This displays the existing values well
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_order_custom_field_value' );
function display_order_custom_field_value( $order ){
echo '<p><strong>'.__('Order Currency').':</strong> <br/>' . get_post_meta( $order->get_id(), '_order_currency', true ) . '</p>';
echo '<p><strong>'.__('Booster Order Currency').':</strong> <br/>' . get_post_meta( $order->get_id(), '_wcj_order_currency', true ) . '</p>';
}
Testing output in order edit pages (below billing address). The code works well.
But I am unable to make it work and update the order currency on order creation.
Any help on this is welcome.
To make your script work on new order creation only, try the following revisited code (commented):
// Save order data
add_action( 'save_post_shop_order', 'update_order_currency_on_creation', 1000 );
function update_order_currency_on_creation( $order_id ){
// Ensure that this is a manual new order
if( $created = get_post_meta( $order_id, '_created_via', true ) ) {
return $order_id;
}
// Checking that is not an autosave (not sure that this is really needed on Woocommerce orders)
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $order_id;
}
// Check the user’s permissions (for 'shop_manager' and 'administrator' user roles)
if ( ! current_user_can( 'edit_shop_order', $order_id ) ) {
return $order_id;
}
## ---- Updating order currency ---- ##
// Get the WC_Order object
$order = wc_get_order($order_id);
// HERE below the Booster meta key for Order currency
$meta_key = '_wcj_order_currency';
// If Booster currency is already in database (in case of, to be sure)
if ( $value = $order->get_meta($meta_key) ) {
$order->set_currency( esc_attr($value) );
$order->save(); // Save order data
}
// If not, we get the posted Booster currency value (else)
elseif ( isset($_POST[$meta_key]) && ( $value = esc_attr($_POST[$meta_key]) ) ) {
$order->set_currency( esc_attr($_POST[$meta_key]) );
$order->save(); // Save order data
}
}
// Testing output in order edit pages (below billing address): This displays the existing values as well.
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_specific_order_details' );
function display_specific_order_details( $order ){
echo '<div><p><strong>'.__('Order Currency').':</strong> ' . $order->get_currency() . '</p>
<p><strong>'.__('Booster Order Currency').':</strong> ' . $order->get_meta( '_wcj_order_currency' ) . '</p></div>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Replace order currency when creating a manual order in Woocommerce admin

In WooCommerce, when creating and saving a manual order via Admin, I am trying to replace the order currency value with a custom meta data value (which meta key is _wcj_order_currency)
Here are 2 screenshots of the related meta data (key/value pairs):
The order currency:
The custom currency (from Booster plugin):
So I would like to replace the order currency EUR to the custom currency USD from _order_currency meta key on save.
References I used:
How can I populate meta fields of a Woocommerce manual order
WooCommerce admin order edit save post
My code attempt:
// Saving (Updating) or doing an action when submitting
add_action( 'save_post', 'update_order_custom_field_value' );
function update_order_custom_field_value( $post_id ){
// Only for shop order
// if ( 'shop_order' != $_POST[ 'post_type' ] )
if ( 'shop_order')
return $post_id;
// Checking that is not an autosave
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
// Check the user’s permissions (for 'shop_manager' and 'administrator' user roles)
if ( ! current_user_can( 'edit_shop_order', $post_id ) )
return $post_id;
//Up to above is fine for Admin order
// Updating custom field data
if( isset( $_POST['_wcj_order_currency'] ) ) {
$order = wc_get_order( $post_id );
// Replacing and updating the value
update_post_meta( $post_id, '_order_currency', $_POST['_wcj_order_currency'] );
}}
// Testing output in order edit pages (below billing address):
//This displays the existing values well
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_order_custom_field_value' );
function display_order_custom_field_value( $order ){
echo '<p><strong>'.__('Order Currency').':</strong> <br/>' . get_post_meta( $order->get_id(), '_order_currency', true ) . '</p>';
echo '<p><strong>'.__('Booster Order Currency').':</strong> <br/>' . get_post_meta( $order->get_id(), '_wcj_order_currency', true ) . '</p>';
}
Testing output in order edit pages (below billing address). The code works well.
But I am unable to make it work and update the order currency on order creation.
Any help on this is welcome.
To make your script work on new order creation only, try the following revisited code (commented):
// Save order data
add_action( 'save_post_shop_order', 'update_order_currency_on_creation', 1000 );
function update_order_currency_on_creation( $order_id ){
// Ensure that this is a manual new order
if( $created = get_post_meta( $order_id, '_created_via', true ) ) {
return $order_id;
}
// Checking that is not an autosave (not sure that this is really needed on Woocommerce orders)
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $order_id;
}
// Check the user’s permissions (for 'shop_manager' and 'administrator' user roles)
if ( ! current_user_can( 'edit_shop_order', $order_id ) ) {
return $order_id;
}
## ---- Updating order currency ---- ##
// Get the WC_Order object
$order = wc_get_order($order_id);
// HERE below the Booster meta key for Order currency
$meta_key = '_wcj_order_currency';
// If Booster currency is already in database (in case of, to be sure)
if ( $value = $order->get_meta($meta_key) ) {
$order->set_currency( esc_attr($value) );
$order->save(); // Save order data
}
// If not, we get the posted Booster currency value (else)
elseif ( isset($_POST[$meta_key]) && ( $value = esc_attr($_POST[$meta_key]) ) ) {
$order->set_currency( esc_attr($_POST[$meta_key]) );
$order->save(); // Save order data
}
}
// Testing output in order edit pages (below billing address): This displays the existing values as well.
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_specific_order_details' );
function display_specific_order_details( $order ){
echo '<div><p><strong>'.__('Order Currency').':</strong> ' . $order->get_currency() . '</p>
<p><strong>'.__('Booster Order Currency').':</strong> ' . $order->get_meta( '_wcj_order_currency' ) . '</p></div>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Overwrite cart item title and price from Toolset CRED form data in Woocommerce

I'm trying to overwrite the price for a product in the WooCommerce cart.
The problem is that I'm using Divi which includes an ajax cart update. So when I reload the checkout page I can see my overwritten changes for 1-2 seconds (during the ajax loading) and after this the cart details get overwritten again by the default values. I've tried everythink, different hooks, delays, priority changes but nothing works.
This is my initial code:
add_filter( 'woocommerce_calculate_totals', 'custom_cart_items_prices', 1000, 1 )
function custom_cart_items_prices( $cart_object ) {
$title = $_GET['form-title'];
$money = $_GET['money'];
if ($title && $money) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Iterating through cart items
foreach ( $cart_object->get_cart() as $cart_item ) {
// Get an instance of the WC_Product object
$wc_product = $cart_item['data'];
// Get the product name (WooCommerce versions 2.5.x to 3+)
$original_name = method_exists( $wc_product, 'get_name' ) ? $wc_product->get_name() : $wc_product->post->post_title;
// SET THE NEW NAME
$new_name = $title;
// Set the new name (WooCommerce versions 2.5.x to 3+)
if( method_exists( $wc_product, 'set_name' ) )
$wc_product->set_name( $new_name );
else
$wc_product->post->post_title = $new_name;
}
// Updated cart item price
$cart_item['data']->set_price( $money );
}}
Picture during the loading (Everything looks great):
When the loading is completed:
Update - I've also tried a different approach as I am using a custom form made with CRED Toolset and Toolset Woocommerce plugins where customer create a product with a custom title and price, adding to cart a default existing product (and redirected to checkout page). I am trying to replace the cart item title and price by the submitted form data.
Here is my code:
// Change the product ID
add_filter('cred_commerce_add_product_to_cart', function( $product_id, $form_id, $post_id ) {
error_log($form_id);
if( $form_id == 55 ) {
if (!session_id()) {
session_start();
}
$_SESSION['target_post_id'] = $post_id;
if(isset($_POST['product-id'])){
$product_id = $_POST['product-id'];
$_SESSION['target_post_id'] = $post_id;
}
}
return $product_id;
}, 20, 3);
// change the price in cart
add_action('woocommerce_before_calculate_totals', function(){
session_start();
if($form_id != 55 && !isset($_SESSION['target_post_id']))return;
global $woocommerce;
$post_id = $_SESSION['target_post_id'];
$price = 0;
foreach ( $woocommerce->cart->get_cart() as $key => $cart_item ) {
$product_id = $cart_item['data']->get_id();
$adult_price = get_post_meta($product_id, 'wpcf-prezzo-1', true);
$adult_num = get_post_meta($post_id, 'wpcf-adult-number', true);
$child_price = get_post_meta($product_id, 'wpcf-prezzo-2', true);
$child_num = get_post_meta($post_id, 'wpcf-children-number', true);
$price = $adult_price * $adult_num + $child_price * $child_num;
$cart_item['data']->set_price($price);
}
}, 999);
But it doesn't work either.
How can I get the submitted form data (custom title and price) and to overwrite the cart item title and price in Woocommerce?
Try the following instead as you are using the toolset plugin with a custom form, where you will use WC_Sessions to store the product ID and change the price:
add_filter( 'cred_commerce_add_product_to_cart', 'cred_commerce_add_product_to_cart', 20, 3 );
function cred_commerce_add_product_to_cart( $product_id, $form_id, $post_id ) {
if( $form_id == 55 && $post_id > 0 ) {
WC()->session->set( 'cp_id', $post_id );
}
return $product_id;
}
add_filter( 'woocommerce_add_cart_item_data', 'filter_add_cart_item_data', 30, 4 );
function filter_add_cart_item_data( $cart_item_data, $product_id, $variation_id ){
if ( WC()->session->get('cp_id') ) {
$cp_id = WC()->session->get('cp_id');
$product = wc_get_product($cp_id);
$cart_item_data['cp_price'] = $product->get_regular_price();
$cart_item_data['cp_title'] = $product->get_title();
}
return $cart_item_data;
}
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_items_price', 30, 1 );
function custom_cart_items_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Iterating through cart items
foreach ( $cart->get_cart() as $cart_item ) {
if( isset($cat_item['cp_price']) && isset($cat_item['cp_title']) ){
$cart_item['data']->set_price( $cat_item['cp_price'] );
$cart_item['data']->set_name( $cat_item['cp_title'] );
}
}
}
Code goes in function.php file of your active child theme (or active theme). It should works.
Some related answers:
Set cart item price from a hidden input field custom price in Woocommerce 3
Custom cart item price based on user input in Woocommerce
Conditionally alter specific product price in Woocommerce
Change cart item prices in Woocommerce 3
Deactivate all of your plugins and voila!
You will suprisingly understand that its a cause of one.
Enabling them one by one back, will let you know which one is conflicting.
And.. Please consider using WordPress stack exchange for WordPress-specific questions.
1 woocommerce_add_cart_item_data
add_filter( 'woocommerce_add_cart_item_data', function($cart_item_data, $product_id, $variation_id ){
if ( empty( $_GET['form-title'] ) || empty( $_GET['money'] ) ) {
return;
}
$title = $_GET['form-title'];
$money = $_GET['money'];
$cart_item_data['form-title'] = $title ;
$cart_item_data['money'] = $money ;
return $cart_item_data;
} ,100,4);
2 woocommerce_before_calculate_totals
add_action( 'woocommerce_before_calculate_totals', 'update_custom_price', 10, 1 );
function update_custom_price( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
foreach ( $cart_object->cart_contents as $cart_item_key => $cart_item ) {
if(isset($cart_item["money"]) ){
$money = $cart_item["money"] ;
$cart_item['data']->set_price( $money);
}
if(isset($cart_item["form-title"]) ){
$title = $cart_item["form-title"] ;
}
$wc_product = $cart_item['data'];
// Get the product name (WooCommerce versions 2.5.x to 3+)
$original_name = method_exists( $wc_product, 'get_name' ) ? $wc_product->get_name() : $wc_product->post->post_title;
// SET THE NEW NAME
$new_name = $title;
// Set the new name (WooCommerce versions 2.5.x to 3+)
if( method_exists( $wc_product, 'set_name' ) )
$wc_product->set_name( $new_name );
else
$wc_product->post->post_title = $new_name;
}
}
return $cart_object ;
}
Hope this will help.

Conditional WooCommerce Order Received text on based on Product or Category?

For Woocommerce, I found this piece of code but I need to make it conditional on product id:
add_action( 'woocommerce_thankyou', 'custom_thankyou_text', 1, 0);
function custom_thankyou_text(){
echo '<p class="thankyou-custom-text">If you do not see the download button(s) below, please refresh the page. Processing can take a few minutes.</p>';
}
How can I show a specific WooCommerce thank you page text based on the products they purchased?
Also I found this conditions example that would fit (without the redirection, which I don't need):
add_action( 'template_redirect', 'wc_custom_redirect_after_purchase' );
function wc_custom_redirect_after_purchase() {
if ( ! is_wc_endpoint_url( 'order-received' ) ) return;
// Define the product IDs in this array
$product_ids = array( 37, 25, 50 ); // or an empty array if not used
// Define the product categories (can be IDs, slugs or names)
$product_categories = array( 'clothing' ); // or an empty array if not used
$redirection = false;
global $wp;
$order_id = intval( str_replace( 'checkout/order-received/', '', $wp->request ) ); // Order ID
$order = wc_get_order( $order_id ); // Get an instance of the WC_Order Object
// Iterating through order items and finding targeted products
foreach( $order->get_items() as $item ){
if( in_array( $item->get_product_id(), $product_ids ) || has_term( $product_categories, 'product_cat', $item->get_product_id() ) ) {
$redirection = true;
break;
}
}
// Make the custom redirection when a targeted product has been found in the order
if( $redirection ){
wp_redirect( home_url( '/your-page/' ) );
exit;
}
}
Is there a way to combine the two for the needed result?
This can be done easily in the example below, where you will have to define the targeted product IDs and a Product category (for testing). So this example will display a custom message:
for specific product IDs
for specific product categories
for all other cases
The code:
add_action( 'woocommerce_thankyou', 'custom_thankyou_text', 1, 1);
function custom_thankyou_text( $order_id ){
// HERE Define Your product IDs below
$product_id1 = 30;
$product_id2 = 40;
// HERE Define Your product category (ID, slug or name)
$category = array('clothing');
// Get the WC_Order object (an instance)
$order = wc_get_order( $order_id );
$product_ids = array();
$has_category = false;
// Loop through the order items
foreach( $order->get_items() as $item ){
// PRODUCT ID: Store the product ID in an array
$product_ids[] = $item->get_product_id();
// PRODUCT CATEGORY
if( has_term( $category, 'product_cat', $item->get_product_id() ) )
$has_category = true;
}
// For first product ID
if( in_array( $product_id1, $product_ids ) ){
echo '<p class="thankyou-custom-text">Custom message for Product ID .'.$product_id1.'</p>';
}
// For Second product ID
elseif( in_array( $product_id2, $product_ids ) ){
echo '<p class="thankyou-custom-text">Custom message for Product ID .'.$product_id1.'</p>';
}
// For product category
elseif( $has_category ){
echo '<p class="thankyou-custom-text">Custom message for Product Category.</p>';
}
// For all other cases
else {
echo '<p class="thankyou-custom-text">If you do not see the download button(s) below, please refresh the page. Processing can take a few minutes.</p>';
}
}
Code goes in function.php file of the active child theme (or active theme).
Tested and works

Change the user role on purchase for specific products when order status is completed

So I helped someone launch a site and they wanted a discounted product when someone purchased a specific product. I found a solution and implemented it and it worked at launch of the site and is no longer changing the role of customers when they purchase the products. I tried to get support from Woothemes and they don't support customization and want them to purchase a $129 extension to handle this.
Does anyone out there have a solution for this that still works?
Here is my code:
// Update User on purchase https://gist.github.com/troydean/9322593
function lgbk_add_member( $order_id ) {
$order = new WC_Order( $order_id );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_name = $item['name'];
$product_id = $item['product_id'];
$product_variation_id = $item['variation_id'];
}
if ( $order->user_id > 0 && $product_id == '247' || $order->user_id > 0 && $product_id == '255') {
update_user_meta( $order->user_id, 'paying_customer', 1 );
$user = new WP_User( $order->user_id );
// Remove role
$user->remove_role( 'customer' );
// Add role
$user->add_role( 'author' );
}
}
add_action( 'woocommerce_order_status_completed', 'lgbk_add_member' );
UPDATE
Normally this updated code version should work with woocommerce_order_status_completed and then you should try this code before. (This code is also compatible with next upcoming major WooCommerce update 2.7).
Here is the code:
add_action( 'woocommerce_order_status_completed', 'custom_action_on_completed_customer_email_notification' );
function custom_action_on_completed_customer_email_notification( $order_id ) {
// Set HERE your targetted products IDs:
$targetted_products = array( 247, 255 );
$order = wc_get_order( $order_id );
if ( $order->get_user_id() > 0 ) {
foreach ( $order->get_items() as $order_item ) {
// Here we detect if the a target product is part of this order items
if ( in_array( $order_item['product_id'], $targetted_products ) ){
// I think tha this is not really needed as it's set when an order has been paid…
update_user_meta( $order->get_user_id(), 'paying_customer', 1 ); // 1 => true
// Remove all roles and set 'editor' as user role (for current user)
$user = new WP_User( $order->get_user_id() );
$user->set_role( 'author' );
// Product is found, we break the loop…
break;
}
}
}
}
But as I don't know how your order is changed to 'completed' status, if you want to be sure (in all possible cases) that the customer that will buy one of your 2 specific products, will have his role changed from 'customer' to 'author' when order status is set to 'completed', I will recommend you trying to use this an email notification hook (if the first code snippet doesn't work).
For example here I use woocommerce_email_before_order_table hook, that will be executed and fired on "Completed order customer email notification" with the help of some conditions. (This code is also compatible with next upcoming major WooCommerce update 2.7).
Here is your revisited and tested code:
add_action( 'woocommerce_email_before_order_table', 'custom_action_on_completed_customer_email_notification', 10, 4 );
function custom_action_on_completed_customer_email_notification( $order, $sent_to_admin, $plain_text, $email ) {
if( 'customer_completed_order' == $email->id ){
// Set HERE your targetted products IDs:
$targetted_products = array( 247, 255 );
if ( $order->get_user_id() > 0 ) {
foreach ( $order->get_items() as $order_item ) {
// Here we detect if the a target product is part of this order items
if ( in_array( $order_item['product_id'], $targetted_products ) ){
// I think tha this is not really needed as it's set when an order has been paid…
update_user_meta( $order->get_user_id(), 'paying_customer', 1 ); // 1 => true
// Remove all roles and set 'editor' as user role (for current user)
$user = new WP_User( $order->get_user_id() );
$user->set_role( 'author' );
// Product is found, we break the loop…
break;
}
}
}
}
}
Code goes in function.php file of your active child theme (or theme). Or also in any plugin php files.

Categories