Skip to content
Advertisement

Hook woocommerce price in backend order edition

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


                }
    }
}

Advertisement

Answer

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.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement